From 6730f431588faab86a1fc52942a08f9112601b8e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 19 Mar 2026 15:18:48 +0000 Subject: [PATCH 1/2] Bump @actions/github from 6.0.1 to 9.0.0 Bumps [@actions/github](https://github.com/actions/toolkit/tree/HEAD/packages/github) from 6.0.1 to 9.0.0. - [Changelog](https://github.com/actions/toolkit/blob/main/packages/github/RELEASES.md) - [Commits](https://github.com/actions/toolkit/commits/HEAD/packages/github) --- updated-dependencies: - dependency-name: "@actions/github" dependency-version: 9.0.0 dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- package-lock.json | 409 ++++++++++------------------------------------ package.json | 2 +- 2 files changed, 86 insertions(+), 325 deletions(-) diff --git a/package-lock.json b/package-lock.json index 92b02fc..33a7590 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,7 +10,7 @@ "license": "MIT", "dependencies": { "@actions/core": "^2.0.2", - "@actions/github": "^6.0.1", + "@actions/github": "^9.0.0", "@octokit/rest": "^22.0.1", "handlebars": "^4.7.8", "ts-dedent": "^2.2.0", @@ -69,16 +69,6 @@ "@actions/http-client": "^3.0.1" } }, - "node_modules/@actions/core/node_modules/@actions/http-client": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-3.0.1.tgz", - "integrity": "sha512-SbGS8c/vySbNO3kjFgSW77n83C4MQx/Yoe+b1hAdpuvfHxnkHzDq2pWljUpAA56Si1Gae/7zjeZsV0CYjmLo/w==", - "license": "MIT", - "dependencies": { - "tunnel": "^0.0.6", - "undici": "^5.28.5" - } - }, "node_modules/@actions/exec": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/@actions/exec/-/exec-2.0.0.tgz", @@ -89,28 +79,28 @@ } }, "node_modules/@actions/github": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/@actions/github/-/github-6.0.1.tgz", - "integrity": "sha512-xbZVcaqD4XnQAe35qSQqskb3SqIAfRyLBrHMd/8TuL7hJSz2QtbDwnNM8zWx4zO5l2fnGtseNE3MbEvD7BxVMw==", + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/@actions/github/-/github-9.0.0.tgz", + "integrity": "sha512-yJ0RoswsAaKcvkmpCE4XxBRiy/whH2SdTBHWzs0gi4wkqTDhXMChjSdqBz/F4AeiDlP28rQqL33iHb+kjAMX6w==", "license": "MIT", "dependencies": { - "@actions/http-client": "^2.2.0", - "@octokit/core": "^5.0.1", - "@octokit/plugin-paginate-rest": "^9.2.2", - "@octokit/plugin-rest-endpoint-methods": "^10.4.0", - "@octokit/request": "^8.4.1", - "@octokit/request-error": "^5.1.1", - "undici": "^5.28.5" + "@actions/http-client": "^3.0.2", + "@octokit/core": "^7.0.6", + "@octokit/plugin-paginate-rest": "^14.0.0", + "@octokit/plugin-rest-endpoint-methods": "^17.0.0", + "@octokit/request": "^10.0.7", + "@octokit/request-error": "^7.1.0", + "undici": "^6.23.0" } }, "node_modules/@actions/http-client": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-2.2.3.tgz", - "integrity": "sha512-mx8hyJi/hjFvbPokCg4uRd4ZX78t+YyRPtnKWwIl+RzNaVuFpQHfmlGVfsKEJN8LwTCvL+DfVgAM04XaHkm6bA==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-3.0.2.tgz", + "integrity": "sha512-JP38FYYpyqvUsz+Igqlc/JG6YO9PaKuvqjM3iGvaLqFnJ7TFmcLyy2IDrY0bI0qCQug8E9K+elv5ZNfw62ZJzA==", "license": "MIT", "dependencies": { "tunnel": "^0.0.6", - "undici": "^5.25.4" + "undici": "^6.23.0" } }, "node_modules/@actions/io": { @@ -890,14 +880,6 @@ "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, - "node_modules/@fastify/busboy": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@fastify/busboy/-/busboy-2.0.0.tgz", - "integrity": "sha512-JUFJad5lv7jxj926GPgymrWQxxjPYuJNiNjNMzqT+HiuP6Vl3dk5xzG+8sTX96np0ZAluvaMzPsjhHZ5rNuNQQ==", - "engines": { - "node": ">=14" - } - }, "node_modules/@humanfs/core": { "version": "0.19.1", "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz", @@ -2597,239 +2579,6 @@ } }, "node_modules/@octokit/auth-token": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/@octokit/auth-token/-/auth-token-4.0.0.tgz", - "integrity": "sha512-tY/msAuJo6ARbK6SPIxZrPBms3xPbfwBrulZe0Wtr/DIY9lje2HeV1uoebShn6mx7SjCHif6EjMvoREj+gZ+SA==", - "engines": { - "node": ">= 18" - } - }, - "node_modules/@octokit/core": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/@octokit/core/-/core-5.2.0.tgz", - "integrity": "sha512-1LFfa/qnMQvEOAdzlQymH0ulepxbxnCYAKJZfMci/5XJyIHWgEYnDmgnKakbTh7CH2tFQ5O60oYDvns4i9RAIg==", - "dependencies": { - "@octokit/auth-token": "^4.0.0", - "@octokit/graphql": "^7.1.0", - "@octokit/request": "^8.3.1", - "@octokit/request-error": "^5.1.0", - "@octokit/types": "^13.0.0", - "before-after-hook": "^2.2.0", - "universal-user-agent": "^6.0.0" - }, - "engines": { - "node": ">= 18" - } - }, - "node_modules/@octokit/core/node_modules/@octokit/openapi-types": { - "version": "24.2.0", - "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-24.2.0.tgz", - "integrity": "sha512-9sIH3nSUttelJSXUrmGzl7QUBFul0/mB8HRYl3fOlgHbIWG+WnYDXU3v/2zMtAvuzZ/ed00Ei6on975FhBfzrg==", - "license": "MIT" - }, - "node_modules/@octokit/core/node_modules/@octokit/types": { - "version": "13.10.0", - "resolved": "https://registry.npmjs.org/@octokit/types/-/types-13.10.0.tgz", - "integrity": "sha512-ifLaO34EbbPj0Xgro4G5lP5asESjwHracYJvVaPIyXMuiuXLlhic3S47cBdTb+jfODkTE5YtGCLt3Ay3+J97sA==", - "license": "MIT", - "dependencies": { - "@octokit/openapi-types": "^24.2.0" - } - }, - "node_modules/@octokit/endpoint": { - "version": "9.0.6", - "resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-9.0.6.tgz", - "integrity": "sha512-H1fNTMA57HbkFESSt3Y9+FBICv+0jFceJFPWDePYlR/iMGrwM5ph+Dd4XRQs+8X+PUFURLQgX9ChPfhJ/1uNQw==", - "license": "MIT", - "dependencies": { - "@octokit/types": "^13.1.0", - "universal-user-agent": "^6.0.0" - }, - "engines": { - "node": ">= 18" - } - }, - "node_modules/@octokit/endpoint/node_modules/@octokit/openapi-types": { - "version": "24.2.0", - "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-24.2.0.tgz", - "integrity": "sha512-9sIH3nSUttelJSXUrmGzl7QUBFul0/mB8HRYl3fOlgHbIWG+WnYDXU3v/2zMtAvuzZ/ed00Ei6on975FhBfzrg==", - "license": "MIT" - }, - "node_modules/@octokit/endpoint/node_modules/@octokit/types": { - "version": "13.10.0", - "resolved": "https://registry.npmjs.org/@octokit/types/-/types-13.10.0.tgz", - "integrity": "sha512-ifLaO34EbbPj0Xgro4G5lP5asESjwHracYJvVaPIyXMuiuXLlhic3S47cBdTb+jfODkTE5YtGCLt3Ay3+J97sA==", - "license": "MIT", - "dependencies": { - "@octokit/openapi-types": "^24.2.0" - } - }, - "node_modules/@octokit/graphql": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/@octokit/graphql/-/graphql-7.1.0.tgz", - "integrity": "sha512-r+oZUH7aMFui1ypZnAvZmn0KSqAUgE1/tUXIWaqUCa1758ts/Jio84GZuzsvUkme98kv0WFY8//n0J1Z+vsIsQ==", - "dependencies": { - "@octokit/request": "^8.3.0", - "@octokit/types": "^13.0.0", - "universal-user-agent": "^6.0.0" - }, - "engines": { - "node": ">= 18" - } - }, - "node_modules/@octokit/graphql/node_modules/@octokit/openapi-types": { - "version": "24.2.0", - "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-24.2.0.tgz", - "integrity": "sha512-9sIH3nSUttelJSXUrmGzl7QUBFul0/mB8HRYl3fOlgHbIWG+WnYDXU3v/2zMtAvuzZ/ed00Ei6on975FhBfzrg==", - "license": "MIT" - }, - "node_modules/@octokit/graphql/node_modules/@octokit/types": { - "version": "13.10.0", - "resolved": "https://registry.npmjs.org/@octokit/types/-/types-13.10.0.tgz", - "integrity": "sha512-ifLaO34EbbPj0Xgro4G5lP5asESjwHracYJvVaPIyXMuiuXLlhic3S47cBdTb+jfODkTE5YtGCLt3Ay3+J97sA==", - "license": "MIT", - "dependencies": { - "@octokit/openapi-types": "^24.2.0" - } - }, - "node_modules/@octokit/openapi-types": { - "version": "27.0.0", - "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-27.0.0.tgz", - "integrity": "sha512-whrdktVs1h6gtR+09+QsNk2+FO+49j6ga1c55YZudfEG+oKJVvJLQi3zkOm5JjiUXAagWK2tI2kTGKJ2Ys7MGA==", - "license": "MIT" - }, - "node_modules/@octokit/plugin-paginate-rest": { - "version": "9.2.2", - "resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-9.2.2.tgz", - "integrity": "sha512-u3KYkGF7GcZnSD/3UP0S7K5XUFT2FkOQdcfXZGZQPGv3lm4F2Xbf71lvjldr8c1H3nNbF+33cLEkWYbokGWqiQ==", - "license": "MIT", - "dependencies": { - "@octokit/types": "^12.6.0" - }, - "engines": { - "node": ">= 18" - }, - "peerDependencies": { - "@octokit/core": "5" - } - }, - "node_modules/@octokit/plugin-paginate-rest/node_modules/@octokit/openapi-types": { - "version": "20.0.0", - "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-20.0.0.tgz", - "integrity": "sha512-EtqRBEjp1dL/15V7WiX5LJMIxxkdiGJnabzYx5Apx4FkQIFgAfKumXeYAqqJCj1s+BMX4cPFIFC4OLCR6stlnA==", - "license": "MIT" - }, - "node_modules/@octokit/plugin-paginate-rest/node_modules/@octokit/types": { - "version": "12.6.0", - "resolved": "https://registry.npmjs.org/@octokit/types/-/types-12.6.0.tgz", - "integrity": "sha512-1rhSOfRa6H9w4YwK0yrf5faDaDTb+yLyBUKOCV4xtCDB5VmIPqd/v9yr9o6SAzOAlRxMiRiCic6JVM1/kunVkw==", - "license": "MIT", - "dependencies": { - "@octokit/openapi-types": "^20.0.0" - } - }, - "node_modules/@octokit/plugin-rest-endpoint-methods": { - "version": "10.4.1", - "resolved": "https://registry.npmjs.org/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-10.4.1.tgz", - "integrity": "sha512-xV1b+ceKV9KytQe3zCVqjg+8GTGfDYwaT1ATU5isiUyVtlVAO3HNdzpS4sr4GBx4hxQ46s7ITtZrAsxG22+rVg==", - "dependencies": { - "@octokit/types": "^12.6.0" - }, - "engines": { - "node": ">= 18" - }, - "peerDependencies": { - "@octokit/core": "5" - } - }, - "node_modules/@octokit/plugin-rest-endpoint-methods/node_modules/@octokit/openapi-types": { - "version": "20.0.0", - "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-20.0.0.tgz", - "integrity": "sha512-EtqRBEjp1dL/15V7WiX5LJMIxxkdiGJnabzYx5Apx4FkQIFgAfKumXeYAqqJCj1s+BMX4cPFIFC4OLCR6stlnA==" - }, - "node_modules/@octokit/plugin-rest-endpoint-methods/node_modules/@octokit/types": { - "version": "12.6.0", - "resolved": "https://registry.npmjs.org/@octokit/types/-/types-12.6.0.tgz", - "integrity": "sha512-1rhSOfRa6H9w4YwK0yrf5faDaDTb+yLyBUKOCV4xtCDB5VmIPqd/v9yr9o6SAzOAlRxMiRiCic6JVM1/kunVkw==", - "dependencies": { - "@octokit/openapi-types": "^20.0.0" - } - }, - "node_modules/@octokit/request": { - "version": "8.4.1", - "resolved": "https://registry.npmjs.org/@octokit/request/-/request-8.4.1.tgz", - "integrity": "sha512-qnB2+SY3hkCmBxZsR/MPCybNmbJe4KAlfWErXq+rBKkQJlbjdJeS85VI9r8UqeLYLvnAenU8Q1okM/0MBsAGXw==", - "license": "MIT", - "dependencies": { - "@octokit/endpoint": "^9.0.6", - "@octokit/request-error": "^5.1.1", - "@octokit/types": "^13.1.0", - "universal-user-agent": "^6.0.0" - }, - "engines": { - "node": ">= 18" - } - }, - "node_modules/@octokit/request-error": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-5.1.1.tgz", - "integrity": "sha512-v9iyEQJH6ZntoENr9/yXxjuezh4My67CBSu9r6Ve/05Iu5gNgnisNWOsoJHTP6k0Rr0+HQIpnH+kyammu90q/g==", - "license": "MIT", - "dependencies": { - "@octokit/types": "^13.1.0", - "deprecation": "^2.0.0", - "once": "^1.4.0" - }, - "engines": { - "node": ">= 18" - } - }, - "node_modules/@octokit/request-error/node_modules/@octokit/openapi-types": { - "version": "24.2.0", - "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-24.2.0.tgz", - "integrity": "sha512-9sIH3nSUttelJSXUrmGzl7QUBFul0/mB8HRYl3fOlgHbIWG+WnYDXU3v/2zMtAvuzZ/ed00Ei6on975FhBfzrg==", - "license": "MIT" - }, - "node_modules/@octokit/request-error/node_modules/@octokit/types": { - "version": "13.10.0", - "resolved": "https://registry.npmjs.org/@octokit/types/-/types-13.10.0.tgz", - "integrity": "sha512-ifLaO34EbbPj0Xgro4G5lP5asESjwHracYJvVaPIyXMuiuXLlhic3S47cBdTb+jfODkTE5YtGCLt3Ay3+J97sA==", - "license": "MIT", - "dependencies": { - "@octokit/openapi-types": "^24.2.0" - } - }, - "node_modules/@octokit/request/node_modules/@octokit/openapi-types": { - "version": "24.2.0", - "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-24.2.0.tgz", - "integrity": "sha512-9sIH3nSUttelJSXUrmGzl7QUBFul0/mB8HRYl3fOlgHbIWG+WnYDXU3v/2zMtAvuzZ/ed00Ei6on975FhBfzrg==", - "license": "MIT" - }, - "node_modules/@octokit/request/node_modules/@octokit/types": { - "version": "13.10.0", - "resolved": "https://registry.npmjs.org/@octokit/types/-/types-13.10.0.tgz", - "integrity": "sha512-ifLaO34EbbPj0Xgro4G5lP5asESjwHracYJvVaPIyXMuiuXLlhic3S47cBdTb+jfODkTE5YtGCLt3Ay3+J97sA==", - "license": "MIT", - "dependencies": { - "@octokit/openapi-types": "^24.2.0" - } - }, - "node_modules/@octokit/rest": { - "version": "22.0.1", - "resolved": "https://registry.npmjs.org/@octokit/rest/-/rest-22.0.1.tgz", - "integrity": "sha512-Jzbhzl3CEexhnivb1iQ0KJ7s5vvjMWcmRtq5aUsKmKDrRW6z3r84ngmiFKFvpZjpiU/9/S6ITPFRpn5s/3uQJw==", - "license": "MIT", - "dependencies": { - "@octokit/core": "^7.0.6", - "@octokit/plugin-paginate-rest": "^14.0.0", - "@octokit/plugin-request-log": "^6.0.0", - "@octokit/plugin-rest-endpoint-methods": "^17.0.0" - }, - "engines": { - "node": ">= 20" - } - }, - "node_modules/@octokit/rest/node_modules/@octokit/auth-token": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/@octokit/auth-token/-/auth-token-6.0.0.tgz", "integrity": "sha512-P4YJBPdPSpWTQ1NU4XYdvHvXJJDxM6YwpS0FZHRgP7YFkdVxsWcpWGy/NVqlAA7PcPCnMacXlRm1y2PFZRWL/w==", @@ -2838,7 +2587,7 @@ "node": ">= 20" } }, - "node_modules/@octokit/rest/node_modules/@octokit/core": { + "node_modules/@octokit/core": { "version": "7.0.6", "resolved": "https://registry.npmjs.org/@octokit/core/-/core-7.0.6.tgz", "integrity": "sha512-DhGl4xMVFGVIyMwswXeyzdL4uXD5OGILGX5N8Y+f6W7LhC1Ze2poSNrkF/fedpVDHEEZ+PHFW0vL14I+mm8K3Q==", @@ -2856,10 +2605,10 @@ "node": ">= 20" } }, - "node_modules/@octokit/rest/node_modules/@octokit/endpoint": { - "version": "11.0.2", - "resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-11.0.2.tgz", - "integrity": "sha512-4zCpzP1fWc7QlqunZ5bSEjxc6yLAlRTnDwKtgXfcI/FxxGoqedDG8V2+xJ60bV2kODqcGB+nATdtap/XYq2NZQ==", + "node_modules/@octokit/endpoint": { + "version": "11.0.3", + "resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-11.0.3.tgz", + "integrity": "sha512-FWFlNxghg4HrXkD3ifYbS/IdL/mDHjh9QcsNyhQjN8dplUoZbejsdpmuqdA76nxj2xoWPs7p8uX2SNr9rYu0Ag==", "license": "MIT", "dependencies": { "@octokit/types": "^16.0.0", @@ -2869,7 +2618,7 @@ "node": ">= 20" } }, - "node_modules/@octokit/rest/node_modules/@octokit/graphql": { + "node_modules/@octokit/graphql": { "version": "9.0.3", "resolved": "https://registry.npmjs.org/@octokit/graphql/-/graphql-9.0.3.tgz", "integrity": "sha512-grAEuupr/C1rALFnXTv6ZQhFuL1D8G5y8CN04RgrO4FIPMrtm+mcZzFG7dcBm+nq+1ppNixu+Jd78aeJOYxlGA==", @@ -2883,7 +2632,13 @@ "node": ">= 20" } }, - "node_modules/@octokit/rest/node_modules/@octokit/plugin-paginate-rest": { + "node_modules/@octokit/openapi-types": { + "version": "27.0.0", + "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-27.0.0.tgz", + "integrity": "sha512-whrdktVs1h6gtR+09+QsNk2+FO+49j6ga1c55YZudfEG+oKJVvJLQi3zkOm5JjiUXAagWK2tI2kTGKJ2Ys7MGA==", + "license": "MIT" + }, + "node_modules/@octokit/plugin-paginate-rest": { "version": "14.0.0", "resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-14.0.0.tgz", "integrity": "sha512-fNVRE7ufJiAA3XUrha2omTA39M6IXIc6GIZLvlbsm8QOQCYvpq/LkMNGyFlB1d8hTDzsAXa3OKtybdMAYsV/fw==", @@ -2898,19 +2653,7 @@ "@octokit/core": ">=6" } }, - "node_modules/@octokit/rest/node_modules/@octokit/plugin-request-log": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/@octokit/plugin-request-log/-/plugin-request-log-6.0.0.tgz", - "integrity": "sha512-UkOzeEN3W91/eBq9sPZNQ7sUBvYCqYbrrD8gTbBuGtHEuycE4/awMXcYvx6sVYo7LypPhmQwwpUe4Yyu4QZN5Q==", - "license": "MIT", - "engines": { - "node": ">= 20" - }, - "peerDependencies": { - "@octokit/core": ">=6" - } - }, - "node_modules/@octokit/rest/node_modules/@octokit/plugin-rest-endpoint-methods": { + "node_modules/@octokit/plugin-rest-endpoint-methods": { "version": "17.0.0", "resolved": "https://registry.npmjs.org/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-17.0.0.tgz", "integrity": "sha512-B5yCyIlOJFPqUUeiD0cnBJwWJO8lkJs5d8+ze9QDP6SvfiXSz1BF+91+0MeI1d2yxgOhU/O+CvtiZ9jSkHhFAw==", @@ -2925,26 +2668,27 @@ "@octokit/core": ">=6" } }, - "node_modules/@octokit/rest/node_modules/@octokit/request": { - "version": "10.0.6", - "resolved": "https://registry.npmjs.org/@octokit/request/-/request-10.0.6.tgz", - "integrity": "sha512-FO+UgZCUu+pPnZAR+iKdUt64kPE7QW7ciqpldaMXaNzixz5Jld8dJ31LAUewk0cfSRkNSRKyqG438ba9c/qDlQ==", + "node_modules/@octokit/request": { + "version": "10.0.8", + "resolved": "https://registry.npmjs.org/@octokit/request/-/request-10.0.8.tgz", + "integrity": "sha512-SJZNwY9pur9Agf7l87ywFi14W+Hd9Jg6Ifivsd33+/bGUQIjNujdFiXII2/qSlN2ybqUHfp5xpekMEjIBTjlSw==", "license": "MIT", "dependencies": { - "@octokit/endpoint": "^11.0.2", + "@octokit/endpoint": "^11.0.3", "@octokit/request-error": "^7.0.2", "@octokit/types": "^16.0.0", "fast-content-type-parse": "^3.0.0", + "json-with-bigint": "^3.5.3", "universal-user-agent": "^7.0.2" }, "engines": { "node": ">= 20" } }, - "node_modules/@octokit/rest/node_modules/@octokit/request-error": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-7.0.2.tgz", - "integrity": "sha512-U8piOROoQQUyExw5c6dTkU3GKxts5/ERRThIauNL7yaRoeXW0q/5bgHWT7JfWBw1UyrbK8ERId2wVkcB32n0uQ==", + "node_modules/@octokit/request-error": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-7.1.0.tgz", + "integrity": "sha512-KMQIfq5sOPpkQYajXHwnhjCC0slzCNScLHs9JafXc4RAJI+9f+jNDlBNaIMTvazOPLgb4BnlhGJOTbnN0wIjPw==", "license": "MIT", "dependencies": { "@octokit/types": "^16.0.0" @@ -2953,17 +2697,32 @@ "node": ">= 20" } }, - "node_modules/@octokit/rest/node_modules/before-after-hook": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/before-after-hook/-/before-after-hook-4.0.0.tgz", - "integrity": "sha512-q6tR3RPqIB1pMiTRMFcZwuG5T8vwp+vUvEG0vuI6B+Rikh5BfPp2fQ82c925FOs+b0lcFQ8CFrL+KbilfZFhOQ==", - "license": "Apache-2.0" + "node_modules/@octokit/rest": { + "version": "22.0.1", + "resolved": "https://registry.npmjs.org/@octokit/rest/-/rest-22.0.1.tgz", + "integrity": "sha512-Jzbhzl3CEexhnivb1iQ0KJ7s5vvjMWcmRtq5aUsKmKDrRW6z3r84ngmiFKFvpZjpiU/9/S6ITPFRpn5s/3uQJw==", + "license": "MIT", + "dependencies": { + "@octokit/core": "^7.0.6", + "@octokit/plugin-paginate-rest": "^14.0.0", + "@octokit/plugin-request-log": "^6.0.0", + "@octokit/plugin-rest-endpoint-methods": "^17.0.0" + }, + "engines": { + "node": ">= 20" + } }, - "node_modules/@octokit/rest/node_modules/universal-user-agent": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-7.0.3.tgz", - "integrity": "sha512-TmnEAEAsBJVZM/AADELsK76llnwcf9vMKuPz8JflO1frO8Lchitr0fNaN9d+Ap0BjKtqWqd/J17qeDnXh8CL2A==", - "license": "ISC" + "node_modules/@octokit/rest/node_modules/@octokit/plugin-request-log": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/@octokit/plugin-request-log/-/plugin-request-log-6.0.0.tgz", + "integrity": "sha512-UkOzeEN3W91/eBq9sPZNQ7sUBvYCqYbrrD8gTbBuGtHEuycE4/awMXcYvx6sVYo7LypPhmQwwpUe4Yyu4QZN5Q==", + "license": "MIT", + "engines": { + "node": ">= 20" + }, + "peerDependencies": { + "@octokit/core": ">=6" + } }, "node_modules/@octokit/types": { "version": "16.0.0", @@ -4699,9 +4458,10 @@ "dev": true }, "node_modules/before-after-hook": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/before-after-hook/-/before-after-hook-2.2.3.tgz", - "integrity": "sha512-NzUnlZexiaH/46WDhANlyR2bXRopNg4F/zuSA3OpZnllCUgRaOF2znDioDWrmbNVsuZk6l9pMquQB38cfBZwkQ==" + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/before-after-hook/-/before-after-hook-4.0.0.tgz", + "integrity": "sha512-q6tR3RPqIB1pMiTRMFcZwuG5T8vwp+vUvEG0vuI6B+Rikh5BfPp2fQ82c925FOs+b0lcFQ8CFrL+KbilfZFhOQ==", + "license": "Apache-2.0" }, "node_modules/brace-expansion": { "version": "1.1.12", @@ -5158,11 +4918,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/deprecation": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/deprecation/-/deprecation-2.3.1.tgz", - "integrity": "sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ==" - }, "node_modules/detect-newline": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", @@ -9796,6 +9551,12 @@ "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", "dev": true }, + "node_modules/json-with-bigint": { + "version": "3.5.7", + "resolved": "https://registry.npmjs.org/json-with-bigint/-/json-with-bigint-3.5.7.tgz", + "integrity": "sha512-7ei3MdAI5+fJPVnKlW77TKNKwQ5ppSzWvhPuSuINT/GYW9ZOC1eRKOuhV9yHG5aEsUPj9BBx5JIekkmoLHxZOw==", + "license": "MIT" + }, "node_modules/json5": { "version": "2.2.3", "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", @@ -10313,6 +10074,7 @@ "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, "dependencies": { "wrappy": "1" } @@ -12270,15 +12032,12 @@ } }, "node_modules/undici": { - "version": "5.29.0", - "resolved": "https://registry.npmjs.org/undici/-/undici-5.29.0.tgz", - "integrity": "sha512-raqeBD6NQK4SkWhQzeYKd1KmIG6dllBOTt55Rmkt4HtI9mwdWtJljnrXjAFUBLTSN67HWrOIZ3EPF4kjUw80Bg==", + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/undici/-/undici-6.24.1.tgz", + "integrity": "sha512-sC+b0tB1whOCzbtlx20fx3WgCXwkW627p4EA9uM+/tNNPkSS+eSEld6pAs9nDv7WbY1UUljBMYPtu9BCOrCWKA==", "license": "MIT", - "dependencies": { - "@fastify/busboy": "^2.0.0" - }, "engines": { - "node": ">=14.0" + "node": ">=18.17" } }, "node_modules/undici-types": { @@ -12289,9 +12048,10 @@ "license": "MIT" }, "node_modules/universal-user-agent": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-6.0.1.tgz", - "integrity": "sha512-yCzhz6FN2wU1NiiQRogkTQszlQSlpWaw8SvVegAc+bDxbzHgh1vX8uIe8OYyMH6DwH+sdTJsgMl36+mSMdRJIQ==" + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-7.0.3.tgz", + "integrity": "sha512-TmnEAEAsBJVZM/AADELsK76llnwcf9vMKuPz8JflO1frO8Lchitr0fNaN9d+Ap0BjKtqWqd/J17qeDnXh8CL2A==", + "license": "ISC" }, "node_modules/unrs-resolver": { "version": "1.9.2", @@ -12590,7 +12350,8 @@ "node_modules/wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true }, "node_modules/write-file-atomic": { "version": "5.0.1", diff --git a/package.json b/package.json index 50e08f1..7bf24ec 100644 --- a/package.json +++ b/package.json @@ -41,7 +41,7 @@ }, "dependencies": { "@actions/core": "^2.0.2", - "@actions/github": "^6.0.1", + "@actions/github": "^9.0.0", "@octokit/rest": "^22.0.1", "handlebars": "^4.7.8", "ts-dedent": "^2.2.0", From d65fefd04d6ed7dbee418e067b5301e6aa8f3515 Mon Sep 17 00:00:00 2001 From: Nick Alteen Date: Thu, 19 Mar 2026 11:27:48 -0400 Subject: [PATCH 2/2] Rebuild dist --- dist/index.js | 30631 ++++++++++++++++++++++---------------------- package-lock.json | 22 +- 2 files changed, 15056 insertions(+), 15597 deletions(-) diff --git a/dist/index.js b/dist/index.js index 4e7ecbb..90b318a 100644 --- a/dist/index.js +++ b/dist/index.js @@ -1,31 +1,34 @@ -import require$$0 from 'os'; +import require$$0, { EOL } from 'os'; import require$$0$1 from 'crypto'; -import fs from 'fs'; -import require$$1$5 from 'path'; -import require$$2$1 from 'http'; -import require$$1 from 'https'; -import require$$0$4 from 'net'; -import require$$1$1 from 'tls'; -import require$$4$1 from 'events'; -import require$$0$3 from 'assert'; -import require$$0$2 from 'util'; -import require$$0$5 from 'stream'; -import require$$7 from 'buffer'; -import require$$8 from 'querystring'; -import require$$14 from 'stream/web'; -import require$$0$7 from 'node:stream'; -import require$$1$2 from 'node:util'; -import require$$0$6 from 'node:events'; -import require$$0$8 from 'worker_threads'; -import require$$2$2 from 'perf_hooks'; -import require$$5 from 'util/types'; -import require$$4$2 from 'async_hooks'; -import require$$1$3 from 'console'; -import require$$1$4 from 'url'; -import require$$3$1 from 'zlib'; -import require$$6 from 'string_decoder'; -import require$$0$9 from 'diagnostics_channel'; -import require$$2$3 from 'child_process'; +import fs, { existsSync, readFileSync } from 'fs'; +import require$$1$6 from 'path'; +import require$$2 from 'http'; +import require$$3 from 'https'; +import 'net'; +import require$$1 from 'tls'; +import require$$4 from 'events'; +import require$$5$4 from 'assert'; +import require$$6 from 'util'; +import require$$0$3 from 'node:assert'; +import require$$0$5 from 'node:net'; +import require$$2$1 from 'node:http'; +import require$$0$4 from 'node:stream'; +import require$$0$2 from 'node:buffer'; +import require$$0$6 from 'node:util'; +import require$$7 from 'node:querystring'; +import require$$8 from 'node:events'; +import require$$0$7 from 'node:diagnostics_channel'; +import require$$5 from 'node:tls'; +import require$$1$2 from 'node:zlib'; +import require$$5$1 from 'node:perf_hooks'; +import require$$8$1 from 'node:util/types'; +import require$$1$1 from 'node:worker_threads'; +import require$$1$3 from 'node:url'; +import require$$5$2 from 'node:async_hooks'; +import require$$1$4 from 'node:console'; +import require$$1$5 from 'node:dns'; +import require$$5$3 from 'string_decoder'; +import require$$2$2 from 'child_process'; import require$$6$1 from 'timers'; var commonjsGlobal = typeof globalThis !== 'undefined' ? globalThis : typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {}; @@ -34,51 +37,22 @@ function getDefaultExportFromCjs (x) { return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x; } -function getAugmentedNamespace(n) { - if (Object.prototype.hasOwnProperty.call(n, '__esModule')) return n; - var f = n.default; - if (typeof f == "function") { - var a = function a () { - var isInstance = false; - try { - isInstance = this instanceof a; - } catch {} - if (isInstance) { - return Reflect.construct(f, arguments, this.constructor); - } - return f.apply(this, arguments); - }; - a.prototype = f.prototype; - } else a = {}; - Object.defineProperty(a, '__esModule', {value: true}); - Object.keys(n).forEach(function (k) { - var d = Object.getOwnPropertyDescriptor(n, k); - Object.defineProperty(a, k, d.get ? d : { - enumerable: true, - get: function () { - return n[k]; - } - }); - }); - return a; -} - var core = {}; var command = {}; -var utils$4 = {}; +var utils$2 = {}; -var hasRequiredUtils$4; +var hasRequiredUtils$2; -function requireUtils$4 () { - if (hasRequiredUtils$4) return utils$4; - hasRequiredUtils$4 = 1; +function requireUtils$2 () { + if (hasRequiredUtils$2) return utils$2; + hasRequiredUtils$2 = 1; // We use any as a valid input type /* eslint-disable @typescript-eslint/no-explicit-any */ - Object.defineProperty(utils$4, "__esModule", { value: true }); - utils$4.toCommandValue = toCommandValue; - utils$4.toCommandProperties = toCommandProperties; + Object.defineProperty(utils$2, "__esModule", { value: true }); + utils$2.toCommandValue = toCommandValue; + utils$2.toCommandProperties = toCommandProperties; /** * Sanitizes an input into a string so it can be passed into issueCommand safely * @param input input to sanitize into a string @@ -112,7 +86,7 @@ function requireUtils$4 () { }; } - return utils$4; + return utils$2; } var hasRequiredCommand; @@ -157,7 +131,7 @@ function requireCommand () { command.issueCommand = issueCommand; command.issue = issue; const os = __importStar(require$$0); - const utils_1 = requireUtils$4(); + const utils_1 = requireUtils$2(); /** * Issues a command to the GitHub Actions runner * @@ -299,7 +273,7 @@ function requireFileCommand () { const crypto = __importStar(require$$0$1); const fs$1 = __importStar(fs); const os = __importStar(require$$0); - const utils_1 = requireUtils$4(); + const utils_1 = requireUtils$2(); function issueFileCommand(command, message) { const filePath = process.env[`GITHUB_${command}`]; if (!filePath) { @@ -332,18 +306,18 @@ function requireFileCommand () { var oidcUtils = {}; -var lib$2 = {}; +var lib$1 = {}; -var proxy$1 = {}; +var proxy = {}; -var hasRequiredProxy$1; +var hasRequiredProxy; -function requireProxy$1 () { - if (hasRequiredProxy$1) return proxy$1; - hasRequiredProxy$1 = 1; - Object.defineProperty(proxy$1, "__esModule", { value: true }); - proxy$1.getProxyUrl = getProxyUrl; - proxy$1.checkBypass = checkBypass; +function requireProxy () { + if (hasRequiredProxy) return proxy; + hasRequiredProxy = 1; + Object.defineProperty(proxy, "__esModule", { value: true }); + proxy.getProxyUrl = getProxyUrl; + proxy.checkBypass = checkBypass; function getProxyUrl(reqUrl) { const usingSsl = reqUrl.protocol === 'https:'; if (checkBypass(reqUrl)) { @@ -434,7 +408,7 @@ function requireProxy$1 () { } } - return proxy$1; + return proxy; } var tunnel$1 = {}; @@ -444,11 +418,11 @@ var hasRequiredTunnel$1; function requireTunnel$1 () { if (hasRequiredTunnel$1) return tunnel$1; hasRequiredTunnel$1 = 1; - var tls = require$$1$1; - var http = require$$2$1; - var https = require$$1; - var events = require$$4$1; - var util = require$$0$2; + var tls = require$$1; + var http = require$$2; + var https = require$$3; + var events = require$$4; + var util = require$$6; tunnel$1.httpOverHttp = httpOverHttp; @@ -735,7 +709,6 @@ function requireSymbols$4 () { kQueue: Symbol('queue'), kConnect: Symbol('connect'), kConnecting: Symbol('connecting'), - kHeadersList: Symbol('headers list'), kKeepAliveDefaultTimeout: Symbol('default keep alive timeout'), kKeepAliveMaxTimeout: Symbol('max keep alive timeout'), kKeepAliveTimeoutThreshold: Symbol('keep alive timeout threshold'), @@ -748,6 +721,7 @@ function requireSymbols$4 () { kHost: Symbol('host'), kNoRef: Symbol('no ref'), kBodyUsed: Symbol('used'), + kBody: Symbol('abstracted request body'), kRunning: Symbol('running'), kBlocking: Symbol('blocking'), kPending: Symbol('pending'), @@ -760,6 +734,8 @@ function requireSymbols$4 () { kNeedDrain: Symbol('need drain'), kReset: Symbol('reset'), kDestroyed: Symbol.for('nodejs.stream.destroyed'), + kResume: Symbol('resume'), + kOnError: Symbol('on error'), kMaxHeadersSize: Symbol('max headers size'), kRunningIdx: Symbol('running index'), kPendingIdx: Symbol('pending index'), @@ -781,12 +757,14 @@ function requireSymbols$4 () { kMaxResponseSize: Symbol('max response size'), kHTTP2Session: Symbol('http2Session'), kHTTP2SessionState: Symbol('http2Session state'), - kHTTP2BuildRequest: Symbol('http2 build request'), - kHTTP1BuildRequest: Symbol('http1 build request'), - kHTTP2CopyHeaders: Symbol('http2 copy headers'), - kHTTPConnVersion: Symbol('http connection version'), kRetryHandlerDefaultRetry: Symbol('retry agent default retry'), - kConstruct: Symbol('constructable') + kConstruct: Symbol('constructable'), + kListeners: Symbol('listeners'), + kHTTPContext: Symbol('http context'), + kMaxConcurrentStreams: Symbol('max concurrent streams'), + kNoProxyAgent: Symbol('no proxy agent'), + kHttpProxyAgent: Symbol('http proxy agent'), + kHttpsProxyAgent: Symbol('https proxy agent') }; return symbols$4; } @@ -798,58 +776,89 @@ function requireErrors () { if (hasRequiredErrors) return errors; hasRequiredErrors = 1; + const kUndiciError = Symbol.for('undici.error.UND_ERR'); class UndiciError extends Error { constructor (message) { super(message); this.name = 'UndiciError'; this.code = 'UND_ERR'; } + + static [Symbol.hasInstance] (instance) { + return instance && instance[kUndiciError] === true + } + + [kUndiciError] = true } + const kConnectTimeoutError = Symbol.for('undici.error.UND_ERR_CONNECT_TIMEOUT'); class ConnectTimeoutError extends UndiciError { constructor (message) { super(message); - Error.captureStackTrace(this, ConnectTimeoutError); 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 } + const kHeadersTimeoutError = Symbol.for('undici.error.UND_ERR_HEADERS_TIMEOUT'); class HeadersTimeoutError extends UndiciError { constructor (message) { super(message); - Error.captureStackTrace(this, HeadersTimeoutError); 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 } + const kHeadersOverflowError = Symbol.for('undici.error.UND_ERR_HEADERS_OVERFLOW'); class HeadersOverflowError extends UndiciError { constructor (message) { super(message); - Error.captureStackTrace(this, HeadersOverflowError); 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 } + const kBodyTimeoutError = Symbol.for('undici.error.UND_ERR_BODY_TIMEOUT'); class BodyTimeoutError extends UndiciError { constructor (message) { super(message); - Error.captureStackTrace(this, BodyTimeoutError); 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 } + const kResponseStatusCodeError = Symbol.for('undici.error.UND_ERR_RESPONSE_STATUS_CODE'); class ResponseStatusCodeError extends UndiciError { constructor (message, statusCode, headers, body) { super(message); - Error.captureStackTrace(this, ResponseStatusCodeError); this.name = 'ResponseStatusCodeError'; this.message = message || 'Response Status Code Error'; this.code = 'UND_ERR_RESPONSE_STATUS_CODE'; @@ -858,143 +867,243 @@ function requireErrors () { this.statusCode = statusCode; this.headers = headers; } + + static [Symbol.hasInstance] (instance) { + return instance && instance[kResponseStatusCodeError] === true + } + + [kResponseStatusCodeError] = true } + const kInvalidArgumentError = Symbol.for('undici.error.UND_ERR_INVALID_ARG'); class InvalidArgumentError extends UndiciError { constructor (message) { super(message); - Error.captureStackTrace(this, InvalidArgumentError); 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 } + const kInvalidReturnValueError = Symbol.for('undici.error.UND_ERR_INVALID_RETURN_VALUE'); class InvalidReturnValueError extends UndiciError { constructor (message) { super(message); - Error.captureStackTrace(this, InvalidReturnValueError); 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 + } + + const kAbortError = Symbol.for('undici.error.UND_ERR_ABORT'); + class AbortError 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 } - class RequestAbortedError extends UndiciError { + const kRequestAbortedError = Symbol.for('undici.error.UND_ERR_ABORTED'); + class RequestAbortedError extends AbortError { constructor (message) { super(message); - Error.captureStackTrace(this, RequestAbortedError); this.name = 'AbortError'; this.message = message || 'Request aborted'; this.code = 'UND_ERR_ABORTED'; } + + static [Symbol.hasInstance] (instance) { + return instance && instance[kRequestAbortedError] === true + } + + [kRequestAbortedError] = true } + const kInformationalError = Symbol.for('undici.error.UND_ERR_INFO'); class InformationalError extends UndiciError { constructor (message) { super(message); - Error.captureStackTrace(this, InformationalError); this.name = 'InformationalError'; this.message = message || 'Request information'; this.code = 'UND_ERR_INFO'; } + + static [Symbol.hasInstance] (instance) { + return instance && instance[kInformationalError] === true + } + + [kInformationalError] = true } + const kRequestContentLengthMismatchError = Symbol.for('undici.error.UND_ERR_REQ_CONTENT_LENGTH_MISMATCH'); class RequestContentLengthMismatchError extends UndiciError { constructor (message) { super(message); - Error.captureStackTrace(this, RequestContentLengthMismatchError); 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 } + const kResponseContentLengthMismatchError = Symbol.for('undici.error.UND_ERR_RES_CONTENT_LENGTH_MISMATCH'); class ResponseContentLengthMismatchError extends UndiciError { constructor (message) { super(message); - Error.captureStackTrace(this, ResponseContentLengthMismatchError); 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 } + const kClientDestroyedError = Symbol.for('undici.error.UND_ERR_DESTROYED'); class ClientDestroyedError extends UndiciError { constructor (message) { super(message); - Error.captureStackTrace(this, ClientDestroyedError); 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 } + const kClientClosedError = Symbol.for('undici.error.UND_ERR_CLOSED'); class ClientClosedError extends UndiciError { constructor (message) { super(message); - Error.captureStackTrace(this, ClientClosedError); 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 } + const kSocketError = Symbol.for('undici.error.UND_ERR_SOCKET'); class SocketError extends UndiciError { constructor (message, socket) { super(message); - Error.captureStackTrace(this, SocketError); 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 } + const kNotSupportedError = Symbol.for('undici.error.UND_ERR_NOT_SUPPORTED'); class NotSupportedError extends UndiciError { constructor (message) { super(message); - Error.captureStackTrace(this, NotSupportedError); 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 } + const kBalancedPoolMissingUpstreamError = Symbol.for('undici.error.UND_ERR_BPL_MISSING_UPSTREAM'); class BalancedPoolMissingUpstreamError extends UndiciError { constructor (message) { super(message); - Error.captureStackTrace(this, NotSupportedError); 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 } + const kHTTPParserError = Symbol.for('undici.error.UND_ERR_HTTP_PARSER'); class HTTPParserError extends Error { constructor (message, code, data) { super(message); - Error.captureStackTrace(this, HTTPParserError); this.name = 'HTTPParserError'; this.code = code ? `HPE_${code}` : undefined; this.data = data ? data.toString() : undefined; } + + static [Symbol.hasInstance] (instance) { + return instance && instance[kHTTPParserError] === true + } + + [kHTTPParserError] = true } + const kResponseExceededMaxSizeError = Symbol.for('undici.error.UND_ERR_RES_EXCEEDED_MAX_SIZE'); class ResponseExceededMaxSizeError extends UndiciError { constructor (message) { super(message); - Error.captureStackTrace(this, ResponseExceededMaxSizeError); 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 } + const kRequestRetryError = Symbol.for('undici.error.UND_ERR_REQ_RETRY'); class RequestRetryError extends UndiciError { constructor (message, code, { headers, data }) { super(message); - Error.captureStackTrace(this, RequestRetryError); this.name = 'RequestRetryError'; this.message = message || 'Request retry error'; this.code = 'UND_ERR_REQ_RETRY'; @@ -1002,9 +1111,70 @@ function requireErrors () { this.data = data; this.headers = headers; } + + static [Symbol.hasInstance] (instance) { + return instance && instance[kRequestRetryError] === true + } + + [kRequestRetryError] = true + } + + const kResponseError = Symbol.for('undici.error.UND_ERR_RESPONSE'); + class ResponseError 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 + } + + const kSecureProxyConnectionError = Symbol.for('undici.error.UND_ERR_PRX_TLS'); + class SecureProxyConnectionError 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 + } + + const kMessageSizeExceededError = Symbol.for('undici.error.UND_ERR_WS_MESSAGE_SIZE_EXCEEDED'); + class MessageSizeExceededError 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 + } } errors = { + AbortError, HTTPParserError, UndiciError, HeadersTimeoutError, @@ -1024,7 +1194,10 @@ function requireErrors () { ResponseContentLengthMismatchError, BalancedPoolMissingUpstreamError, ResponseExceededMaxSizeError, - RequestRetryError + RequestRetryError, + ResponseError, + SecureProxyConnectionError, + MessageSizeExceededError }; return errors; } @@ -1155,26 +1328,240 @@ function requireConstants$4 () { return constants$4; } -var util$7; -var hasRequiredUtil$7; +var tree_1; +var hasRequiredTree; -function requireUtil$7 () { - if (hasRequiredUtil$7) return util$7; - hasRequiredUtil$7 = 1; +function requireTree () { + if (hasRequiredTree) return tree_1; + hasRequiredTree = 1; + + const { + wellknownHeaderNames, + headerNameLowerCasedRecord + } = requireConstants$4(); + + 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 === undefined || index >= key.length) { + throw new TypeError('Unreachable') + } + const code = this.code = key.charCodeAt(index); + // check code is ascii string + if (code > 0x7F) { + 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); + // check code is ascii string + if (code > 0x7F) { + 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]; + // A-Z + // First check if it is bigger than 0x5a. + // Lowercase letters have higher char codes than uppercase ones. + // Also we assume that headers will mostly contain lowercase characters. + if (code <= 0x5a && code >= 0x41) { + // Lowercase for uppercase. + code |= 32; + } + while (node !== null) { + if (code === node.code) { + if (keylength === ++index) { + // Returns Node since it is the last key. + return node + } + node = node.middle; + break + } + node = node.code < code ? node.left : node.right; + } + } + return null + } + } + + class TernarySearchTree { + /** @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 + } + } + + const tree = new TernarySearchTree(); + + for (let i = 0; i < wellknownHeaderNames.length; ++i) { + const key = headerNameLowerCasedRecord[wellknownHeaderNames[i]]; + tree.insert(key, key); + } + + tree_1 = { + TernarySearchTree, + tree + }; + return tree_1; +} + +var util$8; +var hasRequiredUtil$8; + +function requireUtil$8 () { + if (hasRequiredUtil$8) return util$8; + hasRequiredUtil$8 = 1; const assert = require$$0$3; - const { kDestroyed, kBodyUsed } = requireSymbols$4(); + const { kDestroyed, kBodyUsed, kListeners, kBody } = requireSymbols$4(); const { IncomingMessage } = require$$2$1; - const stream = require$$0$5; - const net = require$$0$4; + const stream = require$$0$4; + const net = require$$0$5; + const { Blob } = require$$0$2; + const nodeUtil = require$$0$6; + const { stringify } = require$$7; + const { EventEmitter: EE } = require$$8; const { InvalidArgumentError } = requireErrors(); - const { Blob } = require$$7; - const nodeUtil = require$$0$2; - const { stringify } = require$$8; const { headerNameLowerCasedRecord } = requireConstants$4(); + const { tree } = requireTree(); const [nodeMajor, nodeMinor] = process.versions.node.split('.').map(v => Number(v)); + class BodyAsyncIterable { + 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 (isStream(body)) { + // TODO (fix): Provide some way for the user to cache the file to e.g. /tmp + // so that it can be dispatched again? + // TODO (fix): Do we need 100-expect support to provide a way to do this properly? + 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') { + // TODO (fix): We can't access ReadableStream internal state + // to determine whether or not it has been disturbed. This is just + // a workaround. + return new BodyAsyncIterable(body) + } else if ( + body && + typeof body !== 'string' && + !ArrayBuffer.isView(body) && + isIterable(body) + ) { + // TODO: Should we allow re-using iterable if !this.opts.idempotent + // or through some other flag? + return new BodyAsyncIterable(body) + } else { + return body + } + } + function nop () {} function isStream (obj) { @@ -1183,13 +1570,20 @@ function requireUtil$7 () { // based on https://github.com/node-fetch/fetch-blob/blob/8ab587d34080de94140b54f07168451e7d0b655e/index.js#L229-L241 (MIT License) function isBlobLike (object) { - return (Blob && object instanceof Blob) || ( - object && - typeof object === 'object' && - (typeof object.stream === 'function' || - typeof object.arrayBuffer === 'function') && - /^(Blob|File)$/.test(object[Symbol.toStringTag]) - ) + if (object === null) { + return false + } else if (object instanceof Blob) { + 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) { @@ -1206,11 +1600,37 @@ function requireUtil$7 () { return url } + function isValidPort (port) { + const value = parseInt(port, 10); + return ( + value === Number(port) && + 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 (!/^https?:/.test(url.origin || url.protocol)) { + if (!isHttpOrHttpsPrefixed(url.origin || url.protocol)) { throw new InvalidArgumentError('Invalid URL protocol: the URL must start with `http:` or `https:`.') } @@ -1221,12 +1641,8 @@ function requireUtil$7 () { throw new InvalidArgumentError('Invalid URL: The URL argument must be a non-null object.') } - if (!/^https?:/.test(url.origin || url.protocol)) { - throw new InvalidArgumentError('Invalid URL protocol: the URL must start with `http:` or `https:`.') - } - if (!(url instanceof URL)) { - if (url.port != null && url.port !== '' && !Number.isFinite(parseInt(url.port))) { + 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.') } @@ -1246,28 +1662,36 @@ function requireUtil$7 () { 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 port = url.port != null ? url.port : (url.protocol === 'https:' ? 443 : 80); let origin = url.origin != null ? url.origin - : `${url.protocol}//${url.hostname}:${port}`; + : `${url.protocol || ''}//${url.hostname || ''}:${port}`; let path = url.path != null ? url.path : `${url.pathname || ''}${url.search || ''}`; - if (origin.endsWith('/')) { - origin = origin.substring(0, origin.length - 1); + if (origin[origin.length - 1] === '/') { + origin = origin.slice(0, origin.length - 1); } - if (path && !path.startsWith('/')) { + if (path && path[0] !== '/') { path = `/${path}`; } // new URL(path, origin) is unsafe when `path` contains an absolute URL // From https://developer.mozilla.org/en-US/docs/Web/API/URL/URL: // If first parameter is a relative URL, second param is required, and will be used as the base URL. // If first parameter is an absolute URL, a given second param will be ignored. - url = new URL(origin + path); + return new URL(`${origin}${path}`) + } + + if (!isHttpOrHttpsPrefixed(url.origin || url.protocol)) { + throw new InvalidArgumentError('Invalid URL protocol: the URL must start with `http:` or `https:`.') } return url @@ -1304,7 +1728,7 @@ function requireUtil$7 () { return null } - assert.strictEqual(typeof host, 'string'); + assert(typeof host === 'string'); const servername = getHostname(host); if (net.isIP(servername)) { @@ -1343,13 +1767,8 @@ function requireUtil$7 () { return null } - function isDestroyed (stream) { - return !stream || !!(stream.destroyed || stream[kDestroyed]) - } - - function isReadableAborted (stream) { - const state = stream && stream._readableState; - return isDestroyed(stream) && state && !state.endEmitted + function isDestroyed (body) { + return body && !!(body.destroyed || body[kDestroyed] || (stream.isDestroyed?.(body))) } function destroy (stream, err) { @@ -1365,9 +1784,9 @@ function requireUtil$7 () { stream.destroy(err); } else if (err) { - process.nextTick((stream, err) => { + queueMicrotask(() => { stream.emit('error', err); - }, stream, err); + }); } if (stream.destroyed !== true) { @@ -1387,29 +1806,44 @@ function requireUtil$7 () { * @returns {string} */ function headerNameToString (value) { - return headerNameLowerCasedRecord[value] || value.toLowerCase() + return typeof value === 'string' + ? headerNameLowerCasedRecord[value] ?? value.toLowerCase() + : tree.lookup(value) ?? value.toString('latin1').toLowerCase() } - function parseHeaders (headers, obj = {}) { - // For H2 support - if (!Array.isArray(headers)) return headers + /** + * Receive the buffer as a string and return its lowercase value. + * @param {Buffer} value Header name + * @returns {string} + */ + function bufferToLowerCasedHeaderName (value) { + return tree.lookup(value) ?? value.toString('latin1').toLowerCase() + } + /** + * @param {Record | (Buffer | string | (Buffer | string)[])[]} headers + * @param {Record} [obj] + * @returns {Record} + */ + function parseHeaders (headers, obj) { + if (obj === undefined) obj = {}; for (let i = 0; i < headers.length; i += 2) { - const key = headers[i].toString().toLowerCase(); + const key = headerNameToString(headers[i]); let val = obj[key]; - if (!val) { - if (Array.isArray(headers[i + 1])) { - obj[key] = headers[i + 1].map(x => x.toString('utf8')); - } else { - obj[key] = headers[i + 1].toString('utf8'); - } - } else { - if (!Array.isArray(val)) { + 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'); + } } } @@ -1422,22 +1856,30 @@ function requireUtil$7 () { } function parseRawHeaders (headers) { - const ret = []; + 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) { - const key = headers[n + 0].toString(); - const val = headers[n + 1].toString('utf8'); + key = headers[n]; + val = headers[n + 1]; - if (key.length === 14 && (key === 'content-length' || key.toLowerCase() === 'content-length')) { - ret.push(key, val); + 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 (key.length === 19 && (key === 'content-disposition' || key.toLowerCase() === 'content-disposition')) { - contentDispositionIdx = ret.push(key, val) - 1; - } else { - ret.push(key, val); + } else if (kLen === 19 && key[7] === '-' && (key === 'content-disposition' || key.toLowerCase() === 'content-disposition')) { + contentDispositionIdx = n + 1; } + ret[n] = key; + ret[n + 1] = val; } // See https://github.com/nodejs/node/pull/46528 @@ -1492,30 +1934,16 @@ function requireUtil$7 () { // A body is disturbed if it has been read from and it cannot // be re-used without losing state or data. function isDisturbed (body) { - return !!(body && ( - stream.isDisturbed - ? stream.isDisturbed(body) || body[kBodyUsed] // TODO (fix): Why is body[kBodyUsed] needed? - : body[kBodyUsed] || - body.readableDidRead || - (body._readableState && body._readableState.dataEmitted) || - isReadableAborted(body) - )) + // TODO (fix): Why is body[kBodyUsed] needed? + return !!(body && (stream.isDisturbed(body) || body[kBodyUsed])) } function isErrored (body) { - return !!(body && ( - stream.isErrored - ? stream.isErrored(body) - : /state: 'errored'/.test(nodeUtil.inspect(body) - ))) + return !!(body && stream.isErrored(body)) } function isReadable (body) { - return !!(body && ( - stream.isReadable - ? stream.isReadable(body) - : /state: 'readable'/.test(nodeUtil.inspect(body) - ))) + return !!(body && stream.isReadable(body)) } function getSocketInfo (socket) { @@ -1531,21 +1959,9 @@ function requireUtil$7 () { } } - async function * convertIterableToBuffer (iterable) { - for await (const chunk of iterable) { - yield Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk); - } - } - - let ReadableStream; + /** @type {globalThis['ReadableStream']} */ function ReadableStreamFrom (iterable) { - if (!ReadableStream) { - ReadableStream = require$$14.ReadableStream; - } - - if (ReadableStream.from) { - return ReadableStream.from(convertIterableToBuffer(iterable)) - } + // We cannot use ReadableStream.from here because it does not return a byte stream. let iterator; return new ReadableStream( @@ -1558,18 +1974,21 @@ function requireUtil$7 () { if (done) { queueMicrotask(() => { controller.close(); + controller.byobRequest?.respond(0); }); } else { const buf = Buffer.isBuffer(value) ? value : Buffer.from(value); - controller.enqueue(new Uint8Array(buf)); + if (buf.byteLength) { + controller.enqueue(new Uint8Array(buf)); + } } return controller.desiredSize > 0 }, async cancel (reason) { await iterator.return(); - } - }, - 0 + }, + type: 'bytes' + } ) } @@ -1589,20 +2008,6 @@ function requireUtil$7 () { ) } - function throwIfAborted (signal) { - if (!signal) { return } - if (typeof signal.throwIfAborted === 'function') { - signal.throwIfAborted(); - } else { - if (signal.aborted) { - // DOMException not available < v17.0.0 - const err = new Error('The operation was aborted'); - err.name = 'AbortError'; - throw err - } - } - } - function addAbortListener (signal, listener) { if ('addEventListener' in signal) { signal.addEventListener('abort', listener, { once: true }); @@ -1612,19 +2017,86 @@ function requireUtil$7 () { return () => signal.removeListener('abort', listener) } - const hasToWellFormed = !!String.prototype.toWellFormed; + const hasToWellFormed = typeof String.prototype.toWellFormed === 'function'; + const hasIsWellFormed = typeof String.prototype.isWellFormed === 'function'; /** * @param {string} val */ function toUSVString (val) { - if (hasToWellFormed) { - return `${val}`.toWellFormed() - } else if (nodeUtil.toUSVString) { - return nodeUtil.toUSVString(val) + return hasToWellFormed ? `${val}`.toWellFormed() : nodeUtil.toUSVString(val) + } + + /** + * @param {string} val + */ + // TODO: move this to webidl + function isUSVString (val) { + return hasIsWellFormed ? `${val}`.isWellFormed() : toUSVString(val) === `${val}` + } + + /** + * @see https://tools.ietf.org/html/rfc7230#section-3.2.6 + * @param {number} c + */ + function isTokenCharCode (c) { + switch (c) { + case 0x22: + case 0x28: + case 0x29: + case 0x2c: + case 0x2f: + case 0x3a: + case 0x3b: + case 0x3c: + case 0x3d: + case 0x3e: + case 0x3f: + case 0x40: + case 0x5b: + case 0x5c: + case 0x5d: + case 0x7b: + case 0x7d: + // DQUOTE and "(),/:;<=>?@[\]{}" + return false + default: + // VCHAR %x21-7E + return c >= 0x21 && c <= 0x7e + } + } + + /** + * @param {string} characters + */ + 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 + } + + // headerCharRegex have been lifted from + // https://github.com/nodejs/node/blob/main/lib/_http_common.js + + /** + * Matches if val contains an invalid field-vchar + * field-value = *( field-content / obs-fold ) + * field-content = field-vchar [ 1*( SP / HTAB ) field-vchar ] + * field-vchar = VCHAR / obs-text + */ + const headerCharRegex = /[^\t\x20-\x7e\x80-\xff]/; - return `${val}` + /** + * @param {string} characters + */ + function isValidHeaderValue (characters) { + return !headerCharRegex.test(characters) } // Parsed accordingly to RFC 9110 @@ -1642,17 +2114,65 @@ function requireUtil$7 () { : 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 (err) { + client.emit('error', err); + } + } + const kEnumerableProperty = Object.create(null); kEnumerableProperty.enumerable = true; - util$7 = { + const 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' + }; + + const normalizedMethodRecords = { + ...normalizedMethodRecordsBase, + patch: 'patch', + PATCH: 'PATCH' + }; + + // Note: object prototypes should not be able to be referenced. e.g. `Object#hasOwnProperty`. + Object.setPrototypeOf(normalizedMethodRecordsBase, null); + Object.setPrototypeOf(normalizedMethodRecords, null); + + util$8 = { kEnumerableProperty, nop, isDisturbed, isErrored, isReadable, toUSVString, - isReadableAborted, + isUSVString, isBlobLike, parseOrigin, parseURL, @@ -1662,6 +2182,10 @@ function requireUtil$7 () { isAsyncIterable, isDestroyed, headerNameToString, + bufferToLowerCasedHeaderName, + addListener, + removeAllListeners, + errorRequest, parseRawHeaders, parseHeaders, parseKeepAliveTimeout, @@ -1674,2919 +2198,2859 @@ function requireUtil$7 () { getSocketInfo, isFormDataLike, buildURL, - throwIfAborted, addAbortListener, + isValidHTTPToken, + isValidHeaderValue, + isTokenCharCode, parseRangeHeader, + normalizedMethodRecordsBase, + normalizedMethodRecords, + isValidPort, + isHttpOrHttpsPrefixed, nodeMajor, nodeMinor, - nodeHasAutoSelectFamily: nodeMajor > 18 || (nodeMajor === 18 && nodeMinor >= 13), - safeHTTPMethods: ['GET', 'HEAD', 'OPTIONS', 'TRACE'] + safeHTTPMethods: ['GET', 'HEAD', 'OPTIONS', 'TRACE'], + wrapRequestBody + }; + return util$8; +} + +var diagnostics; +var hasRequiredDiagnostics; + +function requireDiagnostics () { + if (hasRequiredDiagnostics) return diagnostics; + hasRequiredDiagnostics = 1; + const diagnosticsChannel = require$$0$7; + const util = require$$0$6; + + const undiciDebugLog = util.debuglog('undici'); + const fetchDebuglog = util.debuglog('fetch'); + const websocketDebuglog = util.debuglog('websocket'); + let isClientSet = false; + const 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') }; - return util$7; -} -var timers; -var hasRequiredTimers; + if (undiciDebugLog.enabled || fetchDebuglog.enabled) { + const debuglog = fetchDebuglog.enabled ? fetchDebuglog : undiciDebugLog; -function requireTimers () { - if (hasRequiredTimers) return timers; - hasRequiredTimers = 1; + // Track all Client events + diagnosticsChannel.channel('undici:client:beforeConnect').subscribe(evt => { + const { + connectParams: { version, protocol, port, host } + } = evt; + debuglog( + 'connecting to %s using %s%s', + `${host}${port ? `:${port}` : ''}`, + protocol, + version + ); + }); - let fastNow = Date.now(); - let fastNowTimeout; + diagnosticsChannel.channel('undici:client:connected').subscribe(evt => { + const { + connectParams: { version, protocol, port, host } + } = evt; + debuglog( + 'connected to %s using %s%s', + `${host}${port ? `:${port}` : ''}`, + protocol, + version + ); + }); - const fastTimers = []; + diagnosticsChannel.channel('undici:client:connectError').subscribe(evt => { + const { + connectParams: { version, protocol, port, host }, + error + } = evt; + debuglog( + 'connection to %s using %s%s errored - %s', + `${host}${port ? `:${port}` : ''}`, + protocol, + version, + error.message + ); + }); - function onTimeout () { - fastNow = Date.now(); + diagnosticsChannel.channel('undici:client:sendHeaders').subscribe(evt => { + const { + request: { method, path, origin } + } = evt; + debuglog('sending request to %s %s/%s', method, origin, path); + }); - let len = fastTimers.length; - let idx = 0; - while (idx < len) { - const timer = fastTimers[idx]; + // Track Request events + diagnosticsChannel.channel('undici:request:headers').subscribe(evt => { + const { + request: { method, path, origin }, + response: { statusCode } + } = evt; + debuglog( + 'received response to %s %s/%s - HTTP %d', + method, + origin, + path, + statusCode + ); + }); - if (timer.state === 0) { - timer.state = fastNow + timer.delay; - } else if (timer.state > 0 && fastNow >= timer.state) { - timer.state = -1; - timer.callback(timer.opaque); - } + diagnosticsChannel.channel('undici:request:trailers').subscribe(evt => { + const { + request: { method, path, origin } + } = evt; + debuglog('trailers received from %s %s/%s', method, origin, path); + }); - if (timer.state === -1) { - timer.state = -2; - if (idx !== len - 1) { - fastTimers[idx] = fastTimers.pop(); - } else { - fastTimers.pop(); - } - len -= 1; - } else { - idx += 1; - } - } + diagnosticsChannel.channel('undici:request:error').subscribe(evt => { + const { + request: { method, path, origin }, + error + } = evt; + debuglog( + 'request to %s %s/%s errored - %s', + method, + origin, + path, + error.message + ); + }); - if (fastTimers.length > 0) { - refreshTimeout(); - } + isClientSet = true; } - function refreshTimeout () { - if (fastNowTimeout && fastNowTimeout.refresh) { - fastNowTimeout.refresh(); - } else { - clearTimeout(fastNowTimeout); - fastNowTimeout = setTimeout(onTimeout, 1e3); - if (fastNowTimeout.unref) { - fastNowTimeout.unref(); - } - } - } + if (websocketDebuglog.enabled) { + if (!isClientSet) { + const debuglog = undiciDebugLog.enabled ? undiciDebugLog : websocketDebuglog; + diagnosticsChannel.channel('undici:client:beforeConnect').subscribe(evt => { + const { + connectParams: { version, protocol, port, host } + } = evt; + debuglog( + 'connecting to %s%s using %s%s', + host, + port ? `:${port}` : '', + protocol, + version + ); + }); - class Timeout { - constructor (callback, delay, opaque) { - this.callback = callback; - this.delay = delay; - this.opaque = opaque; + diagnosticsChannel.channel('undici:client:connected').subscribe(evt => { + const { + connectParams: { version, protocol, port, host } + } = evt; + debuglog( + 'connected to %s%s using %s%s', + host, + port ? `:${port}` : '', + protocol, + version + ); + }); - // -2 not in timer list - // -1 in timer list but inactive - // 0 in timer list waiting for time - // > 0 in timer list waiting for time to expire - this.state = -2; + diagnosticsChannel.channel('undici:client:connectError').subscribe(evt => { + const { + connectParams: { version, protocol, port, host }, + error + } = evt; + debuglog( + 'connection to %s%s using %s%s errored - %s', + host, + port ? `:${port}` : '', + protocol, + version, + error.message + ); + }); - this.refresh(); + diagnosticsChannel.channel('undici:client:sendHeaders').subscribe(evt => { + const { + request: { method, path, origin } + } = evt; + debuglog('sending request to %s %s/%s', method, origin, path); + }); } - refresh () { - if (this.state === -2) { - fastTimers.push(this); - if (!fastNowTimeout || fastTimers.length === 1) { - refreshTimeout(); - } - } + // Track all WebSocket events + diagnosticsChannel.channel('undici:websocket:open').subscribe(evt => { + const { + address: { address, port } + } = evt; + websocketDebuglog('connection opened %s%s', address, port ? `:${port}` : ''); + }); - this.state = 0; - } + diagnosticsChannel.channel('undici:websocket:close').subscribe(evt => { + const { websocket, code, reason } = evt; + websocketDebuglog( + 'closed connection to %s - %s %s', + websocket.url, + code, + reason + ); + }); - clear () { - this.state = -1; - } + 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'); + }); } - timers = { - setTimeout (callback, delay, opaque) { - return delay < 1e3 - ? setTimeout(callback, delay, opaque) - : new Timeout(callback, delay, opaque) - }, - clearTimeout (timeout) { - if (timeout instanceof Timeout) { - timeout.clear(); - } else { - clearTimeout(timeout); - } - } + diagnostics = { + channels }; - return timers; + return diagnostics; } -var main = {exports: {}}; - -var sbmh; -var hasRequiredSbmh; +var request$2; +var hasRequiredRequest$1; -function requireSbmh () { - if (hasRequiredSbmh) return sbmh; - hasRequiredSbmh = 1; +function requireRequest$1 () { + if (hasRequiredRequest$1) return request$2; + hasRequiredRequest$1 = 1; - /** - * Copyright Brian White. All rights reserved. - * - * @see https://github.com/mscdex/streamsearch - * - * 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. - * - * Based heavily on the Streaming Boyer-Moore-Horspool C++ implementation - * by Hongli Lai at: https://github.com/FooBarWidget/boyer-moore-horspool - */ - const EventEmitter = require$$0$6.EventEmitter; - const inherits = require$$1$2.inherits; + const { + InvalidArgumentError, + NotSupportedError + } = requireErrors(); + const assert = require$$0$3; + const { + isValidHTTPToken, + isValidHeaderValue, + isStream, + destroy, + isBuffer, + isFormDataLike, + isIterable, + isBlobLike, + buildURL, + validateHandler, + getServerName, + normalizedMethodRecords + } = requireUtil$8(); + const { channels } = requireDiagnostics(); + const { headerNameLowerCasedRecord } = requireConstants$4(); - function SBMH (needle) { - if (typeof needle === 'string') { - needle = Buffer.from(needle); - } + // Verifies that a given path is valid does not contain control chars \x00 to \x20 + const invalidPathRegex = /[^\u0021-\u00ff]/; - if (!Buffer.isBuffer(needle)) { - throw new TypeError('The needle has to be a String or a Buffer.') - } + const kHandler = Symbol('handler'); - const needleLength = needle.length; + class Request { + constructor (origin, { + path, + method, + body, + headers, + query, + idempotent, + blocking, + upgrade, + headersTimeout, + bodyTimeout, + reset, + throwOnError, + expectContinue, + servername + }, handler) { + if (typeof path !== 'string') { + throw new InvalidArgumentError('path must be a string') + } else if ( + path[0] !== '/' && + !(path.startsWith('http://') || path.startsWith('https://')) && + method !== 'CONNECT' + ) { + throw new InvalidArgumentError('path must be an absolute URL or start with a slash') + } else if (invalidPathRegex.test(path)) { + throw new InvalidArgumentError('invalid request path') + } - if (needleLength === 0) { - throw new Error('The needle cannot be an empty String/Buffer.') - } + if (typeof method !== 'string') { + throw new InvalidArgumentError('method must be a string') + } else if (normalizedMethodRecords[method] === undefined && !isValidHTTPToken(method)) { + throw new InvalidArgumentError('invalid request method') + } - if (needleLength > 256) { - throw new Error('The needle cannot have a length bigger than 256.') - } + if (upgrade && typeof upgrade !== 'string') { + throw new InvalidArgumentError('upgrade must be a string') + } - this.maxMatches = Infinity; - this.matches = 0; + if (upgrade && !isValidHeaderValue(upgrade)) { + throw new InvalidArgumentError('invalid upgrade header') + } - this._occ = new Array(256) - .fill(needleLength); // Initialize occurrence table. - this._lookbehind_size = 0; - this._needle = needle; - this._bufpos = 0; + if (headersTimeout != null && (!Number.isFinite(headersTimeout) || headersTimeout < 0)) { + throw new InvalidArgumentError('invalid headersTimeout') + } - this._lookbehind = Buffer.alloc(needleLength); + if (bodyTimeout != null && (!Number.isFinite(bodyTimeout) || bodyTimeout < 0)) { + throw new InvalidArgumentError('invalid bodyTimeout') + } - // Populate occurrence table with analysis of the needle, - // ignoring last letter. - for (var i = 0; i < needleLength - 1; ++i) { // eslint-disable-line no-var - this._occ[needle[i]] = needleLength - 1 - i; - } - } - inherits(SBMH, EventEmitter); + if (reset != null && typeof reset !== 'boolean') { + throw new InvalidArgumentError('invalid reset') + } - SBMH.prototype.reset = function () { - this._lookbehind_size = 0; - this.matches = 0; - this._bufpos = 0; - }; + if (expectContinue != null && typeof expectContinue !== 'boolean') { + throw new InvalidArgumentError('invalid expectContinue') + } - SBMH.prototype.push = function (chunk, pos) { - if (!Buffer.isBuffer(chunk)) { - chunk = Buffer.from(chunk, 'binary'); - } - const chlen = chunk.length; - this._bufpos = pos || 0; - let r; - while (r !== chlen && this.matches < this.maxMatches) { r = this._sbmh_feed(chunk); } - return r - }; + this.headersTimeout = headersTimeout; - SBMH.prototype._sbmh_feed = function (data) { - const len = data.length; - const needle = this._needle; - const needleLength = needle.length; - const lastNeedleChar = needle[needleLength - 1]; - - // Positive: points to a position in `data` - // pos == 3 points to data[3] - // Negative: points to a position in the lookbehind buffer - // pos == -2 points to lookbehind[lookbehind_size - 2] - let pos = -this._lookbehind_size; - let ch; - - if (pos < 0) { - // Lookbehind buffer is not empty. Perform Boyer-Moore-Horspool - // search with character lookup code that considers both the - // lookbehind buffer and the current round's haystack data. - // - // Loop until - // there is a match. - // or until - // we've moved past the position that requires the - // lookbehind buffer. In this case we switch to the - // optimized loop. - // or until - // the character to look at lies outside the haystack. - while (pos < 0 && pos <= len - needleLength) { - ch = this._sbmh_lookup_char(data, pos + needleLength - 1); + this.bodyTimeout = bodyTimeout; - if ( - ch === lastNeedleChar && - this._sbmh_memcmp(data, pos, needleLength - 1) - ) { - this._lookbehind_size = 0; - ++this.matches; - this.emit('info', true); + this.throwOnError = throwOnError === true; - return (this._bufpos = pos + needleLength) - } - pos += this._occ[ch]; - } + this.method = method; - // No match. + this.abort = null; - if (pos < 0) { - // There's too few data for Boyer-Moore-Horspool to run, - // so let's use a different algorithm to skip as much as - // we can. - // Forward pos until - // the trailing part of lookbehind + data - // looks like the beginning of the needle - // or until - // pos == 0 - while (pos < 0 && !this._sbmh_memcmp(data, pos, len - pos)) { ++pos; } - } + if (body == null) { + this.body = null; + } else if (isStream(body)) { + this.body = body; - if (pos >= 0) { - // Discard lookbehind buffer. - this.emit('info', false, this._lookbehind, 0, this._lookbehind_size); - this._lookbehind_size = 0; - } else { - // Cut off part of the lookbehind buffer that has - // been processed and append the entire haystack - // into it. - const bytesToCutOff = this._lookbehind_size + pos; - if (bytesToCutOff > 0) { - // The cut off data is guaranteed not to contain the needle. - this.emit('info', false, this._lookbehind, 0, bytesToCutOff); + const rState = this.body._readableState; + if (!rState || !rState.autoDestroy) { + this.endHandler = function autoDestroy () { + destroy(this); + }; + this.body.on('end', this.endHandler); } - this._lookbehind.copy(this._lookbehind, 0, bytesToCutOff, - this._lookbehind_size - bytesToCutOff); - this._lookbehind_size -= bytesToCutOff; + this.errorHandler = err => { + if (this.abort) { + this.abort(err); + } else { + this.error = err; + } + }; + this.body.on('error', this.errorHandler); + } else if (isBuffer(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') + } - data.copy(this._lookbehind, this._lookbehind_size); - this._lookbehind_size += len; + this.completed = false; - this._bufpos = len; - return len - } - } + this.aborted = false; - pos += (pos >= 0) * this._bufpos; + this.upgrade = upgrade || null; - // Lookbehind buffer is now empty. We only need to check if the - // needle is in the haystack. - if (data.indexOf(needle, pos) !== -1) { - pos = data.indexOf(needle, pos); - ++this.matches; - if (pos > 0) { this.emit('info', true, data, this._bufpos, pos); } else { this.emit('info', true); } + this.path = query ? buildURL(path, query) : path; - return (this._bufpos = pos + needleLength) - } else { - pos = len - needleLength; - } + this.origin = origin; - // There was no match. If there's trailing haystack data that we cannot - // match yet using the Boyer-Moore-Horspool algorithm (because the trailing - // data is less than the needle size) then match using a modified - // algorithm that starts matching from the beginning instead of the end. - // Whatever trailing data is left after running this algorithm is added to - // the lookbehind buffer. - while ( - pos < len && - ( - data[pos] !== needle[0] || - ( - (Buffer.compare( - data.subarray(pos, pos + len - pos), - needle.subarray(0, len - pos) - ) !== 0) - ) - ) - ) { - ++pos; - } - if (pos < len) { - data.copy(this._lookbehind, 0, pos, pos + (len - pos)); - this._lookbehind_size = len - pos; - } + this.idempotent = idempotent == null + ? method === 'HEAD' || method === 'GET' + : idempotent; - // Everything until pos is guaranteed not to contain needle data. - if (pos > 0) { this.emit('info', false, data, this._bufpos, pos < len ? pos : len); } + this.blocking = blocking == null ? false : blocking; - this._bufpos = len; - return len - }; + this.reset = reset == null ? null : reset; - SBMH.prototype._sbmh_lookup_char = function (data, pos) { - return (pos < 0) - ? this._lookbehind[this._lookbehind_size + pos] - : data[pos] - }; + this.host = null; - SBMH.prototype._sbmh_memcmp = function (data, pos, len) { - for (var i = 0; i < len; ++i) { // eslint-disable-line no-var - if (this._sbmh_lookup_char(data, pos + i) !== this._needle[i]) { return false } - } - return true - }; + this.contentLength = null; - sbmh = SBMH; - return sbmh; -} + this.contentType = null; -var PartStream_1; -var hasRequiredPartStream; + this.headers = []; -function requirePartStream () { - if (hasRequiredPartStream) return PartStream_1; - hasRequiredPartStream = 1; + // Only for H2 + this.expectContinue = expectContinue != null ? expectContinue : false; - const inherits = require$$1$2.inherits; - const ReadableStream = require$$0$7.Readable; + 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') + } - function PartStream (opts) { - ReadableStream.call(this, opts); - } - inherits(PartStream, ReadableStream); + validateHandler(handler, method, upgrade); - PartStream.prototype._read = function (n) {}; + this.servername = servername || getServerName(this.host); - PartStream_1 = PartStream; - return PartStream_1; -} + this[kHandler] = handler; -var getLimit; -var hasRequiredGetLimit; + if (channels.create.hasSubscribers) { + channels.create.publish({ request: this }); + } + } -function requireGetLimit () { - if (hasRequiredGetLimit) return getLimit; - hasRequiredGetLimit = 1; + onBodySent (chunk) { + if (this[kHandler].onBodySent) { + try { + return this[kHandler].onBodySent(chunk) + } catch (err) { + this.abort(err); + } + } + } - getLimit = function getLimit (limits, name, defaultLimit) { - if ( - !limits || - limits[name] === undefined || - limits[name] === null - ) { return defaultLimit } + onRequestSent () { + if (channels.bodySent.hasSubscribers) { + channels.bodySent.publish({ request: this }); + } - if ( - typeof limits[name] !== 'number' || - isNaN(limits[name]) - ) { throw new TypeError('Limit ' + name + ' is not a valid number') } + if (this[kHandler].onRequestSent) { + try { + return this[kHandler].onRequestSent() + } catch (err) { + this.abort(err); + } + } + } - return limits[name] - }; - return getLimit; -} - -var HeaderParser_1; -var hasRequiredHeaderParser; - -function requireHeaderParser () { - if (hasRequiredHeaderParser) return HeaderParser_1; - hasRequiredHeaderParser = 1; - - const EventEmitter = require$$0$6.EventEmitter; - const inherits = require$$1$2.inherits; - const getLimit = requireGetLimit(); - - const StreamSearch = requireSbmh(); - - const B_DCRLF = Buffer.from('\r\n\r\n'); - const RE_CRLF = /\r\n/g; - const RE_HDR = /^([^:]+):[ \t]?([\x00-\xFF]+)?$/; // eslint-disable-line no-control-regex - - function HeaderParser (cfg) { - EventEmitter.call(this); - - cfg = cfg || {}; - const self = this; - this.nread = 0; - this.maxed = false; - this.npairs = 0; - this.maxHeaderPairs = getLimit(cfg, 'maxHeaderPairs', 2000); - this.maxHeaderSize = getLimit(cfg, 'maxHeaderSize', 80 * 1024); - this.buffer = ''; - this.header = {}; - this.finished = false; - this.ss = new StreamSearch(B_DCRLF); - this.ss.on('info', function (isMatch, data, start, end) { - if (data && !self.maxed) { - if (self.nread + end - start >= self.maxHeaderSize) { - end = self.maxHeaderSize - self.nread + start; - self.nread = self.maxHeaderSize; - self.maxed = true; - } else { self.nread += (end - start); } - - self.buffer += data.toString('binary', start, end); - } - if (isMatch) { self._finish(); } - }); - } - inherits(HeaderParser, EventEmitter); + onConnect (abort) { + assert(!this.aborted); + assert(!this.completed); - HeaderParser.prototype.push = function (data) { - const r = this.ss.push(data); - if (this.finished) { return r } - }; + if (this.error) { + abort(this.error); + } else { + this.abort = abort; + return this[kHandler].onConnect(abort) + } + } - HeaderParser.prototype.reset = function () { - this.finished = false; - this.buffer = ''; - this.header = {}; - this.ss.reset(); - }; + onResponseStarted () { + return this[kHandler].onResponseStarted?.() + } - HeaderParser.prototype._finish = function () { - if (this.buffer) { this._parseHeader(); } - this.ss.matches = this.ss.maxMatches; - const header = this.header; - this.header = {}; - this.buffer = ''; - this.finished = true; - this.nread = this.npairs = 0; - this.maxed = false; - this.emit('header', header); - }; + onHeaders (statusCode, headers, resume, statusText) { + assert(!this.aborted); + assert(!this.completed); - HeaderParser.prototype._parseHeader = function () { - if (this.npairs === this.maxHeaderPairs) { return } - - const lines = this.buffer.split(RE_CRLF); - const len = lines.length; - let m, h; - - for (var i = 0; i < len; ++i) { // eslint-disable-line no-var - if (lines[i].length === 0) { continue } - if (lines[i][0] === '\t' || lines[i][0] === ' ') { - // folded header content - // RFC2822 says to just remove the CRLF and not the whitespace following - // it, so we follow the RFC and include the leading whitespace ... - if (h) { - this.header[h][this.header[h].length - 1] += lines[i]; - continue - } + if (channels.headers.hasSubscribers) { + channels.headers.publish({ request: this, response: { statusCode, headers, statusText } }); } - const posColon = lines[i].indexOf(':'); - if ( - posColon === -1 || - posColon === 0 - ) { - return + try { + return this[kHandler].onHeaders(statusCode, headers, resume, statusText) + } catch (err) { + this.abort(err); } - m = RE_HDR.exec(lines[i]); - h = m[1].toLowerCase(); - this.header[h] = this.header[h] || []; - this.header[h].push((m[2] || '')); - if (++this.npairs === this.maxHeaderPairs) { break } } - }; - HeaderParser_1 = HeaderParser; - return HeaderParser_1; -} + onData (chunk) { + assert(!this.aborted); + assert(!this.completed); -var Dicer_1; -var hasRequiredDicer; + try { + return this[kHandler].onData(chunk) + } catch (err) { + this.abort(err); + return false + } + } -function requireDicer () { - if (hasRequiredDicer) return Dicer_1; - hasRequiredDicer = 1; + onUpgrade (statusCode, headers, socket) { + assert(!this.aborted); + assert(!this.completed); - const WritableStream = require$$0$7.Writable; - const inherits = require$$1$2.inherits; + return this[kHandler].onUpgrade(statusCode, headers, socket) + } - const StreamSearch = requireSbmh(); + onComplete (trailers) { + this.onFinally(); - const PartStream = requirePartStream(); - const HeaderParser = requireHeaderParser(); + assert(!this.aborted); - const DASH = 45; - const B_ONEDASH = Buffer.from('-'); - const B_CRLF = Buffer.from('\r\n'); - const EMPTY_FN = function () {}; + this.completed = true; + if (channels.trailers.hasSubscribers) { + channels.trailers.publish({ request: this, trailers }); + } - function Dicer (cfg) { - if (!(this instanceof Dicer)) { return new Dicer(cfg) } - WritableStream.call(this, cfg); + try { + return this[kHandler].onComplete(trailers) + } catch (err) { + // TODO (fix): This might be a bad idea? + this.onError(err); + } + } - if (!cfg || (!cfg.headerFirst && typeof cfg.boundary !== 'string')) { throw new TypeError('Boundary required') } + onError (error) { + this.onFinally(); - if (typeof cfg.boundary === 'string') { this.setBoundary(cfg.boundary); } else { this._bparser = undefined; } + if (channels.error.hasSubscribers) { + channels.error.publish({ request: this, error }); + } - this._headerFirst = cfg.headerFirst; + if (this.aborted) { + return + } + this.aborted = true; - this._dashes = 0; - this._parts = 0; - this._finished = false; - this._realFinish = false; - this._isPreamble = true; - this._justMatched = false; - this._firstWrite = true; - this._inHeader = true; - this._part = undefined; - this._cb = undefined; - this._ignoreData = false; - this._partOpts = { highWaterMark: cfg.partHwm }; - this._pause = false; + return this[kHandler].onError(error) + } - const self = this; - this._hparser = new HeaderParser(cfg); - this._hparser.on('header', function (header) { - self._inHeader = false; - self._part.emit('header', header); - }); - } - inherits(Dicer, WritableStream); - - Dicer.prototype.emit = function (ev) { - if (ev === 'finish' && !this._realFinish) { - if (!this._finished) { - const self = this; - process.nextTick(function () { - self.emit('error', new Error('Unexpected end of multipart data')); - if (self._part && !self._ignoreData) { - const type = (self._isPreamble ? 'Preamble' : 'Part'); - self._part.emit('error', new Error(type + ' terminated early due to unexpected end of multipart data')); - self._part.push(null); - process.nextTick(function () { - self._realFinish = true; - self.emit('finish'); - self._realFinish = false; - }); - return - } - self._realFinish = true; - self.emit('finish'); - self._realFinish = false; - }); + onFinally () { + if (this.errorHandler) { + this.body.off('error', this.errorHandler); + this.errorHandler = null; } - } else { WritableStream.prototype.emit.apply(this, arguments); } - }; - Dicer.prototype._write = function (data, encoding, cb) { - // ignore unexpected data (e.g. extra trailer data after finished) - if (!this._hparser && !this._bparser) { return cb() } - - if (this._headerFirst && this._isPreamble) { - if (!this._part) { - this._part = new PartStream(this._partOpts); - if (this._events.preamble) { this.emit('preamble', this._part); } else { this._ignore(); } + if (this.endHandler) { + this.body.off('end', this.endHandler); + this.endHandler = null; } - const r = this._hparser.push(data); - if (!this._inHeader && r !== undefined && r < data.length) { data = data.slice(r); } else { return cb() } } - // allows for "easier" testing - if (this._firstWrite) { - this._bparser.push(B_CRLF); - this._firstWrite = false; + addHeader (key, value) { + processHeader(this, key, value); + return this } + } - this._bparser.push(data); + function processHeader (request, key, val) { + if (val && (typeof val === 'object' && !Array.isArray(val))) { + throw new InvalidArgumentError(`invalid ${key} header`) + } else if (val === undefined) { + return + } - if (this._pause) { this._cb = cb; } else { cb(); } - }; + let headerName = headerNameLowerCasedRecord[key]; - Dicer.prototype.reset = function () { - this._part = undefined; - this._bparser = undefined; - this._hparser = undefined; - }; - - Dicer.prototype.setBoundary = function (boundary) { - const self = this; - this._bparser = new StreamSearch('\r\n--' + boundary); - this._bparser.on('info', function (isMatch, data, start, end) { - self._oninfo(isMatch, data, start, end); - }); - }; - - Dicer.prototype._ignore = function () { - if (this._part && !this._ignoreData) { - this._ignoreData = true; - this._part.on('error', EMPTY_FN); - // we must perform some kind of read on the stream even though we are - // ignoring the data, otherwise node's Readable stream will not emit 'end' - // after pushing null to the stream - this._part.resume(); + if (headerName === undefined) { + headerName = key.toLowerCase(); + if (headerNameLowerCasedRecord[headerName] === undefined && !isValidHTTPToken(headerName)) { + throw new InvalidArgumentError('invalid header key') + } } - }; - - Dicer.prototype._oninfo = function (isMatch, data, start, end) { - let buf; const self = this; let i = 0; let r; let shouldWriteMore = true; - if (!this._part && this._justMatched && data) { - while (this._dashes < 2 && (start + i) < end) { - if (data[start + i] === DASH) { - ++i; - ++this._dashes; + 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 { - if (this._dashes) { buf = B_ONEDASH; } - this._dashes = 0; - break - } - } - if (this._dashes === 2) { - if ((start + i) < end && this._events.trailer) { this.emit('trailer', data.slice(start + i, end)); } - this.reset(); - this._finished = true; - // no more parts will be added - if (self._parts === 0) { - self._realFinish = true; - self.emit('finish'); - self._realFinish = false; + arr.push(`${val[i]}`); } } - if (this._dashes) { return } - } - if (this._justMatched) { this._justMatched = false; } - if (!this._part) { - this._part = new PartStream(this._partOpts); - this._part._read = function (n) { - self._unpause(); - }; - if (this._isPreamble && this._events.preamble) { this.emit('preamble', this._part); } else if (this._isPreamble !== true && this._events.part) { this.emit('part', this._part); } else { this._ignore(); } - if (!this._isPreamble) { this._inHeader = true; } - } - if (data && start < end && !this._ignoreData) { - if (this._isPreamble || !this._inHeader) { - if (buf) { shouldWriteMore = this._part.push(buf); } - shouldWriteMore = this._part.push(data.slice(start, end)); - if (!shouldWriteMore) { this._pause = true; } - } else if (!this._isPreamble && this._inHeader) { - if (buf) { this._hparser.push(buf); } - r = this._hparser.push(data.slice(start, end)); - if (!this._inHeader && r !== undefined && r < end) { this._oninfo(false, data, start + r, end); } - } - } - if (isMatch) { - this._hparser.reset(); - if (this._isPreamble) { this._isPreamble = false; } else { - if (start !== end) { - ++this._parts; - this._part.on('end', function () { - if (--self._parts === 0) { - if (self._finished) { - self._realFinish = true; - self.emit('finish'); - self._realFinish = false; - } else { - self._unpause(); - } - } - }); - } + val = arr; + } else if (typeof val === 'string') { + if (!isValidHeaderValue(val)) { + throw new InvalidArgumentError(`invalid ${key} header`) } - this._part.push(null); - this._part = undefined; - this._ignoreData = false; - this._justMatched = true; - this._dashes = 0; + } else if (val === null) { + val = ''; + } else { + val = `${val}`; } - }; - Dicer.prototype._unpause = function () { - if (!this._pause) { return } + if (headerName === 'host') { + if (request.host !== null) { + throw new InvalidArgumentError('duplicate host header') + } + if (typeof val !== 'string') { + throw new InvalidArgumentError('invalid host header') + } + // Consumed by Client + 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') + } - this._pause = false; - if (this._cb) { - const cb = this._cb; - this._cb = undefined; - cb(); + if (value === 'close') { + request.reset = true; + } + } else if (headerName === 'expect') { + throw new NotSupportedError('expect header not supported') + } else { + request.headers.push(key, val); } - }; + } - Dicer_1 = Dicer; - return Dicer_1; + request$2 = Request; + return request$2; } -var decodeText_1; -var hasRequiredDecodeText; +var dispatcher; +var hasRequiredDispatcher; -function requireDecodeText () { - if (hasRequiredDecodeText) return decodeText_1; - hasRequiredDecodeText = 1; +function requireDispatcher () { + if (hasRequiredDispatcher) return dispatcher; + hasRequiredDispatcher = 1; + const EventEmitter = require$$8; - // Node has always utf-8 - const utf8Decoder = new TextDecoder('utf-8'); - const textDecoders = new Map([ - ['utf-8', utf8Decoder], - ['utf8', utf8Decoder] - ]); + class Dispatcher extends EventEmitter { + dispatch () { + throw new Error('not implemented') + } - function decodeText (text, textEncoding, destEncoding) { - if (text) { - if (textDecoders.has(destEncoding)) { - try { - return textDecoders.get(destEncoding).decode(Buffer.from(text, textEncoding)) - } catch (e) { } - } else { - try { - textDecoders.set(destEncoding, new TextDecoder(destEncoding)); - return textDecoders.get(destEncoding).decode(Buffer.from(text, textEncoding)) - } catch (e) { } - } + close () { + throw new Error('not implemented') } - return text - } - decodeText_1 = decodeText; - return decodeText_1; -} + destroy () { + throw new Error('not implemented') + } + + compose (...args) { + // So we handle [interceptor1, interceptor2] or interceptor1, interceptor2, ... + const interceptors = Array.isArray(args[0]) ? args[0] : args; + let dispatch = this.dispatch.bind(this); -var parseParams_1; -var hasRequiredParseParams; + for (const interceptor of interceptors) { + if (interceptor == null) { + continue + } -function requireParseParams () { - if (hasRequiredParseParams) return parseParams_1; - hasRequiredParseParams = 1; + if (typeof interceptor !== 'function') { + throw new TypeError(`invalid interceptor, expected function received ${typeof interceptor}`) + } - const decodeText = requireDecodeText(); + dispatch = interceptor(dispatch); - const RE_ENCODED = /%([a-fA-F0-9]{2})/g; + if (dispatch == null || typeof dispatch !== 'function' || dispatch.length !== 2) { + throw new TypeError('invalid interceptor') + } + } - function encodedReplacer (match, byte) { - return String.fromCharCode(parseInt(byte, 16)) + return new ComposedDispatcher(this, dispatch) + } } - function parseParams (str) { - const res = []; - let state = 'key'; - let charset = ''; - let inquote = false; - let escaping = false; - let p = 0; - let tmp = ''; + class ComposedDispatcher extends Dispatcher { + #dispatcher = null + #dispatch = null - for (var i = 0, len = str.length; i < len; ++i) { // eslint-disable-line no-var - const char = str[i]; - if (char === '\\' && inquote) { - if (escaping) { escaping = false; } else { - escaping = true; - continue - } - } else if (char === '"') { - if (!escaping) { - if (inquote) { - inquote = false; - state = 'key'; - } else { inquote = true; } - continue - } else { escaping = false; } - } else { - if (escaping && inquote) { tmp += '\\'; } - escaping = false; - if ((state === 'charset' || state === 'lang') && char === "'") { - if (state === 'charset') { - state = 'lang'; - charset = tmp.substring(1); - } else { state = 'value'; } - tmp = ''; - continue - } else if (state === 'key' && - (char === '*' || char === '=') && - res.length) { - if (char === '*') { state = 'charset'; } else { state = 'value'; } - res[p] = [tmp, undefined]; - tmp = ''; - continue - } else if (!inquote && char === ';') { - state = 'key'; - if (charset) { - if (tmp.length) { - tmp = decodeText(tmp.replace(RE_ENCODED, encodedReplacer), - 'binary', - charset); - } - charset = ''; - } else if (tmp.length) { - tmp = decodeText(tmp, 'binary', 'utf8'); - } - if (res[p] === undefined) { res[p] = tmp; } else { res[p][1] = tmp; } - tmp = ''; - ++p; - continue - } else if (!inquote && (char === ' ' || char === '\t')) { continue } - } - tmp += char; + constructor (dispatcher, dispatch) { + super(); + this.#dispatcher = dispatcher; + this.#dispatch = dispatch; } - if (charset && tmp.length) { - tmp = decodeText(tmp.replace(RE_ENCODED, encodedReplacer), - 'binary', - charset); - } else if (tmp) { - tmp = decodeText(tmp, 'binary', 'utf8'); + + dispatch (...args) { + this.#dispatch(...args); } - if (res[p] === undefined) { - if (tmp) { res[p] = tmp; } - } else { res[p][1] = tmp; } + close (...args) { + return this.#dispatcher.close(...args) + } - return res + destroy (...args) { + return this.#dispatcher.destroy(...args) + } } - parseParams_1 = parseParams; - return parseParams_1; + dispatcher = Dispatcher; + return dispatcher; } -var basename; -var hasRequiredBasename; +var dispatcherBase; +var hasRequiredDispatcherBase; -function requireBasename () { - if (hasRequiredBasename) return basename; - hasRequiredBasename = 1; +function requireDispatcherBase () { + if (hasRequiredDispatcherBase) return dispatcherBase; + hasRequiredDispatcherBase = 1; - basename = function basename (path) { - if (typeof path !== 'string') { return '' } - for (var i = path.length - 1; i >= 0; --i) { // eslint-disable-line no-var - switch (path.charCodeAt(i)) { - case 0x2F: // '/' - case 0x5C: // '\' - path = path.slice(i + 1); - return (path === '..' || path === '.' ? '' : path) - } - } - return (path === '..' || path === '.' ? '' : path) - }; - return basename; -} - -var multipart; -var hasRequiredMultipart; - -function requireMultipart () { - if (hasRequiredMultipart) return multipart; - hasRequiredMultipart = 1; - - // TODO: - // * support 1 nested multipart level - // (see second multipart example here: - // http://www.w3.org/TR/html401/interact/forms.html#didx-multipartform-data) - // * support limits.fieldNameSize - // -- this will require modifications to utils.parseParams - - const { Readable } = require$$0$7; - const { inherits } = require$$1$2; - - const Dicer = requireDicer(); - - const parseParams = requireParseParams(); - const decodeText = requireDecodeText(); - const basename = requireBasename(); - const getLimit = requireGetLimit(); - - const RE_BOUNDARY = /^boundary$/i; - const RE_FIELD = /^form-data$/i; - const RE_CHARSET = /^charset$/i; - const RE_FILENAME = /^filename$/i; - const RE_NAME = /^name$/i; - - Multipart.detect = /^multipart\/form-data/i; - function Multipart (boy, cfg) { - let i; - let len; - const self = this; - let boundary; - const limits = cfg.limits; - const isPartAFile = cfg.isPartAFile || ((fieldName, contentType, fileName) => (contentType === 'application/octet-stream' || fileName !== undefined)); - const parsedConType = cfg.parsedConType || []; - const defCharset = cfg.defCharset || 'utf8'; - const preservePath = cfg.preservePath; - const fileOpts = { highWaterMark: cfg.fileHwm }; - - for (i = 0, len = parsedConType.length; i < len; ++i) { - if (Array.isArray(parsedConType[i]) && - RE_BOUNDARY.test(parsedConType[i][0])) { - boundary = parsedConType[i][1]; - break - } + const Dispatcher = requireDispatcher(); + const { + ClientDestroyedError, + ClientClosedError, + InvalidArgumentError + } = requireErrors(); + const { kDestroy, kClose, kClosed, kDestroyed, kDispatch, kInterceptors } = requireSymbols$4(); + + const kOnDestroyed = Symbol('onDestroyed'); + const kOnClosed = Symbol('onClosed'); + const kInterceptedDispatch = Symbol('Intercepted Dispatch'); + + class DispatcherBase extends Dispatcher { + constructor () { + super(); + + this[kDestroyed] = false; + this[kOnDestroyed] = null; + this[kClosed] = false; + this[kOnClosed] = []; } - function checkFinished () { - if (nends === 0 && finished && !boy._done) { - finished = false; - self.end(); - } + get destroyed () { + return this[kDestroyed] } - if (typeof boundary !== 'string') { throw new Error('Multipart: Boundary not found') } + get closed () { + return this[kClosed] + } - const fieldSizeLimit = getLimit(limits, 'fieldSize', 1 * 1024 * 1024); - const fileSizeLimit = getLimit(limits, 'fileSize', Infinity); - const filesLimit = getLimit(limits, 'files', Infinity); - const fieldsLimit = getLimit(limits, 'fields', Infinity); - const partsLimit = getLimit(limits, 'parts', Infinity); - const headerPairsLimit = getLimit(limits, 'headerPairs', 2000); - const headerSizeLimit = getLimit(limits, 'headerSize', 80 * 1024); + get interceptors () { + return this[kInterceptors] + } - let nfiles = 0; - let nfields = 0; - let nends = 0; - let curFile; - let curField; - let finished = false; + 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._needDrain = false; - this._pause = false; - this._cb = undefined; - this._nparts = 0; - this._boy = boy; - - const parserCfg = { - boundary, - maxHeaderPairs: headerPairsLimit, - maxHeaderSize: headerSizeLimit, - partHwm: fileOpts.highWaterMark, - highWaterMark: cfg.highWaterMark - }; + this[kInterceptors] = newInterceptors; + } - this.parser = new Dicer(parserCfg); - this.parser.on('drain', function () { - self._needDrain = false; - if (self._cb && !self._pause) { - const cb = self._cb; - self._cb = undefined; - cb(); + close (callback) { + if (callback === undefined) { + return new Promise((resolve, reject) => { + this.close((err, data) => { + return err ? reject(err) : resolve(data) + }); + }) } - }).on('part', function onPart (part) { - if (++self._nparts > partsLimit) { - self.parser.removeListener('part', onPart); - self.parser.on('part', skipPart); - boy.hitPartsLimit = true; - boy.emit('partsLimit'); - return skipPart(part) - } - - // hack because streams2 _always_ doesn't emit 'end' until nextTick, so let - // us emit 'end' early since we know the part has ended if we are already - // seeing the next part - if (curField) { - const field = curField; - field.emit('end'); - field.removeAllListeners('end'); - } - - part.on('header', function (header) { - let contype; - let fieldname; - let parsed; - let charset; - let encoding; - let filename; - let nsize = 0; - - if (header['content-type']) { - parsed = parseParams(header['content-type'][0]); - if (parsed[0]) { - contype = parsed[0].toLowerCase(); - for (i = 0, len = parsed.length; i < len; ++i) { - if (RE_CHARSET.test(parsed[i][0])) { - charset = parsed[i][1].toLowerCase(); - break - } - } - } - } - if (contype === undefined) { contype = 'text/plain'; } - if (charset === undefined) { charset = defCharset; } + if (typeof callback !== 'function') { + throw new InvalidArgumentError('invalid callback') + } - if (header['content-disposition']) { - parsed = parseParams(header['content-disposition'][0]); - if (!RE_FIELD.test(parsed[0])) { return skipPart(part) } - for (i = 0, len = parsed.length; i < len; ++i) { - if (RE_NAME.test(parsed[i][0])) { - fieldname = parsed[i][1]; - } else if (RE_FILENAME.test(parsed[i][0])) { - filename = parsed[i][1]; - if (!preservePath) { filename = basename(filename); } - } - } - } else { return skipPart(part) } + if (this[kDestroyed]) { + queueMicrotask(() => callback(new ClientDestroyedError(), null)); + return + } - if (header['content-transfer-encoding']) { encoding = header['content-transfer-encoding'][0].toLowerCase(); } else { encoding = '7bit'; } + if (this[kClosed]) { + if (this[kOnClosed]) { + this[kOnClosed].push(callback); + } else { + queueMicrotask(() => callback(null, null)); + } + return + } - let onData, - onEnd; + this[kClosed] = true; + this[kOnClosed].push(callback); - if (isPartAFile(fieldname, contype, filename)) { - // file/binary field - if (nfiles === filesLimit) { - if (!boy.hitFilesLimit) { - boy.hitFilesLimit = true; - boy.emit('filesLimit'); - } - return skipPart(part) - } + const onClosed = () => { + const callbacks = this[kOnClosed]; + this[kOnClosed] = null; + for (let i = 0; i < callbacks.length; i++) { + callbacks[i](null, null); + } + }; - ++nfiles; + // Should not error. + this[kClose]() + .then(() => this.destroy()) + .then(() => { + queueMicrotask(onClosed); + }); + } - if (!boy._events.file) { - self.parser._ignore(); - return - } + destroy (err, callback) { + if (typeof err === 'function') { + callback = err; + err = null; + } - ++nends; - const file = new FileStream(fileOpts); - curFile = file; - file.on('end', function () { - --nends; - self._pause = false; - checkFinished(); - if (self._cb && !self._needDrain) { - const cb = self._cb; - self._cb = undefined; - cb(); - } + if (callback === undefined) { + return new Promise((resolve, reject) => { + this.destroy(err, (err, data) => { + return err ? /* istanbul ignore next: should never error */ reject(err) : resolve(data) }); - file._read = function (n) { - if (!self._pause) { return } - self._pause = false; - if (self._cb && !self._needDrain) { - const cb = self._cb; - self._cb = undefined; - cb(); - } - }; - boy.emit('file', fieldname, file, filename, encoding, contype); - - onData = function (data) { - if ((nsize += data.length) > fileSizeLimit) { - const extralen = fileSizeLimit - nsize + data.length; - if (extralen > 0) { file.push(data.slice(0, extralen)); } - file.truncated = true; - file.bytesRead = fileSizeLimit; - part.removeAllListeners('data'); - file.emit('limit'); - return - } else if (!file.push(data)) { self._pause = true; } + }) + } - file.bytesRead = nsize; - }; + if (typeof callback !== 'function') { + throw new InvalidArgumentError('invalid callback') + } - onEnd = function () { - curFile = undefined; - file.push(null); - }; + if (this[kDestroyed]) { + if (this[kOnDestroyed]) { + this[kOnDestroyed].push(callback); } else { - // non-file field - if (nfields === fieldsLimit) { - if (!boy.hitFieldsLimit) { - boy.hitFieldsLimit = true; - boy.emit('fieldsLimit'); - } - return skipPart(part) - } - - ++nfields; - ++nends; - let buffer = ''; - let truncated = false; - curField = part; - - onData = function (data) { - if ((nsize += data.length) > fieldSizeLimit) { - const extralen = (fieldSizeLimit - (nsize - data.length)); - buffer += data.toString('binary', 0, extralen); - truncated = true; - part.removeAllListeners('data'); - } else { buffer += data.toString('binary'); } - }; - - onEnd = function () { - curField = undefined; - if (buffer.length) { buffer = decodeText(buffer, 'binary', charset); } - boy.emit('field', fieldname, buffer, false, truncated, encoding, contype); - --nends; - checkFinished(); - }; + queueMicrotask(() => callback(null, null)); } + return + } - /* As of node@2efe4ab761666 (v0.10.29+/v0.11.14+), busboy had become - broken. Streams2/streams3 is a huge black box of confusion, but - somehow overriding the sync state seems to fix things again (and still - seems to work for previous node versions). - */ - part._readableState.sync = false; + if (!err) { + err = new ClientDestroyedError(); + } - part.on('data', onData); - part.on('end', onEnd); - }).on('error', function (err) { - if (curFile) { curFile.emit('error', err); } - }); - }).on('error', function (err) { - boy.emit('error', err); - }).on('finish', function () { - finished = true; - checkFinished(); - }); - } + this[kDestroyed] = true; + this[kOnDestroyed] = this[kOnDestroyed] || []; + this[kOnDestroyed].push(callback); - Multipart.prototype.write = function (chunk, cb) { - const r = this.parser.write(chunk); - if (r && !this._pause) { - cb(); - } else { - this._needDrain = !r; - this._cb = cb; + const onDestroyed = () => { + const callbacks = this[kOnDestroyed]; + this[kOnDestroyed] = null; + for (let i = 0; i < callbacks.length; i++) { + callbacks[i](null, null); + } + }; + + // Should not error. + this[kDestroy](err).then(() => { + queueMicrotask(onDestroyed); + }); } - }; - Multipart.prototype.end = function () { - const self = this; + [kInterceptedDispatch] (opts, handler) { + if (!this[kInterceptors] || this[kInterceptors].length === 0) { + this[kInterceptedDispatch] = this[kDispatch]; + return this[kDispatch](opts, handler) + } - if (self.parser.writable) { - self.parser.end(); - } else if (!self._boy._done) { - process.nextTick(function () { - self._boy._done = true; - self._boy.emit('finish'); - }); + 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) } - }; - function skipPart (part) { - part.resume(); - } + 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.') + } - function FileStream (opts) { - Readable.call(this, opts); + if (this[kDestroyed] || this[kOnDestroyed]) { + throw new ClientDestroyedError() + } - this.bytesRead = 0; + if (this[kClosed]) { + throw new ClientClosedError() + } - this.truncated = false; - } + return this[kInterceptedDispatch](opts, handler) + } catch (err) { + if (typeof handler.onError !== 'function') { + throw new InvalidArgumentError('invalid onError method') + } - inherits(FileStream, Readable); + handler.onError(err); - FileStream.prototype._read = function (n) {}; + return false + } + } + } - multipart = Multipart; - return multipart; + dispatcherBase = DispatcherBase; + return dispatcherBase; } -var Decoder_1; -var hasRequiredDecoder; +var timers; +var hasRequiredTimers; + +function requireTimers () { + if (hasRequiredTimers) return timers; + hasRequiredTimers = 1; + + /** + * This module offers an optimized timer implementation designed for scenarios + * where high precision is not critical. + * + * The timer achieves faster performance by using a low-resolution approach, + * with an accuracy target of within 500ms. This makes it particularly useful + * for timers with delays of 1 second or more, where exact timing is less + * crucial. + * + * It's important to note that Node.js timers are inherently imprecise, as + * delays can occur due to the event loop being blocked by other operations. + * Consequently, timers may trigger later than their scheduled time. + */ -function requireDecoder () { - if (hasRequiredDecoder) return Decoder_1; - hasRequiredDecoder = 1; + /** + * The fastNow variable contains the internal fast timer clock value. + * + * @type {number} + */ + let fastNow = 0; - const RE_PLUS = /\+/g; + /** + * RESOLUTION_MS represents the target resolution time in milliseconds. + * + * @type {number} + * @default 1000 + */ + const RESOLUTION_MS = 1e3; - const HEX = [ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, - 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 - ]; + /** + * TICK_MS defines the desired interval in milliseconds between each tick. + * The target value is set to half the resolution time, minus 1 ms, to account + * for potential event loop overhead. + * + * @type {number} + * @default 499 + */ + const TICK_MS = (RESOLUTION_MS >> 1) - 1; - function Decoder () { - this.buffer = undefined; - } - Decoder.prototype.write = function (str) { - // Replace '+' with ' ' before decoding - str = str.replace(RE_PLUS, ' '); - let res = ''; - let i = 0; let p = 0; const len = str.length; - for (; i < len; ++i) { - if (this.buffer !== undefined) { - if (!HEX[str.charCodeAt(i)]) { - res += '%' + this.buffer; - this.buffer = undefined; - --i; // retry character - } else { - this.buffer += str[i]; - ++p; - if (this.buffer.length === 2) { - res += String.fromCharCode(parseInt(this.buffer, 16)); - this.buffer = undefined; - } - } - } else if (str[i] === '%') { - if (i > p) { - res += str.substring(p, i); - p = i; - } - this.buffer = ''; - ++p; - } - } - if (p < len && this.buffer === undefined) { res += str.substring(p); } - return res - }; - Decoder.prototype.reset = function () { - this.buffer = undefined; - }; + /** + * fastNowTimeout is a Node.js timer used to manage and process + * the FastTimers stored in the `fastTimers` array. + * + * @type {NodeJS.Timeout} + */ + let fastNowTimeout; - Decoder_1 = Decoder; - return Decoder_1; -} + /** + * The kFastTimer symbol is used to identify FastTimer instances. + * + * @type {Symbol} + */ + const kFastTimer = Symbol('kFastTimer'); -var urlencoded; -var hasRequiredUrlencoded; + /** + * The fastTimers array contains all active FastTimers. + * + * @type {FastTimer[]} + */ + const fastTimers = []; -function requireUrlencoded () { - if (hasRequiredUrlencoded) return urlencoded; - hasRequiredUrlencoded = 1; + /** + * These constants represent the various states of a FastTimer. + */ + + /** + * The `NOT_IN_LIST` constant indicates that the FastTimer is not included + * in the `fastTimers` array. Timers with this status will not be processed + * during the next tick by the `onTick` function. + * + * A FastTimer can be re-added to the `fastTimers` array by invoking the + * `refresh` method on the FastTimer instance. + * + * @type {-2} + */ + const NOT_IN_LIST = -2; - const Decoder = requireDecoder(); - const decodeText = requireDecodeText(); - const getLimit = requireGetLimit(); + /** + * The `TO_BE_CLEARED` constant indicates that the FastTimer is scheduled + * for removal from the `fastTimers` array. A FastTimer in this state will + * be removed in the next tick by the `onTick` function and will no longer + * be processed. + * + * This status is also set when the `clear` method is called on the FastTimer instance. + * + * @type {-1} + */ + const TO_BE_CLEARED = -1; - const RE_CHARSET = /^charset$/i; + /** + * The `PENDING` constant signifies that the FastTimer is awaiting processing + * in the next tick by the `onTick` function. Timers with this status will have + * their `_idleStart` value set and their status updated to `ACTIVE` in the next tick. + * + * @type {0} + */ + const PENDING = 0; - UrlEncoded.detect = /^application\/x-www-form-urlencoded/i; - function UrlEncoded (boy, cfg) { - const limits = cfg.limits; - const parsedConType = cfg.parsedConType; - this.boy = boy; + /** + * The `ACTIVE` constant indicates that the FastTimer is active and waiting + * for its timer to expire. During the next tick, the `onTick` function will + * check if the timer has expired, and if so, it will execute the associated callback. + * + * @type {1} + */ + const ACTIVE = 1; - this.fieldSizeLimit = getLimit(limits, 'fieldSize', 1 * 1024 * 1024); - this.fieldNameSizeLimit = getLimit(limits, 'fieldNameSize', 100); - this.fieldsLimit = getLimit(limits, 'fields', Infinity); + /** + * The onTick function processes the fastTimers array. + * + * @returns {void} + */ + function onTick () { + /** + * Increment the fastNow value by the TICK_MS value, despite the actual time + * that has passed since the last tick. This approach ensures independence + * from the system clock and delays caused by a blocked event loop. + * + * @type {number} + */ + fastNow += TICK_MS; - let charset; - for (var i = 0, len = parsedConType.length; i < len; ++i) { // eslint-disable-line no-var - if (Array.isArray(parsedConType[i]) && - RE_CHARSET.test(parsedConType[i][0])) { - charset = parsedConType[i][1].toLowerCase(); - break - } - } + /** + * The `idx` variable is used to iterate over the `fastTimers` array. + * Expired timers are removed by replacing them with the last element in the array. + * Consequently, `idx` is only incremented when the current element is not removed. + * + * @type {number} + */ + let idx = 0; - if (charset === undefined) { charset = cfg.defCharset || 'utf8'; } + /** + * The len variable will contain the length of the fastTimers array + * and will be decremented when a FastTimer should be removed from the + * fastTimers array. + * + * @type {number} + */ + let len = fastTimers.length; - this.decoder = new Decoder(); - this.charset = charset; - this._fields = 0; - this._state = 'key'; - this._checkingBytes = true; - this._bytesKey = 0; - this._bytesVal = 0; - this._key = ''; - this._val = ''; - this._keyTrunc = false; - this._valTrunc = false; - this._hitLimit = false; - } + while (idx < len) { + /** + * @type {FastTimer} + */ + const timer = fastTimers[idx]; - UrlEncoded.prototype.write = function (data, cb) { - if (this._fields === this.fieldsLimit) { - if (!this.boy.hitFieldsLimit) { - this.boy.hitFieldsLimit = true; - this.boy.emit('fieldsLimit'); + // If the timer is in the ACTIVE state and the timer has expired, it will + // be processed in the next tick. + if (timer._state === PENDING) { + // Set the _idleStart value to the fastNow value minus the TICK_MS value + // to account for the time the timer was in the PENDING state. + 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); } - return cb() - } - let idxeq; let idxamp; let i; let p = 0; const len = data.length; + if (timer._state === TO_BE_CLEARED) { + timer._state = NOT_IN_LIST; - while (p < len) { - if (this._state === 'key') { - idxeq = idxamp = undefined; - for (i = p; i < len; ++i) { - if (!this._checkingBytes) { ++p; } - if (data[i] === 0x3D/* = */) { - idxeq = i; - break - } else if (data[i] === 0x26/* & */) { - idxamp = i; - break - } - if (this._checkingBytes && this._bytesKey === this.fieldNameSizeLimit) { - this._hitLimit = true; - break - } else if (this._checkingBytes) { ++this._bytesKey; } - } - - if (idxeq !== undefined) { - // key with assignment - if (idxeq > p) { this._key += this.decoder.write(data.toString('binary', p, idxeq)); } - this._state = 'val'; - - this._hitLimit = false; - this._checkingBytes = true; - this._val = ''; - this._bytesVal = 0; - this._valTrunc = false; - this.decoder.reset(); - - p = idxeq + 1; - } else if (idxamp !== undefined) { - // key with no assignment - ++this._fields; - let key; const keyTrunc = this._keyTrunc; - if (idxamp > p) { key = (this._key += this.decoder.write(data.toString('binary', p, idxamp))); } else { key = this._key; } - - this._hitLimit = false; - this._checkingBytes = true; - this._key = ''; - this._bytesKey = 0; - this._keyTrunc = false; - this.decoder.reset(); - - if (key.length) { - this.boy.emit('field', decodeText(key, 'binary', this.charset), - '', - keyTrunc, - false); - } - - p = idxamp + 1; - if (this._fields === this.fieldsLimit) { return cb() } - } else if (this._hitLimit) { - // we may not have hit the actual limit if there are encoded bytes... - if (i > p) { this._key += this.decoder.write(data.toString('binary', p, i)); } - p = i; - if ((this._bytesKey = this._key.length) === this.fieldNameSizeLimit) { - // yep, we actually did hit the limit - this._checkingBytes = false; - this._keyTrunc = true; - } - } else { - if (p < len) { this._key += this.decoder.write(data.toString('binary', p)); } - p = len; + // Move the last element to the current index and decrement len if it is + // not the only element in the array. + if (--len !== 0) { + fastTimers[idx] = fastTimers[len]; } } else { - idxamp = undefined; - for (i = p; i < len; ++i) { - if (!this._checkingBytes) { ++p; } - if (data[i] === 0x26/* & */) { - idxamp = i; - break - } - if (this._checkingBytes && this._bytesVal === this.fieldSizeLimit) { - this._hitLimit = true; - break - } else if (this._checkingBytes) { ++this._bytesVal; } - } - - if (idxamp !== undefined) { - ++this._fields; - if (idxamp > p) { this._val += this.decoder.write(data.toString('binary', p, idxamp)); } - this.boy.emit('field', decodeText(this._key, 'binary', this.charset), - decodeText(this._val, 'binary', this.charset), - this._keyTrunc, - this._valTrunc); - this._state = 'key'; - - this._hitLimit = false; - this._checkingBytes = true; - this._key = ''; - this._bytesKey = 0; - this._keyTrunc = false; - this.decoder.reset(); - - p = idxamp + 1; - if (this._fields === this.fieldsLimit) { return cb() } - } else if (this._hitLimit) { - // we may not have hit the actual limit if there are encoded bytes... - if (i > p) { this._val += this.decoder.write(data.toString('binary', p, i)); } - p = i; - if ((this._val === '' && this.fieldSizeLimit === 0) || - (this._bytesVal = this._val.length) === this.fieldSizeLimit) { - // yep, we actually did hit the limit - this._checkingBytes = false; - this._valTrunc = true; - } - } else { - if (p < len) { this._val += this.decoder.write(data.toString('binary', p)); } - p = len; - } + ++idx; } } - cb(); - }; - UrlEncoded.prototype.end = function () { - if (this.boy._done) { return } - - if (this._state === 'key' && this._key.length > 0) { - this.boy.emit('field', decodeText(this._key, 'binary', this.charset), - '', - this._keyTrunc, - false); - } else if (this._state === 'val') { - this.boy.emit('field', decodeText(this._key, 'binary', this.charset), - decodeText(this._val, 'binary', this.charset), - this._keyTrunc, - this._valTrunc); - } - this.boy._done = true; - this.boy.emit('finish'); - }; + // Set the length of the fastTimers array to the new length and thus + // removing the excess FastTimers elements from the array. + fastTimers.length = len; - urlencoded = UrlEncoded; - return urlencoded; -} + // If there are still active FastTimers in the array, refresh the Timer. + // If there are no active FastTimers, the timer will be refreshed again + // when a new FastTimer is instantiated. + if (fastTimers.length !== 0) { + refreshTimeout(); + } + } -var hasRequiredMain; + function refreshTimeout () { + // If the fastNowTimeout is already set, refresh it. + if (fastNowTimeout) { + fastNowTimeout.refresh(); + // fastNowTimeout is not instantiated yet, create a new Timer. + } else { + clearTimeout(fastNowTimeout); + fastNowTimeout = setTimeout(onTick, TICK_MS); -function requireMain () { - if (hasRequiredMain) return main.exports; - hasRequiredMain = 1; + // If the Timer has an unref method, call it to allow the process to exit if + // there are no other active handles. + if (fastNowTimeout.unref) { + fastNowTimeout.unref(); + } + } + } - const WritableStream = require$$0$7.Writable; - const { inherits } = require$$1$2; - const Dicer = requireDicer(); + /** + * The `FastTimer` class is a data structure designed to store and manage + * timer information. + */ + class FastTimer { + [kFastTimer] = true - const MultipartParser = requireMultipart(); - const UrlencodedParser = requireUrlencoded(); - const parseParams = requireParseParams(); + /** + * 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 - function Busboy (opts) { - if (!(this instanceof Busboy)) { return new Busboy(opts) } + /** + * The number of milliseconds to wait before calling the callback. + * + * @type {number} + * @private + */ + _idleTimeout = -1 - if (typeof opts !== 'object') { - throw new TypeError('Busboy expected an options-Object.') - } - if (typeof opts.headers !== 'object') { - throw new TypeError('Busboy expected an options-Object with headers-attribute.') - } - if (typeof opts.headers['content-type'] !== 'string') { - throw new TypeError('Missing Content-Type-header.') - } + /** + * 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 - const { - headers, - ...streamOptions - } = opts; + /** + * The function to be executed when the timer expires. + * @type {Function} + * @private + */ + _onTimeout - this.opts = { - autoDestroy: false, - ...streamOptions - }; - WritableStream.call(this, this.opts); + /** + * The argument to be passed to the callback when the timer expires. + * + * @type {*} + * @private + */ + _timerArg - this._done = false; - this._parser = this.getParserByHeaders(headers); - this._finished = false; - } - inherits(Busboy, WritableStream); + /** + * @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; - Busboy.prototype.emit = function (ev) { - if (ev === 'finish') { - if (!this._done) { - this._parser?.end(); - return - } else if (this._finished) { - return - } - this._finished = true; + this.refresh(); } - WritableStream.prototype.emit.apply(this, arguments); - }; - Busboy.prototype.getParserByHeaders = function (headers) { - const parsed = parseParams(headers['content-type']); + /** + * 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 () { + // In the special case that the timer is not in the list of active timers, + // add it back to the array to be processed in the next tick by the onTick + // function. + if (this._state === NOT_IN_LIST) { + fastTimers.push(this); + } - const cfg = { - defCharset: this.opts.defCharset, - fileHwm: this.opts.fileHwm, - headers, - highWaterMark: this.opts.highWaterMark, - isPartAFile: this.opts.isPartAFile, - limits: this.opts.limits, - parsedConType: parsed, - preservePath: this.opts.preservePath - }; + // If the timer is the only active timer, refresh the fastNowTimeout for + // better resolution. + if (!fastNowTimeout || fastTimers.length === 1) { + refreshTimeout(); + } - if (MultipartParser.detect.test(parsed[0])) { - return new MultipartParser(this, cfg) + // Setting the state to PENDING will cause the timer to be reset in the + // next tick by the onTick function. + this._state = PENDING; } - if (UrlencodedParser.detect.test(parsed[0])) { - return new UrlencodedParser(this, cfg) - } - throw new Error('Unsupported Content-Type.') - }; - Busboy.prototype._write = function (chunk, encoding, cb) { - this._parser.write(chunk, cb); - }; + /** + * The `clear` method cancels the timer, preventing it from executing. + * + * @returns {void} + * @private + */ + clear () { + // Set the state to TO_BE_CLEARED to mark the timer for removal in the next + // tick by the onTick function. + this._state = TO_BE_CLEARED; - main.exports = Busboy; - main.exports.default = Busboy; - main.exports.Busboy = Busboy; + // Reset the _idleStart value to -1 to indicate that the timer is no longer + // active. + this._idleStart = -1; + } + } - main.exports.Dicer = Dicer; - return main.exports; + /** + * This module exports a setTimeout and clearTimeout function that can be + * used as a drop-in replacement for the native functions. + */ + timers = { + /** + * 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) { + // If the delay is less than or equal to the RESOLUTION_MS value return a + // native Node.js Timer instance. + 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 the timeout is a FastTimer, call its own clear method. + if (timeout[kFastTimer]) { + /** + * @type {FastTimer} + */ + timeout.clear(); + // Otherwise it is an instance of a native NodeJS.Timeout, so call the + // Node.js native clearTimeout function. + } 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 + }; + return timers; } -var constants$3; -var hasRequiredConstants$3; - -function requireConstants$3 () { - if (hasRequiredConstants$3) return constants$3; - hasRequiredConstants$3 = 1; - - const { MessageChannel, receiveMessageOnPort } = require$$0$8; +var connect; +var hasRequiredConnect; - const corsSafeListedMethods = ['GET', 'HEAD', 'POST']; - const corsSafeListedMethodsSet = new Set(corsSafeListedMethods); +function requireConnect () { + if (hasRequiredConnect) return connect; + hasRequiredConnect = 1; - const nullBodyStatus = [101, 204, 205, 304]; + const net = require$$0$5; + const assert = require$$0$3; + const util = requireUtil$8(); + const { InvalidArgumentError, ConnectTimeoutError } = requireErrors(); + const timers = requireTimers(); - const redirectStatus = [301, 302, 303, 307, 308]; - const redirectStatusSet = new Set(redirectStatus); + function noop () {} - // https://fetch.spec.whatwg.org/#block-bad-port - const badPorts = [ - '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', '5060', '5061', '6000', '6566', '6665', '6666', '6667', '6668', '6669', '6697', - '10080' - ]; + let tls; // include tls conditionally since it is not always available - const badPortsSet = new Set(badPorts); + // TODO: session re-use does not wait for the first + // connection to resolve the session and might therefore + // resolve the same servername multiple times even when + // re-use is enabled. - // https://w3c.github.io/webappsec-referrer-policy/#referrer-policies - const referrerPolicy = [ - '', - 'no-referrer', - 'no-referrer-when-downgrade', - 'same-origin', - 'origin', - 'strict-origin', - 'origin-when-cross-origin', - 'strict-origin-when-cross-origin', - 'unsafe-url' - ]; - const referrerPolicySet = new Set(referrerPolicy); - - const requestRedirect = ['follow', 'manual', 'error']; - - const safeMethods = ['GET', 'HEAD', 'OPTIONS', 'TRACE']; - const safeMethodsSet = new Set(safeMethods); - - const requestMode = ['navigate', 'same-origin', 'no-cors', 'cors']; - - const requestCredentials = ['omit', 'same-origin', 'include']; - - const requestCache = [ - 'default', - 'no-store', - 'reload', - 'no-cache', - 'force-cache', - 'only-if-cached' - ]; - - // https://fetch.spec.whatwg.org/#request-body-header-name - const requestBodyHeader = [ - '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' - ]; - - // https://fetch.spec.whatwg.org/#enumdef-requestduplex - const requestDuplex = [ - 'half' - ]; - - // http://fetch.spec.whatwg.org/#forbidden-method - const forbiddenMethods = ['CONNECT', 'TRACE', 'TRACK']; - const forbiddenMethodsSet = new Set(forbiddenMethods); - - const subresource = [ - 'audio', - 'audioworklet', - 'font', - 'image', - 'manifest', - 'paintworklet', - 'script', - 'style', - 'track', - 'video', - 'xslt', - '' - ]; - const subresourceSet = new Set(subresource); - - /** @type {globalThis['DOMException']} */ - const DOMException = globalThis.DOMException ?? (() => { - // DOMException was only made a global in Node v17.0.0, - // but fetch supports >= v16.8. - try { - atob('~'); - } catch (err) { - return Object.getPrototypeOf(err).constructor - } - })(); + let SessionCache; + // FIXME: remove workaround when the Node bug is fixed + // https://github.com/nodejs/node/issues/49344#issuecomment-1741776308 + if (commonjsGlobal.FinalizationRegistry && !(process.env.NODE_V8_COVERAGE || process.env.UNDICI_NO_FG)) { + SessionCache = class WeakSessionCache { + constructor (maxCachedSessions) { + this._maxCachedSessions = maxCachedSessions; + this._sessionCache = new Map(); + this._sessionRegistry = new commonjsGlobal.FinalizationRegistry((key) => { + if (this._sessionCache.size < this._maxCachedSessions) { + return + } - let channel; + const ref = this._sessionCache.get(key); + if (ref !== undefined && ref.deref() === undefined) { + this._sessionCache.delete(key); + } + }); + } - /** @type {globalThis['structuredClone']} */ - const structuredClone = - globalThis.structuredClone ?? - // https://github.com/nodejs/node/blob/b27ae24dcc4251bad726d9d84baf678d1f707fed/lib/internal/structured_clone.js - // structuredClone was added in v17.0.0, but fetch supports v16.8 - function structuredClone (value, options = undefined) { - if (arguments.length === 0) { - throw new TypeError('missing argument') + get (sessionKey) { + const ref = this._sessionCache.get(sessionKey); + return ref ? ref.deref() : null } - if (!channel) { - channel = new MessageChannel(); + set (sessionKey, session) { + if (this._maxCachedSessions === 0) { + return + } + + this._sessionCache.set(sessionKey, new WeakRef(session)); + this._sessionRegistry.register(session, sessionKey); } - channel.port1.unref(); - channel.port2.unref(); - channel.port1.postMessage(value, options?.transfer); - return receiveMessageOnPort(channel.port2).message }; + } else { + SessionCache = class SimpleSessionCache { + constructor (maxCachedSessions) { + this._maxCachedSessions = maxCachedSessions; + this._sessionCache = new Map(); + } - constants$3 = { - DOMException, - structuredClone, - subresource, - forbiddenMethods, - requestBodyHeader, - referrerPolicy, - requestRedirect, - requestMode, - requestCredentials, - requestCache, - redirectStatus, - corsSafeListedMethods, - nullBodyStatus, - safeMethods, - badPorts, - requestDuplex, - subresourceSet, - badPortsSet, - redirectStatusSet, - corsSafeListedMethodsSet, - safeMethodsSet, - forbiddenMethodsSet, - referrerPolicySet - }; - return constants$3; -} - -var global$2; -var hasRequiredGlobal$1; + get (sessionKey) { + return this._sessionCache.get(sessionKey) + } -function requireGlobal$1 () { - if (hasRequiredGlobal$1) return global$2; - hasRequiredGlobal$1 = 1; + set (sessionKey, session) { + if (this._maxCachedSessions === 0) { + return + } - // In case of breaking changes, increase the version - // number to avoid conflicts. - const globalOrigin = Symbol.for('undici.globalOrigin.1'); + if (this._sessionCache.size >= this._maxCachedSessions) { + // remove the oldest session + const { value: oldestKey } = this._sessionCache.keys().next(); + this._sessionCache.delete(oldestKey); + } - function getGlobalOrigin () { - return globalThis[globalOrigin] + this._sessionCache.set(sessionKey, session); + } + }; } - function setGlobalOrigin (newOrigin) { - if (newOrigin === undefined) { - Object.defineProperty(globalThis, globalOrigin, { - value: undefined, - 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}`) + 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') } - Object.defineProperty(globalThis, globalOrigin, { - value: parsedURL, - writable: true, - enumerable: false, - configurable: false - }); - } - - global$2 = { - getGlobalOrigin, - setGlobalOrigin - }; - return global$2; -} - -var util$6; -var hasRequiredUtil$6; - -function requireUtil$6 () { - if (hasRequiredUtil$6) return util$6; - hasRequiredUtil$6 = 1; - - const { redirectStatusSet, referrerPolicySet: referrerPolicyTokens, badPortsSet } = requireConstants$3(); - const { getGlobalOrigin } = requireGlobal$1(); - const { performance } = require$$2$2; - const { isBlobLike, toUSVString, ReadableStreamFrom } = requireUtil$7(); - const assert = require$$0$3; - const { isUint8Array } = require$$5; - - let supportedHashes = []; - - // https://nodejs.org/api/crypto.html#determining-if-crypto-support-is-unavailable - /** @type {import('crypto')|undefined} */ - let crypto; + const options = { path: socketPath, ...opts }; + const sessionCache = new SessionCache(maxCachedSessions == null ? 100 : maxCachedSessions); + timeout = timeout == null ? 10e3 : timeout; + allowH2 = allowH2 != null ? allowH2 : false; + return function connect ({ hostname, host, protocol, port, servername, localAddress, httpSocket }, callback) { + let socket; + if (protocol === 'https:') { + if (!tls) { + tls = require$$5; + } + servername = servername || options.servername || util.getServerName(host) || null; - try { - crypto = require('crypto'); - const possibleRelevantHashes = ['sha256', 'sha384', 'sha512']; - supportedHashes = crypto.getHashes().filter((hash) => possibleRelevantHashes.includes(hash)); - /* c8 ignore next 3 */ - } catch { - } + const sessionKey = servername || hostname; + assert(sessionKey); - function responseURL (response) { - // https://fetch.spec.whatwg.org/#responses - // A response has an associated URL. It is a pointer to the last URL - // in response’s URL list and null if response’s URL list is empty. - const urlList = response.urlList; - const length = urlList.length; - return length === 0 ? null : urlList[length - 1].toString() - } + const session = customSession || sessionCache.get(sessionKey) || null; - // https://fetch.spec.whatwg.org/#concept-response-location-url - function responseLocationURL (response, requestFragment) { - // 1. If response’s status is not a redirect status, then return null. - if (!redirectStatusSet.has(response.status)) { - return null - } + port = port || 443; - // 2. Let location be the result of extracting header list values given - // `Location` and response’s header list. - let location = response.headersList.get('location'); + 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, + host: hostname + }); - // 3. If location is a header value, then set location to the result of - // parsing location with response’s URL. - if (location !== null && isValidHeaderValue(location)) { - location = new URL(location, responseURL(response)); - } + socket + .on('session', function (session) { + // TODO (fix): Can a session become invalid once established? Don't think so? + sessionCache.set(sessionKey, session); + }); + } else { + assert(!httpSocket, 'httpSocket can only be sent on TLS update'); - // 4. If location is a URL whose fragment is null, then set location’s - // fragment to requestFragment. - if (location && !location.hash) { - location.hash = requestFragment; - } + port = port || 80; - // 5. Return location. - return location - } + socket = net.connect({ + highWaterMark: 64 * 1024, // Same as nodejs fs streams. + ...options, + localAddress, + port, + host: hostname + }); + } - /** @returns {URL} */ - function requestCurrentURL (request) { - return request.urlList[request.urlList.length - 1] - } + // Set TCP keep alive options on the socket here instead of in connect() for the case of assigning the socket + if (options.keepAlive == null || options.keepAlive) { + const keepAliveInitialDelay = options.keepAliveInitialDelay === undefined ? 60e3 : options.keepAliveInitialDelay; + socket.setKeepAlive(true, keepAliveInitialDelay); + } - function requestBadPort (request) { - // 1. Let url be request’s current URL. - const url = requestCurrentURL(request); + const clearConnectTimeout = setupConnectTimeout(new WeakRef(socket), { timeout, hostname, port }); - // 2. If url’s scheme is an HTTP(S) scheme and url’s port is a bad port, - // then return blocked. - if (urlIsHttpHttpsScheme(url) && badPortsSet.has(url.port)) { - return 'blocked' - } + socket + .setNoDelay(true) + .once(protocol === 'https:' ? 'secureConnect' : 'connect', function () { + queueMicrotask(clearConnectTimeout); - // 3. Return allowed. - return 'allowed' - } + if (callback) { + const cb = callback; + callback = null; + cb(null, this); + } + }) + .on('error', function (err) { + queueMicrotask(clearConnectTimeout); - function isErrorLike (object) { - return object instanceof Error || ( - object?.constructor?.name === 'Error' || - object?.constructor?.name === 'DOMException' - ) - } + if (callback) { + const cb = callback; + callback = null; + cb(err); + } + }); - // Check whether |statusText| is a ByteString and - // matches the Reason-Phrase token production. - // RFC 2616: https://tools.ietf.org/html/rfc2616 - // RFC 7230: https://tools.ietf.org/html/rfc7230 - // "reason-phrase = *( HTAB / SP / VCHAR / obs-text )" - // https://github.com/chromium/chromium/blob/94.0.4604.1/third_party/blink/renderer/core/fetch/response.cc#L116 - function isValidReasonPhrase (statusText) { - for (let i = 0; i < statusText.length; ++i) { - const c = statusText.charCodeAt(i); - if ( - !( - ( - c === 0x09 || // HTAB - (c >= 0x20 && c <= 0x7e) || // SP / VCHAR - (c >= 0x80 && c <= 0xff) - ) // obs-text - ) - ) { - return false - } + return socket } - return true } /** - * @see https://tools.ietf.org/html/rfc7230#section-3.2.6 - * @param {number} c + * @param {WeakRef} socketWeakRef + * @param {object} opts + * @param {number} opts.timeout + * @param {string} opts.hostname + * @param {number} opts.port + * @returns {() => void} */ - function isTokenCharCode (c) { - switch (c) { - case 0x22: - case 0x28: - case 0x29: - case 0x2c: - case 0x2f: - case 0x3a: - case 0x3b: - case 0x3c: - case 0x3d: - case 0x3e: - case 0x3f: - case 0x40: - case 0x5b: - case 0x5c: - case 0x5d: - case 0x7b: - case 0x7d: - // DQUOTE and "(),/:;<=>?@[\]{}" - return false - default: - // VCHAR %x21-7E - return c >= 0x21 && c <= 0x7e - } - } + const setupConnectTimeout = process.platform === 'win32' + ? (socketWeakRef, opts) => { + if (!opts.timeout) { + return noop + } - /** - * @param {string} characters - */ - function isValidHTTPToken (characters) { - if (characters.length === 0) { - return false - } - for (let i = 0; i < characters.length; ++i) { - if (!isTokenCharCode(characters.charCodeAt(i))) { - return false + let s1 = null; + let s2 = null; + const fastTimer = timers.setFastTimeout(() => { + // setImmediate is added to make sure that we prioritize socket error events over timeouts + s1 = setImmediate(() => { + // Windows needs an extra setImmediate probably due to implementation differences in the socket logic + s2 = setImmediate(() => onConnectTimeout(socketWeakRef.deref(), opts)); + }); + }, opts.timeout); + return () => { + timers.clearFastTimeout(fastTimer); + clearImmediate(s1); + clearImmediate(s2); + } } - } - return true - } + : (socketWeakRef, opts) => { + if (!opts.timeout) { + return noop + } - /** - * @see https://fetch.spec.whatwg.org/#header-name - * @param {string} potentialValue - */ - function isValidHeaderName (potentialValue) { - return isValidHTTPToken(potentialValue) - } + let s1 = null; + const fastTimer = timers.setFastTimeout(() => { + // setImmediate is added to make sure that we prioritize socket error events over timeouts + s1 = setImmediate(() => { + onConnectTimeout(socketWeakRef.deref(), opts); + }); + }, opts.timeout); + return () => { + timers.clearFastTimeout(fastTimer); + clearImmediate(s1); + } + }; /** - * @see https://fetch.spec.whatwg.org/#header-value - * @param {string} potentialValue + * @param {net.Socket} socket + * @param {object} opts + * @param {number} opts.timeout + * @param {string} opts.hostname + * @param {number} opts.port */ - function isValidHeaderValue (potentialValue) { - // - Has no leading or trailing HTTP tab or space bytes. - // - Contains no 0x00 (NUL) or HTTP newline bytes. - if ( - potentialValue.startsWith('\t') || - potentialValue.startsWith(' ') || - potentialValue.endsWith('\t') || - potentialValue.endsWith(' ') - ) { - return false - } - - if ( - potentialValue.includes('\0') || - potentialValue.includes('\r') || - potentialValue.includes('\n') - ) { - return false - } - - return true - } - - // https://w3c.github.io/webappsec-referrer-policy/#set-requests-referrer-policy-on-redirect - function setRequestReferrerPolicyOnRedirect (request, actualResponse) { - // Given a request request and a response actualResponse, this algorithm - // updates request’s referrer policy according to the Referrer-Policy - // header (if any) in actualResponse. - - // 1. Let policy be the result of executing § 8.1 Parse a referrer policy - // from a Referrer-Policy header on actualResponse. - - // 8.1 Parse a referrer policy from a Referrer-Policy header - // 1. Let policy-tokens be the result of extracting header list values given `Referrer-Policy` and response’s header list. - const { headersList } = actualResponse; - // 2. Let policy be the empty string. - // 3. For each token in policy-tokens, if token is a referrer policy and token is not the empty string, then set policy to token. - // 4. Return policy. - const policyHeader = (headersList.get('referrer-policy') ?? '').split(','); - - // Note: As the referrer-policy can contain multiple policies - // separated by comma, we need to loop through all of them - // and pick the first valid one. - // Ref: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Referrer-Policy#specify_a_fallback_policy - let policy = ''; - if (policyHeader.length > 0) { - // The right-most policy takes precedence. - // The left-most policy is the fallback. - for (let i = policyHeader.length; i !== 0; i--) { - const token = policyHeader[i - 1].trim(); - if (referrerPolicyTokens.has(token)) { - policy = token; - break - } - } + function onConnectTimeout (socket, opts) { + // The socket could be already garbage collected + if (socket == null) { + return } - // 2. If policy is not the empty string, then set request’s referrer policy to policy. - if (policy !== '') { - request.referrerPolicy = policy; + let message = 'Connect Timeout Error'; + if (Array.isArray(socket.autoSelectFamilyAttemptedAddresses)) { + message += ` (attempted addresses: ${socket.autoSelectFamilyAttemptedAddresses.join(', ')},`; + } else { + message += ` (attempted address: ${opts.hostname}:${opts.port},`; } - } - // https://fetch.spec.whatwg.org/#cross-origin-resource-policy-check - function crossOriginResourcePolicyCheck () { - // TODO - return 'allowed' - } - - // https://fetch.spec.whatwg.org/#concept-cors-check - function corsCheck () { - // TODO - return 'success' - } + message += ` timeout: ${opts.timeout}ms)`; - // https://fetch.spec.whatwg.org/#concept-tao-check - function TAOCheck () { - // TODO - return 'success' + util.destroy(socket, new ConnectTimeoutError(message)); } - function appendFetchMetadata (httpRequest) { - // https://w3c.github.io/webappsec-fetch-metadata/#sec-fetch-dest-header - // TODO - - // https://w3c.github.io/webappsec-fetch-metadata/#sec-fetch-mode-header - - // 1. Assert: r’s url is a potentially trustworthy URL. - // TODO - - // 2. Let header be a Structured Header whose value is a token. - let header = null; + connect = buildConnector; + return connect; +} - // 3. Set header’s value to r’s mode. - header = httpRequest.mode; +var constants$3 = {}; - // 4. Set a structured field value `Sec-Fetch-Mode`/header in r’s header list. - httpRequest.headersList.set('sec-fetch-mode', header); +var utils$1 = {}; - // https://w3c.github.io/webappsec-fetch-metadata/#sec-fetch-site-header - // TODO +var hasRequiredUtils$1; - // https://w3c.github.io/webappsec-fetch-metadata/#sec-fetch-user-header - // TODO +function requireUtils$1 () { + if (hasRequiredUtils$1) return utils$1; + hasRequiredUtils$1 = 1; + Object.defineProperty(utils$1, "__esModule", { value: true }); + utils$1.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; } + utils$1.enumToMap = enumToMap; + + return utils$1; +} - // https://fetch.spec.whatwg.org/#append-a-request-origin-header - function appendRequestOriginHeader (request) { - // 1. Let serializedOrigin be the result of byte-serializing a request origin with request. - let serializedOrigin = request.origin; - - // 2. If request’s response tainting is "cors" or request’s mode is "websocket", then append (`Origin`, serializedOrigin) to request’s header list. - if (request.responseTainting === 'cors' || request.mode === 'websocket') { - if (serializedOrigin) { - request.headersList.append('origin', serializedOrigin); - } +var hasRequiredConstants$3; - // 3. Otherwise, if request’s method is neither `GET` nor `HEAD`, then: - } else if (request.method !== 'GET' && request.method !== 'HEAD') { - // 1. Switch on request’s referrer policy: - switch (request.referrerPolicy) { - case 'no-referrer': - // Set serializedOrigin to `null`. - serializedOrigin = null; - break - case 'no-referrer-when-downgrade': - case 'strict-origin': - case 'strict-origin-when-cross-origin': - // If request’s origin is a tuple origin, its scheme is "https", and request’s current URL’s scheme is not "https", then set serializedOrigin to `null`. - if (request.origin && urlHasHttpsScheme(request.origin) && !urlHasHttpsScheme(requestCurrentURL(request))) { - serializedOrigin = null; - } - break - case 'same-origin': - // If request’s origin is not same origin with request’s current URL’s origin, then set serializedOrigin to `null`. - if (!sameOrigin(request, requestCurrentURL(request))) { - serializedOrigin = null; - } - break - // Do nothing. - } +function requireConstants$3 () { + if (hasRequiredConstants$3) return constants$3; + hasRequiredConstants$3 = 1; + (function (exports$1) { + Object.defineProperty(exports$1, "__esModule", { value: true }); + exports$1.SPECIAL_HEADERS = exports$1.HEADER_STATE = exports$1.MINOR = exports$1.MAJOR = exports$1.CONNECTION_TOKEN_CHARS = exports$1.HEADER_CHARS = exports$1.TOKEN = exports$1.STRICT_TOKEN = exports$1.HEX = exports$1.URL_CHAR = exports$1.STRICT_URL_CHAR = exports$1.USERINFO_CHARS = exports$1.MARK = exports$1.ALPHANUM = exports$1.NUM = exports$1.HEX_MAP = exports$1.NUM_MAP = exports$1.ALPHA = exports$1.FINISH = exports$1.H_METHOD_MAP = exports$1.METHOD_MAP = exports$1.METHODS_RTSP = exports$1.METHODS_ICE = exports$1.METHODS_HTTP = exports$1.METHODS = exports$1.LENIENT_FLAGS = exports$1.FLAGS = exports$1.TYPE = exports$1.ERROR = void 0; + const utils_1 = requireUtils$1(); + (function (ERROR) { + ERROR[ERROR["OK"] = 0] = "OK"; + ERROR[ERROR["INTERNAL"] = 1] = "INTERNAL"; + ERROR[ERROR["STRICT"] = 2] = "STRICT"; + ERROR[ERROR["LF_EXPECTED"] = 3] = "LF_EXPECTED"; + ERROR[ERROR["UNEXPECTED_CONTENT_LENGTH"] = 4] = "UNEXPECTED_CONTENT_LENGTH"; + ERROR[ERROR["CLOSED_CONNECTION"] = 5] = "CLOSED_CONNECTION"; + ERROR[ERROR["INVALID_METHOD"] = 6] = "INVALID_METHOD"; + ERROR[ERROR["INVALID_URL"] = 7] = "INVALID_URL"; + ERROR[ERROR["INVALID_CONSTANT"] = 8] = "INVALID_CONSTANT"; + ERROR[ERROR["INVALID_VERSION"] = 9] = "INVALID_VERSION"; + ERROR[ERROR["INVALID_HEADER_TOKEN"] = 10] = "INVALID_HEADER_TOKEN"; + ERROR[ERROR["INVALID_CONTENT_LENGTH"] = 11] = "INVALID_CONTENT_LENGTH"; + ERROR[ERROR["INVALID_CHUNK_SIZE"] = 12] = "INVALID_CHUNK_SIZE"; + ERROR[ERROR["INVALID_STATUS"] = 13] = "INVALID_STATUS"; + ERROR[ERROR["INVALID_EOF_STATE"] = 14] = "INVALID_EOF_STATE"; + ERROR[ERROR["INVALID_TRANSFER_ENCODING"] = 15] = "INVALID_TRANSFER_ENCODING"; + ERROR[ERROR["CB_MESSAGE_BEGIN"] = 16] = "CB_MESSAGE_BEGIN"; + ERROR[ERROR["CB_HEADERS_COMPLETE"] = 17] = "CB_HEADERS_COMPLETE"; + ERROR[ERROR["CB_MESSAGE_COMPLETE"] = 18] = "CB_MESSAGE_COMPLETE"; + ERROR[ERROR["CB_CHUNK_HEADER"] = 19] = "CB_CHUNK_HEADER"; + ERROR[ERROR["CB_CHUNK_COMPLETE"] = 20] = "CB_CHUNK_COMPLETE"; + ERROR[ERROR["PAUSED"] = 21] = "PAUSED"; + ERROR[ERROR["PAUSED_UPGRADE"] = 22] = "PAUSED_UPGRADE"; + ERROR[ERROR["PAUSED_H2_UPGRADE"] = 23] = "PAUSED_H2_UPGRADE"; + ERROR[ERROR["USER"] = 24] = "USER"; + })(exports$1.ERROR || (exports$1.ERROR = {})); + (function (TYPE) { + TYPE[TYPE["BOTH"] = 0] = "BOTH"; + TYPE[TYPE["REQUEST"] = 1] = "REQUEST"; + TYPE[TYPE["RESPONSE"] = 2] = "RESPONSE"; + })(exports$1.TYPE || (exports$1.TYPE = {})); + (function (FLAGS) { + FLAGS[FLAGS["CONNECTION_KEEP_ALIVE"] = 1] = "CONNECTION_KEEP_ALIVE"; + FLAGS[FLAGS["CONNECTION_CLOSE"] = 2] = "CONNECTION_CLOSE"; + FLAGS[FLAGS["CONNECTION_UPGRADE"] = 4] = "CONNECTION_UPGRADE"; + FLAGS[FLAGS["CHUNKED"] = 8] = "CHUNKED"; + FLAGS[FLAGS["UPGRADE"] = 16] = "UPGRADE"; + FLAGS[FLAGS["CONTENT_LENGTH"] = 32] = "CONTENT_LENGTH"; + FLAGS[FLAGS["SKIPBODY"] = 64] = "SKIPBODY"; + FLAGS[FLAGS["TRAILING"] = 128] = "TRAILING"; + // 1 << 8 is unused + FLAGS[FLAGS["TRANSFER_ENCODING"] = 512] = "TRANSFER_ENCODING"; + })(exports$1.FLAGS || (exports$1.FLAGS = {})); + (function (LENIENT_FLAGS) { + LENIENT_FLAGS[LENIENT_FLAGS["HEADERS"] = 1] = "HEADERS"; + LENIENT_FLAGS[LENIENT_FLAGS["CHUNKED_LENGTH"] = 2] = "CHUNKED_LENGTH"; + LENIENT_FLAGS[LENIENT_FLAGS["KEEP_ALIVE"] = 4] = "KEEP_ALIVE"; + })(exports$1.LENIENT_FLAGS || (exports$1.LENIENT_FLAGS = {})); + var METHODS; + (function (METHODS) { + METHODS[METHODS["DELETE"] = 0] = "DELETE"; + METHODS[METHODS["GET"] = 1] = "GET"; + METHODS[METHODS["HEAD"] = 2] = "HEAD"; + METHODS[METHODS["POST"] = 3] = "POST"; + METHODS[METHODS["PUT"] = 4] = "PUT"; + /* pathological */ + METHODS[METHODS["CONNECT"] = 5] = "CONNECT"; + METHODS[METHODS["OPTIONS"] = 6] = "OPTIONS"; + METHODS[METHODS["TRACE"] = 7] = "TRACE"; + /* WebDAV */ + METHODS[METHODS["COPY"] = 8] = "COPY"; + METHODS[METHODS["LOCK"] = 9] = "LOCK"; + METHODS[METHODS["MKCOL"] = 10] = "MKCOL"; + METHODS[METHODS["MOVE"] = 11] = "MOVE"; + METHODS[METHODS["PROPFIND"] = 12] = "PROPFIND"; + METHODS[METHODS["PROPPATCH"] = 13] = "PROPPATCH"; + METHODS[METHODS["SEARCH"] = 14] = "SEARCH"; + METHODS[METHODS["UNLOCK"] = 15] = "UNLOCK"; + METHODS[METHODS["BIND"] = 16] = "BIND"; + METHODS[METHODS["REBIND"] = 17] = "REBIND"; + METHODS[METHODS["UNBIND"] = 18] = "UNBIND"; + METHODS[METHODS["ACL"] = 19] = "ACL"; + /* subversion */ + METHODS[METHODS["REPORT"] = 20] = "REPORT"; + METHODS[METHODS["MKACTIVITY"] = 21] = "MKACTIVITY"; + METHODS[METHODS["CHECKOUT"] = 22] = "CHECKOUT"; + METHODS[METHODS["MERGE"] = 23] = "MERGE"; + /* upnp */ + METHODS[METHODS["M-SEARCH"] = 24] = "M-SEARCH"; + METHODS[METHODS["NOTIFY"] = 25] = "NOTIFY"; + METHODS[METHODS["SUBSCRIBE"] = 26] = "SUBSCRIBE"; + METHODS[METHODS["UNSUBSCRIBE"] = 27] = "UNSUBSCRIBE"; + /* RFC-5789 */ + METHODS[METHODS["PATCH"] = 28] = "PATCH"; + METHODS[METHODS["PURGE"] = 29] = "PURGE"; + /* CalDAV */ + METHODS[METHODS["MKCALENDAR"] = 30] = "MKCALENDAR"; + /* RFC-2068, section 19.6.1.2 */ + METHODS[METHODS["LINK"] = 31] = "LINK"; + METHODS[METHODS["UNLINK"] = 32] = "UNLINK"; + /* icecast */ + METHODS[METHODS["SOURCE"] = 33] = "SOURCE"; + /* RFC-7540, section 11.6 */ + METHODS[METHODS["PRI"] = 34] = "PRI"; + /* RFC-2326 RTSP */ + METHODS[METHODS["DESCRIBE"] = 35] = "DESCRIBE"; + METHODS[METHODS["ANNOUNCE"] = 36] = "ANNOUNCE"; + METHODS[METHODS["SETUP"] = 37] = "SETUP"; + METHODS[METHODS["PLAY"] = 38] = "PLAY"; + METHODS[METHODS["PAUSE"] = 39] = "PAUSE"; + METHODS[METHODS["TEARDOWN"] = 40] = "TEARDOWN"; + METHODS[METHODS["GET_PARAMETER"] = 41] = "GET_PARAMETER"; + METHODS[METHODS["SET_PARAMETER"] = 42] = "SET_PARAMETER"; + METHODS[METHODS["REDIRECT"] = 43] = "REDIRECT"; + METHODS[METHODS["RECORD"] = 44] = "RECORD"; + /* RAOP */ + METHODS[METHODS["FLUSH"] = 45] = "FLUSH"; + })(METHODS = exports$1.METHODS || (exports$1.METHODS = {})); + exports$1.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$1.METHODS_ICE = [ + METHODS.SOURCE, + ]; + exports$1.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$1.METHOD_MAP = utils_1.enumToMap(METHODS); + exports$1.H_METHOD_MAP = {}; + Object.keys(exports$1.METHOD_MAP).forEach((key) => { + if (/^H/.test(key)) { + exports$1.H_METHOD_MAP[key] = exports$1.METHOD_MAP[key]; + } + }); + (function (FINISH) { + FINISH[FINISH["SAFE"] = 0] = "SAFE"; + FINISH[FINISH["SAFE_WITH_CB"] = 1] = "SAFE_WITH_CB"; + FINISH[FINISH["UNSAFE"] = 2] = "UNSAFE"; + })(exports$1.FINISH || (exports$1.FINISH = {})); + exports$1.ALPHA = []; + for (let i = 'A'.charCodeAt(0); i <= 'Z'.charCodeAt(0); i++) { + // Upper case + exports$1.ALPHA.push(String.fromCharCode(i)); + // Lower case + exports$1.ALPHA.push(String.fromCharCode(i + 0x20)); + } + exports$1.NUM_MAP = { + 0: 0, 1: 1, 2: 2, 3: 3, 4: 4, + 5: 5, 6: 6, 7: 7, 8: 8, 9: 9, + }; + exports$1.HEX_MAP = { + 0: 0, 1: 1, 2: 2, 3: 3, 4: 4, + 5: 5, 6: 6, 7: 7, 8: 8, 9: 9, + A: 0XA, B: 0XB, C: 0XC, D: 0XD, E: 0XE, F: 0XF, + a: 0xa, b: 0xb, c: 0xc, d: 0xd, e: 0xe, f: 0xf, + }; + exports$1.NUM = [ + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', + ]; + exports$1.ALPHANUM = exports$1.ALPHA.concat(exports$1.NUM); + exports$1.MARK = ['-', '_', '.', '!', '~', '*', '\'', '(', ')']; + exports$1.USERINFO_CHARS = exports$1.ALPHANUM + .concat(exports$1.MARK) + .concat(['%', ';', ':', '&', '=', '+', '$', ',']); + // TODO(indutny): use RFC + exports$1.STRICT_URL_CHAR = [ + '!', '"', '$', '%', '&', '\'', + '(', ')', '*', '+', ',', '-', '.', '/', + ':', ';', '<', '=', '>', + '@', '[', '\\', ']', '^', '_', + '`', + '{', '|', '}', '~', + ].concat(exports$1.ALPHANUM); + exports$1.URL_CHAR = exports$1.STRICT_URL_CHAR + .concat(['\t', '\f']); + // All characters with 0x80 bit set to 1 + for (let i = 0x80; i <= 0xff; i++) { + exports$1.URL_CHAR.push(i); + } + exports$1.HEX = exports$1.NUM.concat(['a', 'b', 'c', 'd', 'e', 'f', 'A', 'B', 'C', 'D', 'E', 'F']); + /* Tokens as defined by rfc 2616. Also lowercases them. + * token = 1* + * separators = "(" | ")" | "<" | ">" | "@" + * | "," | ";" | ":" | "\" | <"> + * | "/" | "[" | "]" | "?" | "=" + * | "{" | "}" | SP | HT + */ + exports$1.STRICT_TOKEN = [ + '!', '#', '$', '%', '&', '\'', + '*', '+', '-', '.', + '^', '_', '`', + '|', '~', + ].concat(exports$1.ALPHANUM); + exports$1.TOKEN = exports$1.STRICT_TOKEN.concat([' ']); + /* + * Verify that a char is a valid visible (printable) US-ASCII + * character or %x80-FF + */ + exports$1.HEADER_CHARS = ['\t']; + for (let i = 32; i <= 255; i++) { + if (i !== 127) { + exports$1.HEADER_CHARS.push(i); + } + } + // ',' = \x44 + exports$1.CONNECTION_TOKEN_CHARS = exports$1.HEADER_CHARS.filter((c) => c !== 44); + exports$1.MAJOR = exports$1.NUM_MAP; + exports$1.MINOR = exports$1.MAJOR; + var HEADER_STATE; + (function (HEADER_STATE) { + HEADER_STATE[HEADER_STATE["GENERAL"] = 0] = "GENERAL"; + HEADER_STATE[HEADER_STATE["CONNECTION"] = 1] = "CONNECTION"; + HEADER_STATE[HEADER_STATE["CONTENT_LENGTH"] = 2] = "CONTENT_LENGTH"; + HEADER_STATE[HEADER_STATE["TRANSFER_ENCODING"] = 3] = "TRANSFER_ENCODING"; + HEADER_STATE[HEADER_STATE["UPGRADE"] = 4] = "UPGRADE"; + HEADER_STATE[HEADER_STATE["CONNECTION_KEEP_ALIVE"] = 5] = "CONNECTION_KEEP_ALIVE"; + HEADER_STATE[HEADER_STATE["CONNECTION_CLOSE"] = 6] = "CONNECTION_CLOSE"; + HEADER_STATE[HEADER_STATE["CONNECTION_UPGRADE"] = 7] = "CONNECTION_UPGRADE"; + HEADER_STATE[HEADER_STATE["TRANSFER_ENCODING_CHUNKED"] = 8] = "TRANSFER_ENCODING_CHUNKED"; + })(HEADER_STATE = exports$1.HEADER_STATE || (exports$1.HEADER_STATE = {})); + exports$1.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, + }; + + } (constants$3)); + return constants$3; +} - if (serializedOrigin) { - // 2. Append (`Origin`, serializedOrigin) to request’s header list. - request.headersList.append('origin', serializedOrigin); - } - } - } +var llhttpWasm; +var hasRequiredLlhttpWasm; - function coarsenedSharedCurrentTime (crossOriginIsolatedCapability) { - // TODO - return performance.now() - } +function requireLlhttpWasm () { + if (hasRequiredLlhttpWasm) return llhttpWasm; + hasRequiredLlhttpWasm = 1; - // https://fetch.spec.whatwg.org/#create-an-opaque-timing-info - 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 - } - } + const { Buffer } = require$$0$2; - // https://html.spec.whatwg.org/multipage/origin.html#policy-container - function makePolicyContainer () { - // Note: the fetch spec doesn't make use of embedder policy or CSP list - return { - referrerPolicy: 'strict-origin-when-cross-origin' - } - } + llhttpWasm = Buffer.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'); + return llhttpWasm; +} - // https://html.spec.whatwg.org/multipage/origin.html#clone-a-policy-container - function clonePolicyContainer (policyContainer) { - return { - referrerPolicy: policyContainer.referrerPolicy - } - } +var llhttp_simdWasm; +var hasRequiredLlhttp_simdWasm; - // https://w3c.github.io/webappsec-referrer-policy/#determine-requests-referrer - function determineRequestsReferrer (request) { - // 1. Let policy be request's referrer policy. - const policy = request.referrerPolicy; +function requireLlhttp_simdWasm () { + if (hasRequiredLlhttp_simdWasm) return llhttp_simdWasm; + hasRequiredLlhttp_simdWasm = 1; - // Note: policy cannot (shouldn't) be null or an empty string. - assert(policy); + const { Buffer } = require$$0$2; - // 2. Let environment be request’s client. + llhttp_simdWasm = Buffer.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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JSIARQ0RIAJB5QA2AhwgAiABNgIUIAIgADYCDEEAIQMMtAELIAIoAgQhACACQQA2AgQgAiAAIAEQJSIARQ0gIAJB0wA2AhwgAiABNgIUIAIgADYCDEEAIQMMswELIAIoAgQhACACQQA2AgQgAiAAIAEQJSIARQ0iIAJB0gA2AhwgAiABNgIUIAIgADYCDEEAIQMMsgELIAIoAgQhACACQQA2AgQgAiAAIAEQJSIARQ0OIAJB5QA2AhwgAiABNgIUIAIgADYCDEEAIQMMsQELIAIoAgQhACACQQA2AgQgAiAAIAEQJSIARQ0dIAJB0wA2AhwgAiABNgIUIAIgADYCDEEAIQMMsAELIAIoAgQhACACQQA2AgQgAiAAIAEQJSIARQ0fIAJB0gA2AhwgAiABNgIUIAIgADYCDEEAIQMMrwELIABBP0cNASABQQFqCyEBQQUhAwyUAQtBACEDIAJBADYCHCACIAE2AhQgAkH9EjYCECACQQc2AgwMrAELIAJBADYCHCACIAE2AhQgAkHcCDYCECACQQc2AgxBACEDDKsBCyACKAIEIQAgAkEANgIEIAIgACABECUiAEUNByACQeUANgIcIAIgATYCFCACIAA2AgxBACEDDKoBCyACKAIEIQAgAkEANgIEIAIgACABECUiAEUNFiACQdMANgIcIAIgATYCFCACIAA2AgxBACEDDKkBCyACKAIEIQAgAkEANgIEIAIgACABECUiAEUNGCACQdIANgIcIAIgATYCFCACIAA2AgxBACEDDKgBCyACQQA2AhwgAiABNgIUIAJBxgo2AhAgAkEHNgIMQQAhAwynAQsgAigCBCEAIAJBADYCBCACIAAgARAlIgBFDQMgAkHlADYCHCACIAE2AhQgAiAANgIMQQAhAwymAQsgAigCBCEAIAJBADYCBCACIAAgARAlIgBFDRIgAkHTADYCHCACIAE2AhQgAiAANgIMQQAhAwylAQsgAigCBCEAIAJBADYCBCACIAAgARAlIgBFDRQgAkHSADYCHCACIAE2AhQgAiAANgIMQQAhAwykAQsgAigCBCEAIAJBADYCBCACIAAgARAlIgBFDQAgAkHlADYCHCACIAE2AhQgAiAANgIMQQAhAwyjAQtB1QAhAwyJAQsgAEEVRwRAIAJBADYCHCACIAE2AhQgAkG5DTYCECACQRo2AgxBACEDDKIBCyACQeQANgIcIAIgATYCFCACQeMXNgIQIAJBFTYCDEEAIQMMoQELIAJBADYCACAGQQFqIQEgAi0AKSIAQSNrQQtJDQQCQCAAQQZLDQBBASAAdEHKAHFFDQAMBQtBACEDIAJBADYCHCACIAE2AhQgAkH3CTYCECACQQg2AgwMoAELIAJBADYCACAGQQFqIQEgAi0AKUEhRg0DIAJBADYCHCACIAE2AhQgAkGbCjYCECACQQg2AgxBACEDDJ8BCyACQQA2AgALQQAhAyACQQA2AhwgAiABNgIUIAJBkDM2AhAgAkEINgIMDJ0BCyACQQA2AgAgBkEBaiEBIAItAClBI0kNACACQQA2AhwgAiABNgIUIAJB0wk2AhAgAkEINgIMQQAhAwycAQtB0QAhAwyCAQsgAS0AAEEwayIAQf8BcUEKSQRAIAIgADoAKiABQQFqIQFBzwAhAwyCAQsgAigCBCEAIAJBADYCBCACIAAgARAoIgBFDYYBIAJB3gA2AhwgAiABNgIUIAIgADYCDEEAIQMMmgELIAIoAgQhACACQQA2AgQgAiAAIAEQKCIARQ2GASACQdwANgIcIAIgATYCFCACIAA2AgxBACEDDJkBCyACKAIEIQAgAkEANgIEIAIgACAFECgiAEUEQCAFIQEMhwELIAJB2gA2AhwgAiAFNgIUIAIgADYCDAyYAQtBACEBQQEhAwsgAiADOgArIAVBAWohAwJAAkACQCACLQAtQRBxDQACQAJAAkAgAi0AKg4DAQACBAsgBkUNAwwCCyAADQEMAgsgAUUNAQsgAigCBCEAIAJBADYCBCACIAAgAxAoIgBFBEAgAyEBDAILIAJB2AA2AhwgAiADNgIUIAIgADYCDEEAIQMMmAELIAIoAgQhACACQQA2AgQgAiAAIAMQKCIARQRAIAMhAQyHAQsgAkHZADYCHCACIAM2AhQgAiAANgIMQQAhAwyXAQtBzAAhAwx9CyAAQRVHBEAgAkEANgIcIAIgATYCFCACQZQNNgIQIAJBITYCDEEAIQMMlgELIAJB1wA2AhwgAiABNgIUIAJByRc2AhAgAkEVNgIMQQAhAwyVAQtBACEDIAJBADYCHCACIAE2AhQgAkGAETYCECACQQk2AgwMlAELIAIoAgQhACACQQA2AgQgAiAAIAEQJSIARQ0AIAJB0wA2AhwgAiABNgIUIAIgADYCDEEAIQMMkwELQckAIQMMeQsgAkEANgIcIAIgATYCFCACQcEoNgIQIAJBBzYCDCACQQA2AgBBACEDDJEBCyACKAIEIQBBACEDIAJBADYCBCACIAAgARAlIgBFDQAgAkHSADYCHCACIAE2AhQgAiAANgIMDJABC0HIACEDDHYLIAJBADYCACAFIQELIAJBgBI7ASogAUEBaiEBQQAhAAJAIAIoAjgiA0UNACADKAIwIgNFDQAgAiADEQAAIQALIAANAQtBxwAhAwxzCyAAQRVGBEAgAkHRADYCHCACIAE2AhQgAkHjFzYCECACQRU2AgxBACEDDIwBC0EAIQMgAkEANgIcIAIgATYCFCACQbkNNgIQIAJBGjYCDAyLAQtBACEDIAJBADYCHCACIAE2AhQgAkGgGTYCECACQR42AgwMigELIAEtAABBOkYEQCACKAIEIQBBACEDIAJBADYCBCACIAAgARApIgBFDQEgAkHDADYCHCACIAA2AgwgAiABQQFqNgIUDIoBC0EAIQMgAkEANgIcIAIgATYCFCACQbERNgIQIAJBCjYCDAyJAQsgAUEBaiEBQTshAwxvCyACQcMANgIcIAIgADYCDCACIAFBAWo2AhQMhwELQQAhAyACQQA2AhwgAiABNgIUIAJB8A42AhAgAkEcNgIMDIYBCyACIAIvATBBEHI7ATAMZgsCQCACLwEwIgBBCHFFDQAgAi0AKEEBRw0AIAItAC1BCHFFDQMLIAIgAEH3+wNxQYAEcjsBMAwECyABIARHBEACQANAIAEtAABBMGsiAEH/AXFBCk8EQEE1IQMMbgsgAikDICIKQpmz5syZs+bMGVYNASACIApCCn4iCjcDICAKIACtQv8BgyILQn+FVg0BIAIgCiALfDcDICAEIAFBAWoiAUcNAAtBOSEDDIUBCyACKAIEIQBBACEDIAJBADYCBCACIAAgAUEBaiIBECoiAA0MDHcLQTkhAwyDAQsgAi0AMEEgcQ0GQcUBIQMMaQtBACEDIAJBADYCBCACIAEgARAqIgBFDQQgAkE6NgIcIAIgADYCDCACIAFBAWo2AhQMgQELIAItAChBAUcNACACLQAtQQhxRQ0BC0E3IQMMZgsgAigCBCEAQQAhAyACQQA2AgQgAiAAIAEQKiIABEAgAkE7NgIcIAIgADYCDCACIAFBAWo2AhQMfwsgAUEBaiEBDG4LIAJBCDoALAwECyABQQFqIQEMbQtBACEDIAJBADYCHCACIAE2AhQgAkHkEjYCECACQQQ2AgwMewsgAigCBCEAQQAhAyACQQA2AgQgAiAAIAEQKiIARQ1sIAJBNzYCHCACIAE2AhQgAiAANgIMDHoLIAIgAi8BMEEgcjsBMAtBMCEDDF8LIAJBNjYCHCACIAE2AhQgAiAANgIMDHcLIABBLEcNASABQQFqIQBBASEBAkACQAJAAkACQCACLQAsQQVrDgQDAQIEAAsgACEBDAQLQQIhAQwBC0EEIQELIAJBAToALCACIAIvATAgAXI7ATAgACEBDAELIAIgAi8BMEEIcjsBMCAAIQELQTkhAwxcCyACQQA6ACwLQTQhAwxaCyABIARGBEBBLSEDDHMLAkACQANAAkAgAS0AAEEKaw4EAgAAAwALIAQgAUEBaiIBRw0AC0EtIQMMdAsgAigCBCEAQQAhAyACQQA2AgQgAiAAIAEQKiIARQ0CIAJBLDYCHCACIAE2AhQgAiAANgIMDHMLIAIoAgQhAEEAIQMgAkEANgIEIAIgACABECoiAEUEQCABQQFqIQEMAgsgAkEsNgIcIAIgADYCDCACIAFBAWo2AhQMcgsgAS0AAEENRgRAIAIoAgQhAEEAIQMgAkEANgIEIAIgACABECoiAEUEQCABQQFqIQEMAgsgAkEsNgIcIAIgADYCDCACIAFBAWo2AhQMcgsgAi0ALUEBcQRAQcQBIQMMWQsgAigCBCEAQQAhAyACQQA2AgQgAiAAIAEQKiIADQEMZQtBLyEDDFcLIAJBLjYCHCACIAE2AhQgAiAANgIMDG8LQQAhAyACQQA2AhwgAiABNgIUIAJB8BQ2AhAgAkEDNgIMDG4LQQEhAwJAAkACQAJAIAItACxBBWsOBAMBAgAECyACIAIvATBBCHI7ATAMAwtBAiEDDAELQQQhAwsgAkEBOgAsIAIgAi8BMCADcjsBMAtBKiEDDFMLQQAhAyACQQA2AhwgAiABNgIUIAJB4Q82AhAgAkEKNgIMDGsLQQEhAwJAAkACQAJAAkACQCACLQAsQQJrDgcFBAQDAQIABAsgAiACLwEwQQhyOwEwDAMLQQIhAwwBC0EEIQMLIAJBAToALCACIAIvATAgA3I7ATALQSshAwxSC0EAIQMgAkEANgIcIAIgATYCFCACQasSNgIQIAJBCzYCDAxqC0EAIQMgAkEANgIcIAIgATYCFCACQf0NNgIQIAJBHTYCDAxpCyABIARHBEADQCABLQAAQSBHDUggBCABQQFqIgFHDQALQSUhAwxpC0ElIQMMaAsgAi0ALUEBcQRAQcMBIQMMTwsgAigCBCEAQQAhAyACQQA2AgQgAiAAIAEQKSIABEAgAkEmNgIcIAIgADYCDCACIAFBAWo2AhQMaAsgAUEBaiEBDFwLIAFBAWohASACLwEwIgBBgAFxBEBBACEAAkAgAigCOCIDRQ0AIAMoAlQiA0UNACACIAMRAAAhAAsgAEUNBiAAQRVHDR8gAkEFNgIcIAIgATYCFCACQfkXNgIQIAJBFTYCDEEAIQMMZwsCQCAAQaAEcUGgBEcNACACLQAtQQJxDQBBACEDIAJBADYCHCACIAE2AhQgAkGWEzYCECACQQQ2AgwMZwsgAgJ/IAIvATBBFHFBFEYEQEEBIAItAChBAUYNARogAi8BMkHlAEYMAQsgAi0AKUEFRgs6AC5BACEAAkAgAigCOCIDRQ0AIAMoAiQiA0UNACACIAMRAAAhAAsCQAJAAkACQAJAIAAOFgIBAAQEBAQEBAQEBAQEBAQEBAQEBAMECyACQQE6AC4LIAIgAi8BMEHAAHI7ATALQSchAwxPCyACQSM2AhwgAiABNgIUIAJBpRY2AhAgAkEVNgIMQQAhAwxnC0EAIQMgAkEANgIcIAIgATYCFCACQdULNgIQIAJBETYCDAxmC0EAIQACQCACKAI4IgNFDQAgAygCLCIDRQ0AIAIgAxEAACEACyAADQELQQ4hAwxLCyAAQRVGBEAgAkECNgIcIAIgATYCFCACQbAYNgIQIAJBFTYCDEEAIQMMZAtBACEDIAJBADYCHCACIAE2AhQgAkGnDjYCECACQRI2AgwMYwtBACEDIAJBADYCHCACIAE2AhQgAkGqHDYCECACQQ82AgwMYgsgAigCBCEAQQAhAyACQQA2AgQgAiAAIAEgCqdqIgEQKyIARQ0AIAJBBTYCHCACIAE2AhQgAiAANgIMDGELQQ8hAwxHC0EAIQMgAkEANgIcIAIgATYCFCACQc0TNgIQIAJBDDYCDAxfC0IBIQoLIAFBAWohAQJAIAIpAyAiC0L//////////w9YBEAgAiALQgSGIAqENwMgDAELQQAhAyACQQA2AhwgAiABNgIUIAJBrQk2AhAgAkEMNgIMDF4LQSQhAwxEC0EAIQMgAkEANgIcIAIgATYCFCACQc0TNgIQIAJBDDYCDAxcCyACKAIEIQBBACEDIAJBADYCBCACIAAgARAsIgBFBEAgAUEBaiEBDFILIAJBFzYCHCACIAA2AgwgAiABQQFqNgIUDFsLIAIoAgQhAEEAIQMgAkEANgIEAkAgAiAAIAEQLCIARQRAIAFBAWohAQwBCyACQRY2AhwgAiAANgIMIAIgAUEBajYCFAxbC0EfIQMMQQtBACEDIAJBADYCHCACIAE2AhQgAkGaDzYCECACQSI2AgwMWQsgAigCBCEAQQAhAyACQQA2AgQgAiAAIAEQLSIARQRAIAFBAWohAQxQCyACQRQ2AhwgAiAANgIMIAIgAUEBajYCFAxYCyACKAIEIQBBACEDIAJBADYCBAJAIAIgACABEC0iAEUEQCABQQFqIQEMAQsgAkETNgIcIAIgADYCDCACIAFBAWo2AhQMWAtBHiEDDD4LQQAhAyACQQA2AhwgAiABNgIUIAJBxgw2AhAgAkEjNgIMDFYLIAIoAgQhAEEAIQMgAkEANgIEIAIgACABEC0iAEUEQCABQQFqIQEMTgsgAkERNgIcIAIgADYCDCACIAFBAWo2AhQMVQsgAkEQNgIcIAIgATYCFCACIAA2AgwMVAtBACEDIAJBADYCHCACIAE2AhQgAkHGDDYCECACQSM2AgwMUwtBACEDIAJBADYCHCACIAE2AhQgAkHAFTYCECACQQI2AgwMUgsgAigCBCEAQQAhAyACQQA2AgQCQCACIAAgARAtIgBFBEAgAUEBaiEBDAELIAJBDjYCHCACIAA2AgwgAiABQQFqNgIUDFILQRshAww4C0EAIQMgAkEANgIcIAIgATYCFCACQcYMNgIQIAJBIzYCDAxQCyACKAIEIQBBACEDIAJBADYCBAJAIAIgACABECwiAEUEQCABQQFqIQEMAQsgAkENNgIcIAIgADYCDCACIAFBAWo2AhQMUAtBGiEDDDYLQQAhAyACQQA2AhwgAiABNgIUIAJBmg82AhAgAkEiNgIMDE4LIAIoAgQhAEEAIQMgAkEANgIEAkAgAiAAIAEQLCIARQRAIAFBAWohAQwBCyACQQw2AhwgAiAANgIMIAIgAUEBajYCFAxOC0EZIQMMNAtBACEDIAJBADYCHCACIAE2AhQgAkGaDzYCECACQSI2AgwMTAsgAEEVRwRAQQAhAyACQQA2AhwgAiABNgIUIAJBgww2AhAgAkETNgIMDEwLIAJBCjYCHCACIAE2AhQgAkHkFjYCECACQRU2AgxBACEDDEsLIAIoAgQhAEEAIQMgAkEANgIEIAIgACABIAqnaiIBECsiAARAIAJBBzYCHCACIAE2AhQgAiAANgIMDEsLQRMhAwwxCyAAQRVHBEBBACEDIAJBADYCHCACIAE2AhQgAkHaDTYCECACQRQ2AgwMSgsgAkEeNgIcIAIgATYCFCACQfkXNgIQIAJBFTYCDEEAIQMMSQtBACEAAkAgAigCOCIDRQ0AIAMoAiwiA0UNACACIAMRAAAhAAsgAEUNQSAAQRVGBEAgAkEDNgIcIAIgATYCFCACQbAYNgIQIAJBFTYCDEEAIQMMSQtBACEDIAJBADYCHCACIAE2AhQgAkGnDjYCECACQRI2AgwMSAtBACEDIAJBADYCHCACIAE2AhQgAkHaDTYCECACQRQ2AgwMRwtBACEDIAJBADYCHCACIAE2AhQgAkGnDjYCECACQRI2AgwMRgsgAkEAOgAvIAItAC1BBHFFDT8LIAJBADoALyACQQE6ADRBACEDDCsLQQAhAyACQQA2AhwgAkHkETYCECACQQc2AgwgAiABQQFqNgIUDEMLAkADQAJAIAEtAABBCmsOBAACAgACCyAEIAFBAWoiAUcNAAtB3QEhAwxDCwJAAkAgAi0ANEEBRw0AQQAhAAJAIAIoAjgiA0UNACADKAJYIgNFDQAgAiADEQAAIQALIABFDQAgAEEVRw0BIAJB3AE2AhwgAiABNgIUIAJB1RY2AhAgAkEVNgIMQQAhAwxEC0HBASEDDCoLIAJBADYCHCACIAE2AhQgAkHpCzYCECACQR82AgxBACEDDEILAkACQCACLQAoQQFrDgIEAQALQcABIQMMKQtBuQEhAwwoCyACQQI6AC9BACEAAkAgAigCOCIDRQ0AIAMoAgAiA0UNACACIAMRAAAhAAsgAEUEQEHCASEDDCgLIABBFUcEQCACQQA2AhwgAiABNgIUIAJBpAw2AhAgAkEQNgIMQQAhAwxBCyACQdsBNgIcIAIgATYCFCACQfoWNgIQIAJBFTYCDEEAIQMMQAsgASAERgRAQdoBIQMMQAsgAS0AAEHIAEYNASACQQE6ACgLQawBIQMMJQtBvwEhAwwkCyABIARHBEAgAkEQNgIIIAIgATYCBEG+ASEDDCQLQdkBIQMMPAsgASAERgRAQdgBIQMMPAsgAS0AAEHIAEcNBCABQQFqIQFBvQEhAwwiCyABIARGBEBB1wEhAww7CwJAAkAgAS0AAEHFAGsOEAAFBQUFBQUFBQUFBQUFBQEFCyABQQFqIQFBuwEhAwwiCyABQQFqIQFBvAEhAwwhC0HWASEDIAEgBEYNOSACKAIAIgAgBCABa2ohBSABIABrQQJqIQYCQANAIAEtAAAgAEGD0ABqLQAARw0DIABBAkYNASAAQQFqIQAgBCABQQFqIgFHDQALIAIgBTYCAAw6CyACKAIEIQAgAkIANwMAIAIgACAGQQFqIgEQJyIARQRAQcYBIQMMIQsgAkHVATYCHCACIAE2AhQgAiAANgIMQQAhAww5C0HUASEDIAEgBEYNOCACKAIAIgAgBCABa2ohBSABIABrQQFqIQYCQANAIAEtAAAgAEGB0ABqLQAARw0CIABBAUYNASAAQQFqIQAgBCABQQFqIgFHDQALIAIgBTYCAAw5CyACQYEEOwEoIAIoAgQhACACQgA3AwAgAiAAIAZBAWoiARAnIgANAwwCCyACQQA2AgALQQAhAyACQQA2AhwgAiABNgIUIAJB2Bs2AhAgAkEINgIMDDYLQboBIQMMHAsgAkHTATYCHCACIAE2AhQgAiAANgIMQQAhAww0C0EAIQACQCACKAI4IgNFDQAgAygCOCIDRQ0AIAIgAxEAACEACyAARQ0AIABBFUYNASACQQA2AhwgAiABNgIUIAJBzA42AhAgAkEgNgIMQQAhAwwzC0HkACEDDBkLIAJB+AA2AhwgAiABNgIUIAJByhg2AhAgAkEVNgIMQQAhAwwxC0HSASEDIAQgASIARg0wIAQgAWsgAigCACIBaiEFIAAgAWtBBGohBgJAA0AgAC0AACABQfzPAGotAABHDQEgAUEERg0DIAFBAWohASAEIABBAWoiAEcNAAsgAiAFNgIADDELIAJBADYCHCACIAA2AhQgAkGQMzYCECACQQg2AgwgAkEANgIAQQAhAwwwCyABIARHBEAgAkEONgIIIAIgATYCBEG3ASEDDBcLQdEBIQMMLwsgAkEANgIAIAZBAWohAQtBuAEhAwwUCyABIARGBEBB0AEhAwwtCyABLQAAQTBrIgBB/wFxQQpJBEAgAiAAOgAqIAFBAWohAUG2ASEDDBQLIAIoAgQhACACQQA2AgQgAiAAIAEQKCIARQ0UIAJBzwE2AhwgAiABNgIUIAIgADYCDEEAIQMMLAsgASAERgRAQc4BIQMMLAsCQCABLQAAQS5GBEAgAUEBaiEBDAELIAIoAgQhACACQQA2AgQgAiAAIAEQKCIARQ0VIAJBzQE2AhwgAiABNgIUIAIgADYCDEEAIQMMLAtBtQEhAwwSCyAEIAEiBUYEQEHMASEDDCsLQQAhAEEBIQFBASEGQQAhAwJAAkACQAJAAkACfwJAAkACQAJAAkACQAJAIAUtAABBMGsOCgoJAAECAwQFBggLC0ECDAYLQQMMBQtBBAwEC0EFDAMLQQYMAgtBBwwBC0EICyEDQQAhAUEAIQYMAgtBCSEDQQEhAEEAIQFBACEGDAELQQAhAUEBIQMLIAIgAzoAKyAFQQFqIQMCQAJAIAItAC1BEHENAAJAAkACQCACLQAqDgMBAAIECyAGRQ0DDAILIAANAQwCCyABRQ0BCyACKAIEIQAgAkEANgIEIAIgACADECgiAEUEQCADIQEMAwsgAkHJATYCHCACIAM2AhQgAiAANgIMQQAhAwwtCyACKAIEIQAgAkEANgIEIAIgACADECgiAEUEQCADIQEMGAsgAkHKATYCHCACIAM2AhQgAiAANgIMQQAhAwwsCyACKAIEIQAgAkEANgIEIAIgACAFECgiAEUEQCAFIQEMFgsgAkHLATYCHCACIAU2AhQgAiAANgIMDCsLQbQBIQMMEQtBACEAAkAgAigCOCIDRQ0AIAMoAjwiA0UNACACIAMRAAAhAAsCQCAABEAgAEEVRg0BIAJBADYCHCACIAE2AhQgAkGUDTYCECACQSE2AgxBACEDDCsLQbIBIQMMEQsgAkHIATYCHCACIAE2AhQgAkHJFzYCECACQRU2AgxBACEDDCkLIAJBADYCACAGQQFqIQFB9QAhAwwPCyACLQApQQVGBEBB4wAhAwwPC0HiACEDDA4LIAAhASACQQA2AgALIAJBADoALEEJIQMMDAsgAkEANgIAIAdBAWohAUHAACEDDAsLQQELOgAsIAJBADYCACAGQQFqIQELQSkhAwwIC0E4IQMMBwsCQCABIARHBEADQCABLQAAQYA+ai0AACIAQQFHBEAgAEECRw0DIAFBAWohAQwFCyAEIAFBAWoiAUcNAAtBPiEDDCELQT4hAwwgCwsgAkEAOgAsDAELQQshAwwEC0E6IQMMAwsgAUEBaiEBQS0hAwwCCyACIAE6ACwgAkEANgIAIAZBAWohAUEMIQMMAQsgAkEANgIAIAZBAWohAUEKIQMMAAsAC0EAIQMgAkEANgIcIAIgATYCFCACQc0QNgIQIAJBCTYCDAwXC0EAIQMgAkEANgIcIAIgATYCFCACQekKNgIQIAJBCTYCDAwWC0EAIQMgAkEANgIcIAIgATYCFCACQbcQNgIQIAJBCTYCDAwVC0EAIQMgAkEANgIcIAIgATYCFCACQZwRNgIQIAJBCTYCDAwUC0EAIQMgAkEANgIcIAIgATYCFCACQc0QNgIQIAJBCTYCDAwTC0EAIQMgAkEANgIcIAIgATYCFCACQekKNgIQIAJBCTYCDAwSC0EAIQMgAkEANgIcIAIgATYCFCACQbcQNgIQIAJBCTYCDAwRC0EAIQMgAkEANgIcIAIgATYCFCACQZwRNgIQIAJBCTYCDAwQC0EAIQMgAkEANgIcIAIgATYCFCACQZcVNgIQIAJBDzYCDAwPC0EAIQMgAkEANgIcIAIgATYCFCACQZcVNgIQIAJBDzYCDAwOC0EAIQMgAkEANgIcIAIgATYCFCACQcASNgIQIAJBCzYCDAwNC0EAIQMgAkEANgIcIAIgATYCFCACQZUJNgIQIAJBCzYCDAwMC0EAIQMgAkEANgIcIAIgATYCFCACQeEPNgIQIAJBCjYCDAwLC0EAIQMgAkEANgIcIAIgATYCFCACQfsPNgIQIAJBCjYCDAwKC0EAIQMgAkEANgIcIAIgATYCFCACQfEZNgIQIAJBAjYCDAwJC0EAIQMgAkEANgIcIAIgATYCFCACQcQUNgIQIAJBAjYCDAwIC0EAIQMgAkEANgIcIAIgATYCFCACQfIVNgIQIAJBAjYCDAwHCyACQQI2AhwgAiABNgIUIAJBnBo2AhAgAkEWNgIMQQAhAwwGC0EBIQMMBQtB1AAhAyABIARGDQQgCEEIaiEJIAIoAgAhBQJAAkAgASAERwRAIAVB2MIAaiEHIAQgBWogAWshACAFQX9zQQpqIgUgAWohBgNAIAEtAAAgBy0AAEcEQEECIQcMAwsgBUUEQEEAIQcgBiEBDAMLIAVBAWshBSAHQQFqIQcgBCABQQFqIgFHDQALIAAhBSAEIQELIAlBATYCACACIAU2AgAMAQsgAkEANgIAIAkgBzYCAAsgCSABNgIEIAgoAgwhACAIKAIIDgMBBAIACwALIAJBADYCHCACQbUaNgIQIAJBFzYCDCACIABBAWo2AhRBACEDDAILIAJBADYCHCACIAA2AhQgAkHKGjYCECACQQk2AgxBACEDDAELIAEgBEYEQEEiIQMMAQsgAkEJNgIIIAIgATYCBEEhIQMLIAhBEGokACADRQRAIAIoAgwhAAwBCyACIAM2AhxBACEAIAIoAgQiAUUNACACIAEgBCACKAIIEQEAIgFFDQAgAiAENgIUIAIgATYCDCABIQALIAALvgIBAn8gAEEAOgAAIABB3ABqIgFBAWtBADoAACAAQQA6AAIgAEEAOgABIAFBA2tBADoAACABQQJrQQA6AAAgAEEAOgADIAFBBGtBADoAAEEAIABrQQNxIgEgAGoiAEEANgIAQdwAIAFrQXxxIgIgAGoiAUEEa0EANgIAAkAgAkEJSQ0AIABBADYCCCAAQQA2AgQgAUEIa0EANgIAIAFBDGtBADYCACACQRlJDQAgAEEANgIYIABBADYCFCAAQQA2AhAgAEEANgIMIAFBEGtBADYCACABQRRrQQA2AgAgAUEYa0EANgIAIAFBHGtBADYCACACIABBBHFBGHIiAmsiAUEgSQ0AIAAgAmohAANAIABCADcDGCAAQgA3AxAgAEIANwMIIABCADcDACAAQSBqIQAgAUEgayIBQR9LDQALCwtWAQF/AkAgACgCDA0AAkACQAJAAkAgAC0ALw4DAQADAgsgACgCOCIBRQ0AIAEoAiwiAUUNACAAIAERAAAiAQ0DC0EADwsACyAAQcMWNgIQQQ4hAQsgAQsaACAAKAIMRQRAIABB0Rs2AhAgAEEVNgIMCwsUACAAKAIMQRVGBEAgAEEANgIMCwsUACAAKAIMQRZGBEAgAEEANgIMCwsHACAAKAIMCwcAIAAoAhALCQAgACABNgIQCwcAIAAoAhQLFwAgAEEkTwRAAAsgAEECdEGgM2ooAgALFwAgAEEuTwRAAAsgAEECdEGwNGooAgALvwkBAX9B6yghAQJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAIABB5ABrDvQDY2IAAWFhYWFhYQIDBAVhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhBgcICQoLDA0OD2FhYWFhEGFhYWFhYWFhYWFhEWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYRITFBUWFxgZGhthYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhHB0eHyAhIiMkJSYnKCkqKywtLi8wMTIzNDU2YTc4OTphYWFhYWFhYTthYWE8YWFhYT0+P2FhYWFhYWFhQGFhQWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYUJDREVGR0hJSktMTU5PUFFSU2FhYWFhYWFhVFVWV1hZWlthXF1hYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFeYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhX2BhC0HhJw8LQaQhDwtByywPC0H+MQ8LQcAkDwtBqyQPC0GNKA8LQeImDwtBgDAPC0G5Lw8LQdckDwtB7x8PC0HhHw8LQfofDwtB8iAPC0GoLw8LQa4yDwtBiDAPC0HsJw8LQYIiDwtBjh0PC0HQLg8LQcojDwtBxTIPC0HfHA8LQdIcDwtBxCAPC0HXIA8LQaIfDwtB7S4PC0GrMA8LQdQlDwtBzC4PC0H6Lg8LQfwrDwtB0jAPC0HxHQ8LQbsgDwtB9ysPC0GQMQ8LQdcxDwtBoi0PC0HUJw8LQeArDwtBnywPC0HrMQ8LQdUfDwtByjEPC0HeJQ8LQdQeDwtB9BwPC0GnMg8LQbEdDwtBoB0PC0G5MQ8LQbwwDwtBkiEPC0GzJg8LQeksDwtBrB4PC0HUKw8LQfcmDwtBgCYPC0GwIQ8LQf4eDwtBjSMPC0GJLQ8LQfciDwtBoDEPC0GuHw8LQcYlDwtB6B4PC0GTIg8LQcIvDwtBwx0PC0GLLA8LQeEdDwtBjS8PC0HqIQ8LQbQtDwtB0i8PC0HfMg8LQdIyDwtB8DAPC0GpIg8LQfkjDwtBmR4PC0G1LA8LQZswDwtBkjIPC0G2Kw8LQcIiDwtB+DIPC0GeJQ8LQdAiDwtBuh4PC0GBHg8LAAtB1iEhAQsgAQsWACAAIAAtAC1B/gFxIAFBAEdyOgAtCxkAIAAgAC0ALUH9AXEgAUEAR0EBdHI6AC0LGQAgACAALQAtQfsBcSABQQBHQQJ0cjoALQsZACAAIAAtAC1B9wFxIAFBAEdBA3RyOgAtCz4BAn8CQCAAKAI4IgNFDQAgAygCBCIDRQ0AIAAgASACIAFrIAMRAQAiBEF/Rw0AIABBxhE2AhBBGCEECyAECz4BAn8CQCAAKAI4IgNFDQAgAygCCCIDRQ0AIAAgASACIAFrIAMRAQAiBEF/Rw0AIABB9go2AhBBGCEECyAECz4BAn8CQCAAKAI4IgNFDQAgAygCDCIDRQ0AIAAgASACIAFrIAMRAQAiBEF/Rw0AIABB7Ro2AhBBGCEECyAECz4BAn8CQCAAKAI4IgNFDQAgAygCECIDRQ0AIAAgASACIAFrIAMRAQAiBEF/Rw0AIABBlRA2AhBBGCEECyAECz4BAn8CQCAAKAI4IgNFDQAgAygCFCIDRQ0AIAAgASACIAFrIAMRAQAiBEF/Rw0AIABBqhs2AhBBGCEECyAECz4BAn8CQCAAKAI4IgNFDQAgAygCGCIDRQ0AIAAgASACIAFrIAMRAQAiBEF/Rw0AIABB7RM2AhBBGCEECyAECz4BAn8CQCAAKAI4IgNFDQAgAygCKCIDRQ0AIAAgASACIAFrIAMRAQAiBEF/Rw0AIABB9gg2AhBBGCEECyAECz4BAn8CQCAAKAI4IgNFDQAgAygCHCIDRQ0AIAAgASACIAFrIAMRAQAiBEF/Rw0AIABBwhk2AhBBGCEECyAECz4BAn8CQCAAKAI4IgNFDQAgAygCICIDRQ0AIAAgASACIAFrIAMRAQAiBEF/Rw0AIABBlBQ2AhBBGCEECyAEC1kBAn8CQCAALQAoQQFGDQAgAC8BMiIBQeQAa0HkAEkNACABQcwBRg0AIAFBsAJGDQAgAC8BMCIAQcAAcQ0AQQEhAiAAQYgEcUGABEYNACAAQShxRSECCyACC4wBAQJ/AkACQAJAIAAtACpFDQAgAC0AK0UNACAALwEwIgFBAnFFDQEMAgsgAC8BMCIBQQFxRQ0BC0EBIQIgAC0AKEEBRg0AIAAvATIiAEHkAGtB5ABJDQAgAEHMAUYNACAAQbACRg0AIAFBwABxDQBBACECIAFBiARxQYAERg0AIAFBKHFBAEchAgsgAgtzACAAQRBq/QwAAAAAAAAAAAAAAAAAAAAA/QsDACAA/QwAAAAAAAAAAAAAAAAAAAAA/QsDACAAQTBq/QwAAAAAAAAAAAAAAAAAAAAA/QsDACAAQSBq/QwAAAAAAAAAAAAAAAAAAAAA/QsDACAAQd0BNgIcCwYAIAAQMguaLQELfyMAQRBrIgokAEGk0AAoAgAiCUUEQEHk0wAoAgAiBUUEQEHw0wBCfzcCAEHo0wBCgICEgICAwAA3AgBB5NMAIApBCGpBcHFB2KrVqgVzIgU2AgBB+NMAQQA2AgBByNMAQQA2AgALQczTAEGA1AQ2AgBBnNAAQYDUBDYCAEGw0AAgBTYCAEGs0ABBfzYCAEHQ0wBBgKwDNgIAA0AgAUHI0ABqIAFBvNAAaiICNgIAIAIgAUG00ABqIgM2AgAgAUHA0ABqIAM2AgAgAUHQ0ABqIAFBxNAAaiIDNgIAIAMgAjYCACABQdjQAGogAUHM0ABqIgI2AgAgAiADNgIAIAFB1NAAaiACNgIAIAFBIGoiAUGAAkcNAAtBjNQEQcGrAzYCAEGo0ABB9NMAKAIANgIAQZjQAEHAqwM2AgBBpNAAQYjUBDYCAEHM/wdBODYCAEGI1AQhCQsCQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQCAAQewBTQRAQYzQACgCACIGQRAgAEETakFwcSAAQQtJGyIEQQN2IgB2IgFBA3EEQAJAIAFBAXEgAHJBAXMiAkEDdCIAQbTQAGoiASAAQbzQAGooAgAiACgCCCIDRgRAQYzQACAGQX4gAndxNgIADAELIAEgAzYCCCADIAE2AgwLIABBCGohASAAIAJBA3QiAkEDcjYCBCAAIAJqIgAgACgCBEEBcjYCBAwRC0GU0AAoAgAiCCAETw0BIAEEQAJAQQIgAHQiAkEAIAJrciABIAB0cWgiAEEDdCICQbTQAGoiASACQbzQAGooAgAiAigCCCIDRgRAQYzQACAGQX4gAHdxIgY2AgAMAQsgASADNgIIIAMgATYCDAsgAiAEQQNyNgIEIABBA3QiACAEayEFIAAgAmogBTYCACACIARqIgQgBUEBcjYCBCAIBEAgCEF4cUG00ABqIQBBoNAAKAIAIQMCf0EBIAhBA3Z0IgEgBnFFBEBBjNAAIAEgBnI2AgAgAAwBCyAAKAIICyIBIAM2AgwgACADNgIIIAMgADYCDCADIAE2AggLIAJBCGohAUGg0AAgBDYCAEGU0AAgBTYCAAwRC0GQ0AAoAgAiC0UNASALaEECdEG80gBqKAIAIgAoAgRBeHEgBGshBSAAIQIDQAJAIAIoAhAiAUUEQCACQRRqKAIAIgFFDQELIAEoAgRBeHEgBGsiAyAFSSECIAMgBSACGyEFIAEgACACGyEAIAEhAgwBCwsgACgCGCEJIAAoAgwiAyAARwRAQZzQACgCABogAyAAKAIIIgE2AgggASADNgIMDBALIABBFGoiAigCACIBRQRAIAAoAhAiAUUNAyAAQRBqIQILA0AgAiEHIAEiA0EUaiICKAIAIgENACADQRBqIQIgAygCECIBDQALIAdBADYCAAwPC0F/IQQgAEG/f0sNACAAQRNqIgFBcHEhBEGQ0AAoAgAiCEUNAEEAIARrIQUCQAJAAkACf0EAIARBgAJJDQAaQR8gBEH///8HSw0AGiAEQSYgAUEIdmciAGt2QQFxIABBAXRrQT5qCyIGQQJ0QbzSAGooAgAiAkUEQEEAIQFBACEDDAELQQAhASAEQRkgBkEBdmtBACAGQR9HG3QhAEEAIQMDQAJAIAIoAgRBeHEgBGsiByAFTw0AIAIhAyAHIgUNAEEAIQUgAiEBDAMLIAEgAkEUaigCACIHIAcgAiAAQR12QQRxakEQaigCACICRhsgASAHGyEBIABBAXQhACACDQALCyABIANyRQRAQQAhA0ECIAZ0IgBBACAAa3IgCHEiAEUNAyAAaEECdEG80gBqKAIAIQELIAFFDQELA0AgASgCBEF4cSAEayICIAVJIQAgAiAFIAAbIQUgASADIAAbIQMgASgCECIABH8gAAUgAUEUaigCAAsiAQ0ACwsgA0UNACAFQZTQACgCACAEa08NACADKAIYIQcgAyADKAIMIgBHBEBBnNAAKAIAGiAAIAMoAggiATYCCCABIAA2AgwMDgsgA0EUaiICKAIAIgFFBEAgAygCECIBRQ0DIANBEGohAgsDQCACIQYgASIAQRRqIgIoAgAiAQ0AIABBEGohAiAAKAIQIgENAAsgBkEANgIADA0LQZTQACgCACIDIARPBEBBoNAAKAIAIQECQCADIARrIgJBEE8EQCABIARqIgAgAkEBcjYCBCABIANqIAI2AgAgASAEQQNyNgIEDAELIAEgA0EDcjYCBCABIANqIgAgACgCBEEBcjYCBEEAIQBBACECC0GU0AAgAjYCAEGg0AAgADYCACABQQhqIQEMDwtBmNAAKAIAIgMgBEsEQCAEIAlqIgAgAyAEayIBQQFyNgIEQaTQACAANgIAQZjQACABNgIAIAkgBEEDcjYCBCAJQQhqIQEMDwtBACEBIAQCf0Hk0wAoAgAEQEHs0wAoAgAMAQtB8NMAQn83AgBB6NMAQoCAhICAgMAANwIAQeTTACAKQQxqQXBxQdiq1aoFczYCAEH40wBBADYCAEHI0wBBADYCAEGAgAQLIgAgBEHHAGoiBWoiBkEAIABrIgdxIgJPBEBB/NMAQTA2AgAMDwsCQEHE0wAoAgAiAUUNAEG80wAoAgAiCCACaiEAIAAgAU0gACAIS3ENAEEAIQFB/NMAQTA2AgAMDwtByNMALQAAQQRxDQQCQAJAIAkEQEHM0wAhAQNAIAEoAgAiACAJTQRAIAAgASgCBGogCUsNAwsgASgCCCIBDQALC0EAEDMiAEF/Rg0FIAIhBkHo0wAoAgAiAUEBayIDIABxBEAgAiAAayAAIANqQQAgAWtxaiEGCyAEIAZPDQUgBkH+////B0sNBUHE0wAoAgAiAwRAQbzTACgCACIHIAZqIQEgASAHTQ0GIAEgA0sNBgsgBhAzIgEgAEcNAQwHCyAGIANrIAdxIgZB/v///wdLDQQgBhAzIQAgACABKAIAIAEoAgRqRg0DIAAhAQsCQCAGIARByABqTw0AIAFBf0YNAEHs0wAoAgAiACAFIAZrakEAIABrcSIAQf7///8HSwRAIAEhAAwHCyAAEDNBf0cEQCAAIAZqIQYgASEADAcLQQAgBmsQMxoMBAsgASIAQX9HDQUMAwtBACEDDAwLQQAhAAwKCyAAQX9HDQILQcjTAEHI0wAoAgBBBHI2AgALIAJB/v///wdLDQEgAhAzIQBBABAzIQEgAEF/Rg0BIAFBf0YNASAAIAFPDQEgASAAayIGIARBOGpNDQELQbzTAEG80wAoAgAgBmoiATYCAEHA0wAoAgAgAUkEQEHA0wAgATYCAAsCQAJAAkBBpNAAKAIAIgIEQEHM0wAhAQNAIAAgASgCACIDIAEoAgQiBWpGDQIgASgCCCIBDQALDAILQZzQACgCACIBQQBHIAAgAU9xRQRAQZzQACAANgIAC0EAIQFB0NMAIAY2AgBBzNMAIAA2AgBBrNAAQX82AgBBsNAAQeTTACgCADYCAEHY0wBBADYCAANAIAFByNAAaiABQbzQAGoiAjYCACACIAFBtNAAaiIDNgIAIAFBwNAAaiADNgIAIAFB0NAAaiABQcTQAGoiAzYCACADIAI2AgAgAUHY0ABqIAFBzNAAaiICNgIAIAIgAzYCACABQdTQAGogAjYCACABQSBqIgFBgAJHDQALQXggAGtBD3EiASAAaiICIAZBOGsiAyABayIBQQFyNgIEQajQAEH00wAoAgA2AgBBmNAAIAE2AgBBpNAAIAI2AgAgACADakE4NgIEDAILIAAgAk0NACACIANJDQAgASgCDEEIcQ0AQXggAmtBD3EiACACaiIDQZjQACgCACAGaiIHIABrIgBBAXI2AgQgASAFIAZqNgIEQajQAEH00wAoAgA2AgBBmNAAIAA2AgBBpNAAIAM2AgAgAiAHakE4NgIEDAELIABBnNAAKAIASQRAQZzQACAANgIACyAAIAZqIQNBzNMAIQECQAJAAkADQCADIAEoAgBHBEAgASgCCCIBDQEMAgsLIAEtAAxBCHFFDQELQczTACEBA0AgASgCACIDIAJNBEAgAyABKAIEaiIFIAJLDQMLIAEoAgghAQwACwALIAEgADYCACABIAEoAgQgBmo2AgQgAEF4IABrQQ9xaiIJIARBA3I2AgQgA0F4IANrQQ9xaiIGIAQgCWoiBGshASACIAZGBEBBpNAAIAQ2AgBBmNAAQZjQACgCACABaiIANgIAIAQgAEEBcjYCBAwIC0Gg0AAoAgAgBkYEQEGg0AAgBDYCAEGU0ABBlNAAKAIAIAFqIgA2AgAgBCAAQQFyNgIEIAAgBGogADYCAAwICyAGKAIEIgVBA3FBAUcNBiAFQXhxIQggBUH/AU0EQCAFQQN2IQMgBigCCCIAIAYoAgwiAkYEQEGM0ABBjNAAKAIAQX4gA3dxNgIADAcLIAIgADYCCCAAIAI2AgwMBgsgBigCGCEHIAYgBigCDCIARwRAIAAgBigCCCICNgIIIAIgADYCDAwFCyAGQRRqIgIoAgAiBUUEQCAGKAIQIgVFDQQgBkEQaiECCwNAIAIhAyAFIgBBFGoiAigCACIFDQAgAEEQaiECIAAoAhAiBQ0ACyADQQA2AgAMBAtBeCAAa0EPcSIBIABqIgcgBkE4ayIDIAFrIgFBAXI2AgQgACADakE4NgIEIAIgBUE3IAVrQQ9xakE/ayIDIAMgAkEQakkbIgNBIzYCBEGo0ABB9NMAKAIANgIAQZjQACABNgIAQaTQACAHNgIAIANBEGpB1NMAKQIANwIAIANBzNMAKQIANwIIQdTTACADQQhqNgIAQdDTACAGNgIAQczTACAANgIAQdjTAEEANgIAIANBJGohAQNAIAFBBzYCACAFIAFBBGoiAUsNAAsgAiADRg0AIAMgAygCBEF+cTYCBCADIAMgAmsiBTYCACACIAVBAXI2AgQgBUH/AU0EQCAFQXhxQbTQAGohAAJ/QYzQACgCACIBQQEgBUEDdnQiA3FFBEBBjNAAIAEgA3I2AgAgAAwBCyAAKAIICyIBIAI2AgwgACACNgIIIAIgADYCDCACIAE2AggMAQtBHyEBIAVB////B00EQCAFQSYgBUEIdmciAGt2QQFxIABBAXRrQT5qIQELIAIgATYCHCACQgA3AhAgAUECdEG80gBqIQBBkNAAKAIAIgNBASABdCIGcUUEQCAAIAI2AgBBkNAAIAMgBnI2AgAgAiAANgIYIAIgAjYCCCACIAI2AgwMAQsgBUEZIAFBAXZrQQAgAUEfRxt0IQEgACgCACEDAkADQCADIgAoAgRBeHEgBUYNASABQR12IQMgAUEBdCEBIAAgA0EEcWpBEGoiBigCACIDDQALIAYgAjYCACACIAA2AhggAiACNgIMIAIgAjYCCAwBCyAAKAIIIgEgAjYCDCAAIAI2AgggAkEANgIYIAIgADYCDCACIAE2AggLQZjQACgCACIBIARNDQBBpNAAKAIAIgAgBGoiAiABIARrIgFBAXI2AgRBmNAAIAE2AgBBpNAAIAI2AgAgACAEQQNyNgIEIABBCGohAQwIC0EAIQFB/NMAQTA2AgAMBwtBACEACyAHRQ0AAkAgBigCHCICQQJ0QbzSAGoiAygCACAGRgRAIAMgADYCACAADQFBkNAAQZDQACgCAEF+IAJ3cTYCAAwCCyAHQRBBFCAHKAIQIAZGG2ogADYCACAARQ0BCyAAIAc2AhggBigCECICBEAgACACNgIQIAIgADYCGAsgBkEUaigCACICRQ0AIABBFGogAjYCACACIAA2AhgLIAEgCGohASAGIAhqIgYoAgQhBQsgBiAFQX5xNgIEIAEgBGogATYCACAEIAFBAXI2AgQgAUH/AU0EQCABQXhxQbTQAGohAAJ/QYzQACgCACICQQEgAUEDdnQiAXFFBEBBjNAAIAEgAnI2AgAgAAwBCyAAKAIICyIBIAQ2AgwgACAENgIIIAQgADYCDCAEIAE2AggMAQtBHyEFIAFB////B00EQCABQSYgAUEIdmciAGt2QQFxIABBAXRrQT5qIQULIAQgBTYCHCAEQgA3AhAgBUECdEG80gBqIQBBkNAAKAIAIgJBASAFdCIDcUUEQCAAIAQ2AgBBkNAAIAIgA3I2AgAgBCAANgIYIAQgBDYCCCAEIAQ2AgwMAQsgAUEZIAVBAXZrQQAgBUEfRxt0IQUgACgCACEAAkADQCAAIgIoAgRBeHEgAUYNASAFQR12IQAgBUEBdCEFIAIgAEEEcWpBEGoiAygCACIADQALIAMgBDYCACAEIAI2AhggBCAENgIMIAQgBDYCCAwBCyACKAIIIgAgBDYCDCACIAQ2AgggBEEANgIYIAQgAjYCDCAEIAA2AggLIAlBCGohAQwCCwJAIAdFDQACQCADKAIcIgFBAnRBvNIAaiICKAIAIANGBEAgAiAANgIAIAANAUGQ0AAgCEF+IAF3cSIINgIADAILIAdBEEEUIAcoAhAgA0YbaiAANgIAIABFDQELIAAgBzYCGCADKAIQIgEEQCAAIAE2AhAgASAANgIYCyADQRRqKAIAIgFFDQAgAEEUaiABNgIAIAEgADYCGAsCQCAFQQ9NBEAgAyAEIAVqIgBBA3I2AgQgACADaiIAIAAoAgRBAXI2AgQMAQsgAyAEaiICIAVBAXI2AgQgAyAEQQNyNgIEIAIgBWogBTYCACAFQf8BTQRAIAVBeHFBtNAAaiEAAn9BjNAAKAIAIgFBASAFQQN2dCIFcUUEQEGM0AAgASAFcjYCACAADAELIAAoAggLIgEgAjYCDCAAIAI2AgggAiAANgIMIAIgATYCCAwBC0EfIQEgBUH///8HTQRAIAVBJiAFQQh2ZyIAa3ZBAXEgAEEBdGtBPmohAQsgAiABNgIcIAJCADcCECABQQJ0QbzSAGohAEEBIAF0IgQgCHFFBEAgACACNgIAQZDQACAEIAhyNgIAIAIgADYCGCACIAI2AgggAiACNgIMDAELIAVBGSABQQF2a0EAIAFBH0cbdCEBIAAoAgAhBAJAA0AgBCIAKAIEQXhxIAVGDQEgAUEddiEEIAFBAXQhASAAIARBBHFqQRBqIgYoAgAiBA0ACyAGIAI2AgAgAiAANgIYIAIgAjYCDCACIAI2AggMAQsgACgCCCIBIAI2AgwgACACNgIIIAJBADYCGCACIAA2AgwgAiABNgIICyADQQhqIQEMAQsCQCAJRQ0AAkAgACgCHCIBQQJ0QbzSAGoiAigCACAARgRAIAIgAzYCACADDQFBkNAAIAtBfiABd3E2AgAMAgsgCUEQQRQgCSgCECAARhtqIAM2AgAgA0UNAQsgAyAJNgIYIAAoAhAiAQRAIAMgATYCECABIAM2AhgLIABBFGooAgAiAUUNACADQRRqIAE2AgAgASADNgIYCwJAIAVBD00EQCAAIAQgBWoiAUEDcjYCBCAAIAFqIgEgASgCBEEBcjYCBAwBCyAAIARqIgcgBUEBcjYCBCAAIARBA3I2AgQgBSAHaiAFNgIAIAgEQCAIQXhxQbTQAGohAUGg0AAoAgAhAwJ/QQEgCEEDdnQiAiAGcUUEQEGM0AAgAiAGcjYCACABDAELIAEoAggLIgIgAzYCDCABIAM2AgggAyABNgIMIAMgAjYCCAtBoNAAIAc2AgBBlNAAIAU2AgALIABBCGohAQsgCkEQaiQAIAELQwAgAEUEQD8AQRB0DwsCQCAAQf//A3ENACAAQQBIDQAgAEEQdkAAIgBBf0YEQEH80wBBMDYCAEF/DwsgAEEQdA8LAAsL3D8iAEGACAsJAQAAAAIAAAADAEGUCAsFBAAAAAUAQaQICwkGAAAABwAAAAgAQdwIC4otSW52YWxpZCBjaGFyIGluIHVybCBxdWVyeQBTcGFuIGNhbGxiYWNrIGVycm9yIGluIG9uX2JvZHkAQ29udGVudC1MZW5ndGggb3ZlcmZsb3cAQ2h1bmsgc2l6ZSBvdmVyZmxvdwBSZXNwb25zZSBvdmVyZmxvdwBJbnZhbGlkIG1ldGhvZCBmb3IgSFRUUC94LnggcmVxdWVzdABJbnZhbGlkIG1ldGhvZCBmb3IgUlRTUC94LnggcmVxdWVzdABFeHBlY3RlZCBTT1VSQ0UgbWV0aG9kIGZvciBJQ0UveC54IHJlcXVlc3QASW52YWxpZCBjaGFyIGluIHVybCBmcmFnbWVudCBzdGFydABFeHBlY3RlZCBkb3QAU3BhbiBjYWxsYmFjayBlcnJvciBpbiBvbl9zdGF0dXMASW52YWxpZCByZXNwb25zZSBzdGF0dXMASW52YWxpZCBjaGFyYWN0ZXIgaW4gY2h1bmsgZXh0ZW5zaW9ucwBVc2VyIGNhbGxiYWNrIGVycm9yAGBvbl9yZXNldGAgY2FsbGJhY2sgZXJyb3IAYG9uX2NodW5rX2hlYWRlcmAgY2FsbGJhY2sgZXJyb3IAYG9uX21lc3NhZ2VfYmVnaW5gIGNhbGxiYWNrIGVycm9yAGBvbl9jaHVua19leHRlbnNpb25fdmFsdWVgIGNhbGxiYWNrIGVycm9yAGBvbl9zdGF0dXNfY29tcGxldGVgIGNhbGxiYWNrIGVycm9yAGBvbl92ZXJzaW9uX2NvbXBsZXRlYCBjYWxsYmFjayBlcnJvcgBgb25fdXJsX2NvbXBsZXRlYCBjYWxsYmFjayBlcnJvcgBgb25fY2h1bmtfY29tcGxldGVgIGNhbGxiYWNrIGVycm9yAGBvbl9oZWFkZXJfdmFsdWVfY29tcGxldGVgIGNhbGxiYWNrIGVycm9yAGBvbl9tZXNzYWdlX2NvbXBsZXRlYCBjYWxsYmFjayBlcnJvcgBgb25fbWV0aG9kX2NvbXBsZXRlYCBjYWxsYmFjayBlcnJvcgBgb25faGVhZGVyX2ZpZWxkX2NvbXBsZXRlYCBjYWxsYmFjayBlcnJvcgBgb25fY2h1bmtfZXh0ZW5zaW9uX25hbWVgIGNhbGxiYWNrIGVycm9yAFVuZXhwZWN0ZWQgY2hhciBpbiB1cmwgc2VydmVyAEludmFsaWQgaGVhZGVyIHZhbHVlIGNoYXIASW52YWxpZCBoZWFkZXIgZmllbGQgY2hhcgBTcGFuIGNhbGxiYWNrIGVycm9yIGluIG9uX3ZlcnNpb24ASW52YWxpZCBtaW5vciB2ZXJzaW9uAEludmFsaWQgbWFqb3IgdmVyc2lvbgBFeHBlY3RlZCBzcGFjZSBhZnRlciB2ZXJzaW9uAEV4cGVjdGVkIENSTEYgYWZ0ZXIgdmVyc2lvbgBJbnZhbGlkIEhUVFAgdmVyc2lvbgBJbnZhbGlkIGhlYWRlciB0b2tlbgBTcGFuIGNhbGxiYWNrIGVycm9yIGluIG9uX3VybABJbnZhbGlkIGNoYXJhY3RlcnMgaW4gdXJsAFVuZXhwZWN0ZWQgc3RhcnQgY2hhciBpbiB1cmwARG91YmxlIEAgaW4gdXJsAEVtcHR5IENvbnRlbnQtTGVuZ3RoAEludmFsaWQgY2hhcmFjdGVyIGluIENvbnRlbnQtTGVuZ3RoAER1cGxpY2F0ZSBDb250ZW50LUxlbmd0aABJbnZhbGlkIGNoYXIgaW4gdXJsIHBhdGgAQ29udGVudC1MZW5ndGggY2FuJ3QgYmUgcHJlc2VudCB3aXRoIFRyYW5zZmVyLUVuY29kaW5nAEludmFsaWQgY2hhcmFjdGVyIGluIGNodW5rIHNpemUAU3BhbiBjYWxsYmFjayBlcnJvciBpbiBvbl9oZWFkZXJfdmFsdWUAU3BhbiBjYWxsYmFjayBlcnJvciBpbiBvbl9jaHVua19leHRlbnNpb25fdmFsdWUASW52YWxpZCBjaGFyYWN0ZXIgaW4gY2h1bmsgZXh0ZW5zaW9ucyB2YWx1ZQBNaXNzaW5nIGV4cGVjdGVkIExGIGFmdGVyIGhlYWRlciB2YWx1ZQBJbnZhbGlkIGBUcmFuc2Zlci1FbmNvZGluZ2AgaGVhZGVyIHZhbHVlAEludmFsaWQgY2hhcmFjdGVyIGluIGNodW5rIGV4dGVuc2lvbnMgcXVvdGUgdmFsdWUASW52YWxpZCBjaGFyYWN0ZXIgaW4gY2h1bmsgZXh0ZW5zaW9ucyBxdW90ZWQgdmFsdWUAUGF1c2VkIGJ5IG9uX2hlYWRlcnNfY29tcGxldGUASW52YWxpZCBFT0Ygc3RhdGUAb25fcmVzZXQgcGF1c2UAb25fY2h1bmtfaGVhZGVyIHBhdXNlAG9uX21lc3NhZ2VfYmVnaW4gcGF1c2UAb25fY2h1bmtfZXh0ZW5zaW9uX3ZhbHVlIHBhdXNlAG9uX3N0YXR1c19jb21wbGV0ZSBwYXVzZQBvbl92ZXJzaW9uX2NvbXBsZXRlIHBhdXNlAG9uX3VybF9jb21wbGV0ZSBwYXVzZQBvbl9jaHVua19jb21wbGV0ZSBwYXVzZQBvbl9oZWFkZXJfdmFsdWVfY29tcGxldGUgcGF1c2UAb25fbWVzc2FnZV9jb21wbGV0ZSBwYXVzZQBvbl9tZXRob2RfY29tcGxldGUgcGF1c2UAb25faGVhZGVyX2ZpZWxkX2NvbXBsZXRlIHBhdXNlAG9uX2NodW5rX2V4dGVuc2lvbl9uYW1lIHBhdXNlAFVuZXhwZWN0ZWQgc3BhY2UgYWZ0ZXIgc3RhcnQgbGluZQBTcGFuIGNhbGxiYWNrIGVycm9yIGluIG9uX2NodW5rX2V4dGVuc2lvbl9uYW1lAEludmFsaWQgY2hhcmFjdGVyIGluIGNodW5rIGV4dGVuc2lvbnMgbmFtZQBQYXVzZSBvbiBDT05ORUNUL1VwZ3JhZGUAUGF1c2Ugb24gUFJJL1VwZ3JhZGUARXhwZWN0ZWQgSFRUUC8yIENvbm5lY3Rpb24gUHJlZmFjZQBTcGFuIGNhbGxiYWNrIGVycm9yIGluIG9uX21ldGhvZABFeHBlY3RlZCBzcGFjZSBhZnRlciBtZXRob2QAU3BhbiBjYWxsYmFjayBlcnJvciBpbiBvbl9oZWFkZXJfZmllbGQAUGF1c2VkAEludmFsaWQgd29yZCBlbmNvdW50ZXJlZABJbnZhbGlkIG1ldGhvZCBlbmNvdW50ZXJlZABVbmV4cGVjdGVkIGNoYXIgaW4gdXJsIHNjaGVtYQBSZXF1ZXN0IGhhcyBpbnZhbGlkIGBUcmFuc2Zlci1FbmNvZGluZ2AAU1dJVENIX1BST1hZAFVTRV9QUk9YWQBNS0FDVElWSVRZAFVOUFJPQ0VTU0FCTEVfRU5USVRZAENPUFkATU9WRURfUEVSTUFORU5UTFkAVE9PX0VBUkxZAE5PVElGWQBGQUlMRURfREVQRU5ERU5DWQBCQURfR0FURVdBWQBQTEFZAFBVVABDSEVDS09VVABHQVRFV0FZX1RJTUVPVVQAUkVRVUVTVF9USU1FT1VUAE5FVFdPUktfQ09OTkVDVF9USU1FT1VUAENPTk5FQ1RJT05fVElNRU9VVABMT0dJTl9USU1FT1VUAE5FVFdPUktfUkVBRF9USU1FT1VUAFBPU1QATUlTRElSRUNURURfUkVRVUVTVABDTElFTlRfQ0xPU0VEX1JFUVVFU1QAQ0xJRU5UX0NMT1NFRF9MT0FEX0JBTEFOQ0VEX1JFUVVFU1QAQkFEX1JFUVVFU1QASFRUUF9SRVFVRVNUX1NFTlRfVE9fSFRUUFNfUE9SVABSRVBPUlQASU1fQV9URUFQT1QAUkVTRVRfQ09OVEVOVABOT19DT05URU5UAFBBUlRJQUxfQ09OVEVOVABIUEVfSU5WQUxJRF9DT05TVEFOVABIUEVfQ0JfUkVTRVQAR0VUAEhQRV9TVFJJQ1QAQ09ORkxJQ1QAVEVNUE9SQVJZX1JFRElSRUNUAFBFUk1BTkVOVF9SRURJUkVDVABDT05ORUNUAE1VTFRJX1NUQVRVUwBIUEVfSU5WQUxJRF9TVEFUVVMAVE9PX01BTllfUkVRVUVTVFMARUFSTFlfSElOVFMAVU5BVkFJTEFCTEVfRk9SX0xFR0FMX1JFQVNPTlMAT1BUSU9OUwBTV0lUQ0hJTkdfUFJPVE9DT0xTAFZBUklBTlRfQUxTT19ORUdPVElBVEVTAE1VTFRJUExFX0NIT0lDRVMASU5URVJOQUxfU0VSVkVSX0VSUk9SAFdFQl9TRVJWRVJfVU5LTk9XTl9FUlJPUgBSQUlMR1VOX0VSUk9SAElERU5USVRZX1BST1ZJREVSX0FVVEhFTlRJQ0FUSU9OX0VSUk9SAFNTTF9DRVJUSUZJQ0FURV9FUlJPUgBJTlZBTElEX1hfRk9SV0FSREVEX0ZPUgBTRVRfUEFSQU1FVEVSAEdFVF9QQVJBTUVURVIASFBFX1VTRVIAU0VFX09USEVSAEhQRV9DQl9DSFVOS19IRUFERVIATUtDQUxFTkRBUgBTRVRVUABXRUJfU0VSVkVSX0lTX0RPV04AVEVBUkRPV04ASFBFX0NMT1NFRF9DT05ORUNUSU9OAEhFVVJJU1RJQ19FWFBJUkFUSU9OAERJU0NPTk5FQ1RFRF9PUEVSQVRJT04ATk9OX0FVVEhPUklUQVRJVkVfSU5GT1JNQVRJT04ASFBFX0lOVkFMSURfVkVSU0lPTgBIUEVfQ0JfTUVTU0FHRV9CRUdJTgBTSVRFX0lTX0ZST1pFTgBIUEVfSU5WQUxJRF9IRUFERVJfVE9LRU4ASU5WQUxJRF9UT0tFTgBGT1JCSURERU4ARU5IQU5DRV9ZT1VSX0NBTE0ASFBFX0lOVkFMSURfVVJMAEJMT0NLRURfQllfUEFSRU5UQUxfQ09OVFJPTABNS0NPTABBQ0wASFBFX0lOVEVSTkFMAFJFUVVFU1RfSEVBREVSX0ZJRUxEU19UT09fTEFSR0VfVU5PRkZJQ0lBTABIUEVfT0sAVU5MSU5LAFVOTE9DSwBQUkkAUkVUUllfV0lUSABIUEVfSU5WQUxJRF9DT05URU5UX0xFTkdUSABIUEVfVU5FWFBFQ1RFRF9DT05URU5UX0xFTkdUSABGTFVTSABQUk9QUEFUQ0gATS1TRUFSQ0gAVVJJX1RPT19MT05HAFBST0NFU1NJTkcATUlTQ0VMTEFORU9VU19QRVJTSVNURU5UX1dBUk5JTkcATUlTQ0VMTEFORU9VU19XQVJOSU5HAEhQRV9JTlZBTElEX1RSQU5TRkVSX0VOQ09ESU5HAEV4cGVjdGVkIENSTEYASFBFX0lOVkFMSURfQ0hVTktfU0laRQBNT1ZFAENPTlRJTlVFAEhQRV9DQl9TVEFUVVNfQ09NUExFVEUASFBFX0NCX0hFQURFUlNfQ09NUExFVEUASFBFX0NCX1ZFUlNJT05fQ09NUExFVEUASFBFX0NCX1VSTF9DT01QTEVURQBIUEVfQ0JfQ0hVTktfQ09NUExFVEUASFBFX0NCX0hFQURFUl9WQUxVRV9DT01QTEVURQBIUEVfQ0JfQ0hVTktfRVhURU5TSU9OX1ZBTFVFX0NPTVBMRVRFAEhQRV9DQl9DSFVOS19FWFRFTlNJT05fTkFNRV9DT01QTEVURQBIUEVfQ0JfTUVTU0FHRV9DT01QTEVURQBIUEVfQ0JfTUVUSE9EX0NPTVBMRVRFAEhQRV9DQl9IRUFERVJfRklFTERfQ09NUExFVEUAREVMRVRFAEhQRV9JTlZBTElEX0VPRl9TVEFURQBJTlZBTElEX1NTTF9DRVJUSUZJQ0FURQBQQVVTRQBOT19SRVNQT05TRQBVTlNVUFBPUlRFRF9NRURJQV9UWVBFAEdPTkUATk9UX0FDQ0VQVEFCTEUAU0VSVklDRV9VTkFWQUlMQUJMRQBSQU5HRV9OT1RfU0FUSVNGSUFCTEUAT1JJR0lOX0lTX1VOUkVBQ0hBQkxFAFJFU1BPTlNFX0lTX1NUQUxFAFBVUkdFAE1FUkdFAFJFUVVFU1RfSEVBREVSX0ZJRUxEU19UT09fTEFSR0UAUkVRVUVTVF9IRUFERVJfVE9PX0xBUkdFAFBBWUxPQURfVE9PX0xBUkdFAElOU1VGRklDSUVOVF9TVE9SQUdFAEhQRV9QQVVTRURfVVBHUkFERQBIUEVfUEFVU0VEX0gyX1VQR1JBREUAU09VUkNFAEFOTk9VTkNFAFRSQUNFAEhQRV9VTkVYUEVDVEVEX1NQQUNFAERFU0NSSUJFAFVOU1VCU0NSSUJFAFJFQ09SRABIUEVfSU5WQUxJRF9NRVRIT0QATk9UX0ZPVU5EAFBST1BGSU5EAFVOQklORABSRUJJTkQAVU5BVVRIT1JJWkVEAE1FVEhPRF9OT1RfQUxMT1dFRABIVFRQX1ZFUlNJT05fTk9UX1NVUFBPUlRFRABBTFJFQURZX1JFUE9SVEVEAEFDQ0VQVEVEAE5PVF9JTVBMRU1FTlRFRABMT09QX0RFVEVDVEVEAEhQRV9DUl9FWFBFQ1RFRABIUEVfTEZfRVhQRUNURUQAQ1JFQVRFRABJTV9VU0VEAEhQRV9QQVVTRUQAVElNRU9VVF9PQ0NVUkVEAFBBWU1FTlRfUkVRVUlSRUQAUFJFQ09ORElUSU9OX1JFUVVJUkVEAFBST1hZX0FVVEhFTlRJQ0FUSU9OX1JFUVVJUkVEAE5FVFdPUktfQVVUSEVOVElDQVRJT05fUkVRVUlSRUQATEVOR1RIX1JFUVVJUkVEAFNTTF9DRVJUSUZJQ0FURV9SRVFVSVJFRABVUEdSQURFX1JFUVVJUkVEAFBBR0VfRVhQSVJFRABQUkVDT05ESVRJT05fRkFJTEVEAEVYUEVDVEFUSU9OX0ZBSUxFRABSRVZBTElEQVRJT05fRkFJTEVEAFNTTF9IQU5EU0hBS0VfRkFJTEVEAExPQ0tFRABUUkFOU0ZPUk1BVElPTl9BUFBMSUVEAE5PVF9NT0RJRklFRABOT1RfRVhURU5ERUQAQkFORFdJRFRIX0xJTUlUX0VYQ0VFREVEAFNJVEVfSVNfT1ZFUkxPQURFRABIRUFEAEV4cGVjdGVkIEhUVFAvAABeEwAAJhMAADAQAADwFwAAnRMAABUSAAA5FwAA8BIAAAoQAAB1EgAArRIAAIITAABPFAAAfxAAAKAVAAAjFAAAiRIAAIsUAABNFQAA1BEAAM8UAAAQGAAAyRYAANwWAADBEQAA4BcAALsUAAB0FAAAfBUAAOUUAAAIFwAAHxAAAGUVAACjFAAAKBUAAAIVAACZFQAALBAAAIsZAABPDwAA1A4AAGoQAADOEAAAAhcAAIkOAABuEwAAHBMAAGYUAABWFwAAwRMAAM0TAABsEwAAaBcAAGYXAABfFwAAIhMAAM4PAABpDgAA2A4AAGMWAADLEwAAqg4AACgXAAAmFwAAxRMAAF0WAADoEQAAZxMAAGUTAADyFgAAcxMAAB0XAAD5FgAA8xEAAM8OAADOFQAADBIAALMRAAClEQAAYRAAADIXAAC7EwBB+TULAQEAQZA2C+ABAQECAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAAEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEAQf03CwEBAEGROAteAgMCAgICAgAAAgIAAgIAAgICAgICAgICAgAEAAAAAAACAgICAgICAgICAgICAgICAgICAgICAgICAgAAAAICAgICAgICAgICAgICAgICAgICAgICAgICAgICAAIAAgBB/TkLAQEAQZE6C14CAAICAgICAAACAgACAgACAgICAgICAgICAAMABAAAAAICAgICAgICAgICAgICAgICAgICAgICAgICAAAAAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAAgACAEHwOwsNbG9zZWVlcC1hbGl2ZQBBiTwLAQEAQaA8C+ABAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEAAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEAQYk+CwEBAEGgPgvnAQEBAQEBAQEBAQEBAQIBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAAEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBY2h1bmtlZABBsMAAC18BAQABAQEBAQAAAQEAAQEAAQEBAQEBAQEBAQAAAAAAAAABAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQAAAAEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAAEAAQBBkMIACyFlY3Rpb25lbnQtbGVuZ3Rob25yb3h5LWNvbm5lY3Rpb24AQcDCAAstcmFuc2Zlci1lbmNvZGluZ3BncmFkZQ0KDQoNClNNDQoNClRUUC9DRS9UU1AvAEH5wgALBQECAAEDAEGQwwAL4AEEAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQABAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQBB+cQACwUBAgABAwBBkMUAC+ABBAEBBQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEAAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEAQfnGAAsEAQAAAQBBkccAC98BAQEAAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAAEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQABAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQBB+sgACwQBAAACAEGQyQALXwMEAAAEBAQEBAQEBAQEBAUEBAQEBAQEBAQEBAQABAAGBwQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAAEAAQABAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQAAAAEAEH6ygALBAEAAAEAQZDLAAsBAQBBqssAC0ECAAAAAAAAAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMAAAAAAAADAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwBB+swACwQBAAABAEGQzQALAQEAQZrNAAsGAgAAAAACAEGxzQALOgMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAAAAAAAAAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMAQfDOAAuWAU5PVU5DRUVDS09VVE5FQ1RFVEVDUklCRUxVU0hFVEVBRFNFQVJDSFJHRUNUSVZJVFlMRU5EQVJWRU9USUZZUFRJT05TQ0hTRUFZU1RBVENIR0VPUkRJUkVDVE9SVFJDSFBBUkFNRVRFUlVSQ0VCU0NSSUJFQVJET1dOQUNFSU5ETktDS1VCU0NSSUJFSFRUUC9BRFRQLw==', 'base64'); + return llhttp_simdWasm; +} - let referrerSource = null; +var constants$2; +var hasRequiredConstants$2; - // 3. Switch on request’s referrer: - if (request.referrer === 'client') { - // Note: node isn't a browser and doesn't implement document/iframes, - // so we bypass this step and replace it with our own. +function requireConstants$2 () { + if (hasRequiredConstants$2) return constants$2; + hasRequiredConstants$2 = 1; - const globalOrigin = getGlobalOrigin(); + const corsSafeListedMethods = /** @type {const} */ (['GET', 'HEAD', 'POST']); + const corsSafeListedMethodsSet = new Set(corsSafeListedMethods); - if (!globalOrigin || globalOrigin.origin === 'null') { - return 'no-referrer' - } + const nullBodyStatus = /** @type {const} */ ([101, 204, 205, 304]); - // note: we need to clone it as it's mutated - referrerSource = new URL(globalOrigin); - } else if (request.referrer instanceof URL) { - // Let referrerSource be request’s referrer. - referrerSource = request.referrer; - } + const redirectStatus = /** @type {const} */ ([301, 302, 303, 307, 308]); + const redirectStatusSet = new Set(redirectStatus); - // 4. Let request’s referrerURL be the result of stripping referrerSource for - // use as a referrer. - let referrerURL = stripURLForReferrer(referrerSource); + /** + * @see https://fetch.spec.whatwg.org/#block-bad-port + */ + const 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' + ]); + const badPortsSet = new Set(badPorts); - // 5. Let referrerOrigin be the result of stripping referrerSource for use as - // a referrer, with the origin-only flag set to true. - const referrerOrigin = stripURLForReferrer(referrerSource, true); + /** + * @see https://w3c.github.io/webappsec-referrer-policy/#referrer-policies + */ + const 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' + ]); + const referrerPolicySet = new Set(referrerPolicy); - // 6. If the result of serializing referrerURL is a string whose length is - // greater than 4096, set referrerURL to referrerOrigin. - if (referrerURL.toString().length > 4096) { - referrerURL = referrerOrigin; - } + const requestRedirect = /** @type {const} */ (['follow', 'manual', 'error']); - const areSameOrigin = sameOrigin(request, referrerURL); - const isNonPotentiallyTrustWorthy = isURLPotentiallyTrustworthy(referrerURL) && - !isURLPotentiallyTrustworthy(request.url); + const safeMethods = /** @type {const} */ (['GET', 'HEAD', 'OPTIONS', 'TRACE']); + const safeMethodsSet = new Set(safeMethods); - // 8. Execute the switch statements corresponding to the value of policy: - 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); + const requestMode = /** @type {const} */ (['navigate', 'same-origin', 'no-cors', 'cors']); - // 1. If the origin of referrerURL and the origin of request’s current - // URL are the same, then return referrerURL. - if (sameOrigin(referrerURL, currentURL)) { - return referrerURL - } + const requestCredentials = /** @type {const} */ (['omit', 'same-origin', 'include']); - // 2. If referrerURL is a potentially trustworthy URL and request’s - // current URL is not a potentially trustworthy URL, then return no - // referrer. - if (isURLPotentiallyTrustworthy(referrerURL) && !isURLPotentiallyTrustworthy(currentURL)) { - return 'no-referrer' - } + const requestCache = /** @type {const} */ ([ + 'default', + 'no-store', + 'reload', + 'no-cache', + 'force-cache', + 'only-if-cached' + ]); - // 3. Return referrerOrigin. - 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 - */ + /** + * @see https://fetch.spec.whatwg.org/#request-body-header-name + */ + const 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' + ]); - default: // eslint-disable-line - return isNonPotentiallyTrustWorthy ? 'no-referrer' : referrerOrigin - } - } + /** + * @see https://fetch.spec.whatwg.org/#enumdef-requestduplex + */ + const requestDuplex = /** @type {const} */ ([ + 'half' + ]); /** - * @see https://w3c.github.io/webappsec-referrer-policy/#strip-url - * @param {URL} url - * @param {boolean|undefined} originOnly + * @see http://fetch.spec.whatwg.org/#forbidden-method */ - function stripURLForReferrer (url, originOnly) { - // 1. Assert: url is a URL. - assert(url instanceof URL); + const forbiddenMethods = /** @type {const} */ (['CONNECT', 'TRACE', 'TRACK']); + const forbiddenMethodsSet = new Set(forbiddenMethods); - // 2. If url’s scheme is a local scheme, then return no referrer. - if (url.protocol === 'file:' || url.protocol === 'about:' || url.protocol === 'blank:') { - return 'no-referrer' - } + const subresource = /** @type {const} */ ([ + 'audio', + 'audioworklet', + 'font', + 'image', + 'manifest', + 'paintworklet', + 'script', + 'style', + 'track', + 'video', + 'xslt', + '' + ]); + const subresourceSet = new Set(subresource); - // 3. Set url’s username to the empty string. - url.username = ''; + constants$2 = { + subresource, + forbiddenMethods, + requestBodyHeader, + referrerPolicy, + requestRedirect, + requestMode, + requestCredentials, + requestCache, + redirectStatus, + corsSafeListedMethods, + nullBodyStatus, + safeMethods, + badPorts, + requestDuplex, + subresourceSet, + badPortsSet, + redirectStatusSet, + corsSafeListedMethodsSet, + safeMethodsSet, + forbiddenMethodsSet, + referrerPolicySet + }; + return constants$2; +} - // 4. Set url’s password to the empty string. - url.password = ''; +var global$2; +var hasRequiredGlobal$1; - // 5. Set url’s fragment to null. - url.hash = ''; - - // 6. If the origin-only flag is true, then: - if (originOnly) { - // 1. Set url’s path to « the empty string ». - url.pathname = ''; +function requireGlobal$1 () { + if (hasRequiredGlobal$1) return global$2; + hasRequiredGlobal$1 = 1; - // 2. Set url’s query to null. - url.search = ''; - } + // In case of breaking changes, increase the version + // number to avoid conflicts. + const globalOrigin = Symbol.for('undici.globalOrigin.1'); - // 7. Return url. - return url + function getGlobalOrigin () { + return globalThis[globalOrigin] } - function isURLPotentiallyTrustworthy (url) { - if (!(url instanceof URL)) { - return false - } + function setGlobalOrigin (newOrigin) { + if (newOrigin === undefined) { + Object.defineProperty(globalThis, globalOrigin, { + value: undefined, + writable: true, + enumerable: false, + configurable: false + }); - // If child of about, return true - if (url.href === 'about:blank' || url.href === 'about:srcdoc') { - return true + return } - // If scheme is data, return true - if (url.protocol === 'data:') return true + const parsedURL = new URL(newOrigin); - // If file, return true - if (url.protocol === 'file:') return true + if (parsedURL.protocol !== 'http:' && parsedURL.protocol !== 'https:') { + throw new TypeError(`Only http & https urls are allowed, received ${parsedURL.protocol}`) + } - return isOriginPotentiallyTrustworthy(url.origin) + Object.defineProperty(globalThis, globalOrigin, { + value: parsedURL, + writable: true, + enumerable: false, + configurable: false + }); + } - function isOriginPotentiallyTrustworthy (origin) { - // If origin is explicitly null, return false - if (origin == null || origin === 'null') return false + global$2 = { + getGlobalOrigin, + setGlobalOrigin + }; + return global$2; +} - const originAsURL = new URL(origin); +var dataUrl; +var hasRequiredDataUrl; - // If secure, return true - if (originAsURL.protocol === 'https:' || originAsURL.protocol === 'wss:') { - return true - } +function requireDataUrl () { + if (hasRequiredDataUrl) return dataUrl; + hasRequiredDataUrl = 1; - // If localhost or variants, 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 - } + const assert = require$$0$3; - // If any other, return false - return false - } - } + const encoder = new TextEncoder(); /** - * @see https://w3c.github.io/webappsec-subresource-integrity/#does-response-match-metadatalist - * @param {Uint8Array} bytes - * @param {string} metadataList + * @see https://mimesniff.spec.whatwg.org/#http-token-code-point */ - function bytesMatch (bytes, metadataList) { - // If node is not built with OpenSSL support, we cannot check - // a request's integrity, so allow it by default (the spec will - // allow requests if an invalid hash is given, as precedence). - /* istanbul ignore if: only if node is built with --without-ssl */ - if (crypto === undefined) { - return true - } - - // 1. Let parsedMetadata be the result of parsing metadataList. - const parsedMetadata = parseMetadata(metadataList); - - // 2. If parsedMetadata is no metadata, return true. - if (parsedMetadata === 'no metadata') { - return true - } - - // 3. If response is not eligible for integrity validation, return false. - // TODO - - // 4. If parsedMetadata is the empty set, return true. - if (parsedMetadata.length === 0) { - return true - } + const HTTP_TOKEN_CODEPOINTS = /^[!#$%&'*+\-.^_|~A-Za-z0-9]+$/; + const HTTP_WHITESPACE_REGEX = /[\u000A\u000D\u0009\u0020]/; // eslint-disable-line + const ASCII_WHITESPACE_REPLACE_REGEX = /[\u0009\u000A\u000C\u000D\u0020]/g; // eslint-disable-line + /** + * @see https://mimesniff.spec.whatwg.org/#http-quoted-string-token-code-point + */ + const HTTP_QUOTED_STRING_TOKENS = /^[\u0009\u0020-\u007E\u0080-\u00FF]+$/; // eslint-disable-line - // 5. Let metadata be the result of getting the strongest - // metadata from parsedMetadata. - const strongest = getStrongestMetadata(parsedMetadata); - const metadata = filterMetadataListByAlgorithm(parsedMetadata, strongest); + // https://fetch.spec.whatwg.org/#data-url-processor + /** @param {URL} dataURL */ + function dataURLProcessor (dataURL) { + // 1. Assert: dataURL’s scheme is "data". + assert(dataURL.protocol === 'data:'); - // 6. For each item in metadata: - for (const item of metadata) { - // 1. Let algorithm be the alg component of item. - const algorithm = item.algo; + // 2. Let input be the result of running the URL + // serializer on dataURL with exclude fragment + // set to true. + let input = URLSerializer(dataURL, true); - // 2. Let expectedValue be the val component of item. - const expectedValue = item.hash; + // 3. Remove the leading "data:" string from input. + input = input.slice(5); - // See https://github.com/web-platform-tests/wpt/commit/e4c5cc7a5e48093220528dfdd1c4012dc3837a0e - // "be liberal with padding". This is annoying, and it's not even in the spec. + // 4. Let position point at the start of input. + const position = { position: 0 }; - // 3. Let actualValue be the result of applying algorithm to bytes. - let actualValue = crypto.createHash(algorithm).update(bytes).digest('base64'); + // 5. Let mimeType be the result of collecting a + // sequence of code points that are not equal + // to U+002C (,), given position. + let mimeType = collectASequenceOfCodePointsFast( + ',', + input, + position + ); - if (actualValue[actualValue.length - 1] === '=') { - if (actualValue[actualValue.length - 2] === '=') { - actualValue = actualValue.slice(0, -2); - } else { - actualValue = actualValue.slice(0, -1); - } - } + // 6. Strip leading and trailing ASCII whitespace + // from mimeType. + // Undici implementation note: we need to store the + // length because if the mimetype has spaces removed, + // the wrong amount will be sliced from the input in + // step #9 + const mimeTypeLength = mimeType.length; + mimeType = removeASCIIWhitespace(mimeType, true, true); - // 4. If actualValue is a case-sensitive match for expectedValue, - // return true. - if (compareBase64Mixed(actualValue, expectedValue)) { - return true - } + // 7. If position is past the end of input, then + // return failure + if (position.position >= input.length) { + return 'failure' } - // 7. Return false. - return false - } - - // https://w3c.github.io/webappsec-subresource-integrity/#grammardef-hash-with-options - // https://www.w3.org/TR/CSP2/#source-list-syntax - // https://www.rfc-editor.org/rfc/rfc5234#appendix-B.1 - const parseHashWithOptions = /(?sha256|sha384|sha512)-((?[A-Za-z0-9+/]+|[A-Za-z0-9_-]+)={0,2}(?:\s|$)( +[!-~]*)?)?/i; + // 8. Advance position by 1. + position.position++; - /** - * @see https://w3c.github.io/webappsec-subresource-integrity/#parse-metadata - * @param {string} metadata - */ - function parseMetadata (metadata) { - // 1. Let result be the empty set. - /** @type {{ algo: string, hash: string }[]} */ - const result = []; + // 9. Let encodedBody be the remainder of input. + const encodedBody = input.slice(mimeTypeLength + 1); - // 2. Let empty be equal to true. - let empty = true; + // 10. Let body be the percent-decoding of encodedBody. + let body = stringPercentDecode(encodedBody); - // 3. For each token returned by splitting metadata on spaces: - for (const token of metadata.split(' ')) { - // 1. Set empty to false. - empty = false; + // 11. If mimeType ends with U+003B (;), followed by + // zero or more U+0020 SPACE, followed by an ASCII + // case-insensitive match for "base64", then: + if (/;(\u0020){0,}base64$/i.test(mimeType)) { + // 1. Let stringBody be the isomorphic decode of body. + const stringBody = isomorphicDecode(body); - // 2. Parse token as a hash-with-options. - const parsedToken = parseHashWithOptions.exec(token); + // 2. Set body to the forgiving-base64 decode of + // stringBody. + body = forgivingBase64(stringBody); - // 3. If token does not parse, continue to the next token. - if ( - parsedToken === null || - parsedToken.groups === undefined || - parsedToken.groups.algo === undefined - ) { - // Note: Chromium blocks the request at this point, but Firefox - // gives a warning that an invalid integrity was given. The - // correct behavior is to ignore these, and subsequently not - // check the integrity of the resource. - continue + // 3. If body is failure, then return failure. + if (body === 'failure') { + return 'failure' } - // 4. Let algorithm be the hash-algo component of token. - const algorithm = parsedToken.groups.algo.toLowerCase(); + // 4. Remove the last 6 code points from mimeType. + mimeType = mimeType.slice(0, -6); - // 5. If algorithm is a hash function recognized by the user - // agent, add the parsed token to result. - if (supportedHashes.includes(algorithm)) { - result.push(parsedToken.groups); - } + // 5. Remove trailing U+0020 SPACE code points from mimeType, + // if any. + mimeType = mimeType.replace(/(\u0020)+$/, ''); + + // 6. Remove the last U+003B (;) code point from mimeType. + mimeType = mimeType.slice(0, -1); } - // 4. Return no metadata if empty is true, otherwise return result. - if (empty === true) { - return 'no metadata' + // 12. If mimeType starts with U+003B (;), then prepend + // "text/plain" to mimeType. + if (mimeType.startsWith(';')) { + mimeType = 'text/plain' + mimeType; } - return result + // 13. Let mimeTypeRecord be the result of parsing + // mimeType. + let mimeTypeRecord = parseMIMEType(mimeType); + + // 14. If mimeTypeRecord is failure, then set + // mimeTypeRecord to text/plain;charset=US-ASCII. + if (mimeTypeRecord === 'failure') { + mimeTypeRecord = parseMIMEType('text/plain;charset=US-ASCII'); + } + + // 15. Return a new data: URL struct whose MIME + // type is mimeTypeRecord and body is body. + // https://fetch.spec.whatwg.org/#data-url-struct + return { mimeType: mimeTypeRecord, body } } + // https://url.spec.whatwg.org/#concept-url-serializer /** - * @param {{ algo: 'sha256' | 'sha384' | 'sha512' }[]} metadataList + * @param {URL} url + * @param {boolean} excludeFragment */ - function getStrongestMetadata (metadataList) { - // Let algorithm be the algo component of the first item in metadataList. - // Can be sha256 - let algorithm = metadataList[0].algo; - // If the algorithm is sha512, then it is the strongest - // and we can return immediately - if (algorithm[3] === '5') { - return algorithm + function URLSerializer (url, excludeFragment = false) { + if (!excludeFragment) { + return url.href } - for (let i = 1; i < metadataList.length; ++i) { - const metadata = metadataList[i]; - // If the algorithm is sha512, then it is the strongest - // and we can break the loop immediately - if (metadata.algo[3] === '5') { - algorithm = 'sha512'; - break - // If the algorithm is sha384, then a potential sha256 or sha384 is ignored - } else if (algorithm[3] === '3') { - continue - // algorithm is sha256, check if algorithm is sha384 and if so, set it as - // the strongest - } else if (metadata.algo[3] === '3') { - algorithm = 'sha384'; - } - } - return algorithm - } + const href = url.href; + const hashLength = url.hash.length; - function filterMetadataListByAlgorithm (metadataList, algorithm) { - if (metadataList.length === 1) { - return metadataList - } + const serialized = hashLength === 0 ? href : href.substring(0, href.length - hashLength); - let pos = 0; - for (let i = 0; i < metadataList.length; ++i) { - if (metadataList[i].algo === algorithm) { - metadataList[pos++] = metadataList[i]; - } + if (!hashLength && href.endsWith('#')) { + return serialized.slice(0, -1) } - metadataList.length = pos; - - return metadataList + return serialized } + // https://infra.spec.whatwg.org/#collect-a-sequence-of-code-points /** - * Compares two base64 strings, allowing for base64url - * in the second string. - * - * @param {string} actualValue always base64 - * @param {string} expectedValue base64 or base64url - * @returns {boolean} + * @param {(char: string) => boolean} condition + * @param {string} input + * @param {{ position: number }} position */ - 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 - } - } + function collectASequenceOfCodePoints (condition, input, position) { + // 1. Let result be the empty string. + let result = ''; - return true - } + // 2. While position doesn’t point past the end of input and the + // code point at position within input meets the condition condition: + while (position.position < input.length && condition(input[position.position])) { + // 1. Append that code point to the end of result. + result += input[position.position]; - // https://w3c.github.io/webappsec-upgrade-insecure-requests/#upgrade-request - function tryUpgradeRequestToAPotentiallyTrustworthyURL (request) { - // TODO + // 2. Advance position by 1. + position.position++; + } + + // 3. Return result. + return result } /** - * @link {https://html.spec.whatwg.org/multipage/origin.html#same-origin} - * @param {URL} A - * @param {URL} B + * A faster collectASequenceOfCodePoints that only works when comparing a single character. + * @param {string} char + * @param {string} input + * @param {{ position: number }} position */ - function sameOrigin (A, B) { - // 1. If A and B are the same opaque origin, then return true. - if (A.origin === B.origin && A.origin === 'null') { - return true - } + function collectASequenceOfCodePointsFast (char, input, position) { + const idx = input.indexOf(char, position.position); + const start = position.position; - // 2. If A and B are both tuple origins and their schemes, - // hosts, and port are identical, then return true. - if (A.protocol === B.protocol && A.hostname === B.hostname && A.port === B.port) { - return true + if (idx === -1) { + position.position = input.length; + return input.slice(start) } - // 3. Return false. - return false + position.position = idx; + return input.slice(start, position.position) } - function createDeferredPromise () { - let res; - let rej; - const promise = new Promise((resolve, reject) => { - res = resolve; - rej = reject; - }); - - return { promise, resolve: res, reject: rej } - } + // https://url.spec.whatwg.org/#string-percent-decode + /** @param {string} input */ + function stringPercentDecode (input) { + // 1. Let bytes be the UTF-8 encoding of input. + const bytes = encoder.encode(input); - function isAborted (fetchParams) { - return fetchParams.controller.state === 'aborted' + // 2. Return the percent-decoding of bytes. + return percentDecode(bytes) } - function isCancelled (fetchParams) { - return fetchParams.controller.state === 'aborted' || - fetchParams.controller.state === 'terminated' + /** + * @param {number} byte + */ + function isHexCharByte (byte) { + // 0-9 A-F a-f + return (byte >= 0x30 && byte <= 0x39) || (byte >= 0x41 && byte <= 0x46) || (byte >= 0x61 && byte <= 0x66) } - const normalizeMethodRecord = { - delete: 'DELETE', - DELETE: 'DELETE', - get: 'GET', - GET: 'GET', - head: 'HEAD', - HEAD: 'HEAD', - options: 'OPTIONS', - OPTIONS: 'OPTIONS', - post: 'POST', - POST: 'POST', - put: 'PUT', - PUT: 'PUT' - }; - - // Note: object prototypes should not be able to be referenced. e.g. `Object#hasOwnProperty`. - Object.setPrototypeOf(normalizeMethodRecord, null); - /** - * @see https://fetch.spec.whatwg.org/#concept-method-normalize - * @param {string} method + * @param {number} byte */ - function normalizeMethod (method) { - return normalizeMethodRecord[method.toLowerCase()] ?? method + function hexByteToNumber (byte) { + return ( + // 0-9 + byte >= 0x30 && byte <= 0x39 + ? (byte - 48) + // Convert to uppercase + // ((byte & 0xDF) - 65) + 10 + : ((byte & 0xDF) - 55) + ) } - // https://infra.spec.whatwg.org/#serialize-a-javascript-value-to-a-json-string - function serializeJavascriptValueToJSONString (value) { - // 1. Let result be ? Call(%JSON.stringify%, undefined, « value »). - const result = JSON.stringify(value); + // https://url.spec.whatwg.org/#percent-decode + /** @param {Uint8Array} input */ + function percentDecode (input) { + const length = input.length; + // 1. Let output be an empty byte sequence. + /** @type {Uint8Array} */ + const output = new Uint8Array(length); + let j = 0; + // 2. For each byte byte in input: + for (let i = 0; i < length; ++i) { + const byte = input[i]; - // 2. If result is undefined, then throw a TypeError. - if (result === undefined) { - throw new TypeError('Value is not JSON serializable') - } + // 1. If byte is not 0x25 (%), then append byte to output. + if (byte !== 0x25) { + output[j++] = byte; - // 3. Assert: result is a string. - assert(typeof result === 'string'); + // 2. Otherwise, if byte is 0x25 (%) and the next two bytes + // after byte in input are not in the ranges + // 0x30 (0) to 0x39 (9), 0x41 (A) to 0x46 (F), + // and 0x61 (a) to 0x66 (f), all inclusive, append byte + // to output. + } else if ( + byte === 0x25 && + !(isHexCharByte(input[i + 1]) && isHexCharByte(input[i + 2])) + ) { + output[j++] = 0x25; - // 4. Return result. - return result - } + // 3. Otherwise: + } else { + // 1. Let bytePoint be the two bytes after byte in input, + // decoded, and then interpreted as hexadecimal number. + // 2. Append a byte whose value is bytePoint to output. + output[j++] = (hexByteToNumber(input[i + 1]) << 4) | hexByteToNumber(input[i + 2]); - // https://tc39.es/ecma262/#sec-%25iteratorprototype%25-object - const esIteratorPrototype = Object.getPrototypeOf(Object.getPrototypeOf([][Symbol.iterator]())); + // 3. Skip the next two bytes in input. + i += 2; + } + } - /** - * @see https://webidl.spec.whatwg.org/#dfn-iterator-prototype-object - * @param {() => unknown[]} iterator - * @param {string} name name of the instance - * @param {'key'|'value'|'key+value'} kind - */ - function makeIterator (iterator, name, kind) { - const object = { - index: 0, - kind, - target: iterator - }; + // 3. Return output. + return length === j ? output : output.subarray(0, j) + } - const i = { - next () { - // 1. Let interface be the interface for which the iterator prototype object exists. + // https://mimesniff.spec.whatwg.org/#parse-a-mime-type + /** @param {string} input */ + function parseMIMEType (input) { + // 1. Remove any leading and trailing HTTP whitespace + // from input. + input = removeHTTPWhitespace(input, true, true); - // 2. Let thisValue be the this value. + // 2. Let position be a position variable for input, + // initially pointing at the start of input. + const position = { position: 0 }; - // 3. Let object be ? ToObject(thisValue). + // 3. Let type be the result of collecting a sequence + // of code points that are not U+002F (/) from + // input, given position. + const type = collectASequenceOfCodePointsFast( + '/', + input, + position + ); - // 4. If object is a platform object, then perform a security - // check, passing: + // 4. If type is the empty string or does not solely + // contain HTTP token code points, then return failure. + // https://mimesniff.spec.whatwg.org/#http-token-code-point + if (type.length === 0 || !HTTP_TOKEN_CODEPOINTS.test(type)) { + return 'failure' + } - // 5. If object is not a default iterator object for interface, - // then throw a TypeError. - if (Object.getPrototypeOf(this) !== i) { - throw new TypeError( - `'next' called on an object that does not implement interface ${name} Iterator.` - ) - } + // 5. If position is past the end of input, then return + // failure + if (position.position > input.length) { + return 'failure' + } - // 6. Let index be object’s index. - // 7. Let kind be object’s kind. - // 8. Let values be object’s target's value pairs to iterate over. - const { index, kind, target } = object; - const values = target(); + // 6. Advance position by 1. (This skips past U+002F (/).) + position.position++; - // 9. Let len be the length of values. - const len = values.length; + // 7. Let subtype be the result of collecting a sequence of + // code points that are not U+003B (;) from input, given + // position. + let subtype = collectASequenceOfCodePointsFast( + ';', + input, + position + ); - // 10. If index is greater than or equal to len, then return - // CreateIterResultObject(undefined, true). - if (index >= len) { - return { value: undefined, done: true } - } + // 8. Remove any trailing HTTP whitespace from subtype. + subtype = removeHTTPWhitespace(subtype, false, true); - // 11. Let pair be the entry in values at index index. - const pair = values[index]; + // 9. If subtype is the empty string or does not solely + // contain HTTP token code points, then return failure. + if (subtype.length === 0 || !HTTP_TOKEN_CODEPOINTS.test(subtype)) { + return 'failure' + } - // 12. Set object’s index to index + 1. - object.index = index + 1; + const typeLowercase = type.toLowerCase(); + const subtypeLowercase = subtype.toLowerCase(); - // 13. Return the iterator result for pair and kind. - return iteratorResult(pair, kind) - }, - // The class string of an iterator prototype object for a given interface is the - // result of concatenating the identifier of the interface and the string " Iterator". - [Symbol.toStringTag]: `${name} Iterator` + // 10. Let mimeType be a new MIME type record whose type + // is type, in ASCII lowercase, and subtype is subtype, + // in ASCII lowercase. + // https://mimesniff.spec.whatwg.org/#mime-type + const mimeType = { + type: typeLowercase, + subtype: subtypeLowercase, + /** @type {Map} */ + parameters: new Map(), + // https://mimesniff.spec.whatwg.org/#mime-type-essence + essence: `${typeLowercase}/${subtypeLowercase}` }; - // The [[Prototype]] internal slot of an iterator prototype object must be %IteratorPrototype%. - Object.setPrototypeOf(i, esIteratorPrototype); - // esIteratorPrototype needs to be the prototype of i - // which is the prototype of an empty object. Yes, it's confusing. - return Object.setPrototypeOf({}, i) - } - - // https://webidl.spec.whatwg.org/#iterator-result - function iteratorResult (pair, kind) { - let result; - - // 1. Let result be a value determined by the value of kind: - switch (kind) { - case 'key': { - // 1. Let idlKey be pair’s key. - // 2. Let key be the result of converting idlKey to an - // ECMAScript value. - // 3. result is key. - result = pair[0]; - break - } - case 'value': { - // 1. Let idlValue be pair’s value. - // 2. Let value be the result of converting idlValue to - // an ECMAScript value. - // 3. result is value. - result = pair[1]; - break + // 11. While position is not past the end of input: + while (position.position < input.length) { + // 1. Advance position by 1. (This skips past U+003B (;).) + position.position++; + + // 2. Collect a sequence of code points that are HTTP + // whitespace from input given position. + collectASequenceOfCodePoints( + // https://fetch.spec.whatwg.org/#http-whitespace + char => HTTP_WHITESPACE_REGEX.test(char), + input, + position + ); + + // 3. Let parameterName be the result of collecting a + // sequence of code points that are not U+003B (;) + // or U+003D (=) from input, given position. + let parameterName = collectASequenceOfCodePoints( + (char) => char !== ';' && char !== '=', + input, + position + ); + + // 4. Set parameterName to parameterName, in ASCII + // lowercase. + parameterName = parameterName.toLowerCase(); + + // 5. If position is not past the end of input, then: + if (position.position < input.length) { + // 1. If the code point at position within input is + // U+003B (;), then continue. + if (input[position.position] === ';') { + continue + } + + // 2. Advance position by 1. (This skips past U+003D (=).) + position.position++; } - case 'key+value': { - // 1. Let idlKey be pair’s key. - // 2. Let idlValue be pair’s value. - // 3. Let key be the result of converting idlKey to an - // ECMAScript value. - // 4. Let value be the result of converting idlValue to - // an ECMAScript value. - // 5. Let array be ! ArrayCreate(2). - // 6. Call ! CreateDataProperty(array, "0", key). - // 7. Call ! CreateDataProperty(array, "1", value). - // 8. result is array. - result = pair; + + // 6. If position is past the end of input, then break. + if (position.position > input.length) { break } - } - // 2. Return CreateIterResultObject(result, false). - return { value: result, done: false } - } + // 7. Let parameterValue be null. + let parameterValue = null; - /** - * @see https://fetch.spec.whatwg.org/#body-fully-read - */ - async function fullyReadBody (body, processBody, processBodyError) { - // 1. If taskDestination is null, then set taskDestination to - // the result of starting a new parallel queue. + // 8. If the code point at position within input is + // U+0022 ("), then: + if (input[position.position] === '"') { + // 1. Set parameterValue to the result of collecting + // an HTTP quoted string from input, given position + // and the extract-value flag. + parameterValue = collectAnHTTPQuotedString(input, position, true); - // 2. Let successSteps given a byte sequence bytes be to queue a - // fetch task to run processBody given bytes, with taskDestination. - const successSteps = processBody; + // 2. Collect a sequence of code points that are not + // U+003B (;) from input, given position. + collectASequenceOfCodePointsFast( + ';', + input, + position + ); - // 3. Let errorSteps be to queue a fetch task to run processBodyError, - // with taskDestination. - const errorSteps = processBodyError; + // 9. Otherwise: + } else { + // 1. Set parameterValue to the result of collecting + // a sequence of code points that are not U+003B (;) + // from input, given position. + parameterValue = collectASequenceOfCodePointsFast( + ';', + input, + position + ); - // 4. Let reader be the result of getting a reader for body’s stream. - // If that threw an exception, then run errorSteps with that - // exception and return. - let reader; + // 2. Remove any trailing HTTP whitespace from parameterValue. + parameterValue = removeHTTPWhitespace(parameterValue, false, true); - try { - reader = body.stream.getReader(); - } catch (e) { - errorSteps(e); - return - } + // 3. If parameterValue is the empty string, then continue. + if (parameterValue.length === 0) { + continue + } + } - // 5. Read all bytes from reader, given successSteps and errorSteps. - try { - const result = await readAllBytes(reader); - successSteps(result); - } catch (e) { - errorSteps(e); + // 10. If all of the following are true + // - parameterName is not the empty string + // - parameterName solely contains HTTP token code points + // - parameterValue solely contains HTTP quoted-string token code points + // - mimeType’s parameters[parameterName] does not exist + // then set mimeType’s parameters[parameterName] to parameterValue. + 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); + } } + + // 12. Return mimeType. + return mimeType } - /** @type {ReadableStream} */ - let ReadableStream = globalThis.ReadableStream; + // https://infra.spec.whatwg.org/#forgiving-base64-decode + /** @param {string} data */ + function forgivingBase64 (data) { + // 1. Remove all ASCII whitespace from data. + data = data.replace(ASCII_WHITESPACE_REPLACE_REGEX, ''); // eslint-disable-line - function isReadableStreamLike (stream) { - if (!ReadableStream) { - ReadableStream = require$$14.ReadableStream; + let dataLength = data.length; + // 2. If data’s code point length divides by 4 leaving + // no remainder, then: + if (dataLength % 4 === 0) { + // 1. If data ends with one or two U+003D (=) code points, + // then remove them from data. + if (data.charCodeAt(dataLength - 1) === 0x003D) { + --dataLength; + if (data.charCodeAt(dataLength - 1) === 0x003D) { + --dataLength; + } + } } - return stream instanceof ReadableStream || ( - stream[Symbol.toStringTag] === 'ReadableStream' && - typeof stream.tee === 'function' - ) - } - - const MAXIMUM_ARGUMENT_LENGTH = 65535; - - /** - * @see https://infra.spec.whatwg.org/#isomorphic-decode - * @param {number[]|Uint8Array} input - */ - function isomorphicDecode (input) { - // 1. To isomorphic decode a byte sequence input, return a string whose code point - // length is equal to input’s length and whose code points have the same values - // as the values of input’s bytes, in the same order. + // 3. If data’s code point length divides by 4 leaving + // a remainder of 1, then return failure. + if (dataLength % 4 === 1) { + return 'failure' + } - if (input.length < MAXIMUM_ARGUMENT_LENGTH) { - return String.fromCharCode(...input) + // 4. If data contains a code point that is not one of + // U+002B (+) + // U+002F (/) + // ASCII alphanumeric + // then return failure. + if (/[^+/0-9A-Za-z]/.test(data.length === dataLength ? data : data.substring(0, dataLength))) { + return 'failure' } - return input.reduce((previous, current) => previous + String.fromCharCode(current), '') + const buffer = Buffer.from(data, 'base64'); + return new Uint8Array(buffer.buffer, buffer.byteOffset, buffer.byteLength) } + // https://fetch.spec.whatwg.org/#collect-an-http-quoted-string + // tests: https://fetch.spec.whatwg.org/#example-http-quoted-string /** - * @param {ReadableStreamController} controller + * @param {string} input + * @param {{ position: number }} position + * @param {boolean?} extractValue */ - function readableStreamClose (controller) { - try { - controller.close(); - } catch (err) { - // TODO: add comment explaining why this error occurs. - if (!err.message.includes('Controller is already closed')) { - throw err + function collectAnHTTPQuotedString (input, position, extractValue) { + // 1. Let positionStart be position. + const positionStart = position.position; + + // 2. Let value be the empty string. + let value = ''; + + // 3. Assert: the code point at position within input + // is U+0022 ("). + assert(input[position.position] === '"'); + + // 4. Advance position by 1. + position.position++; + + // 5. While true: + while (true) { + // 1. Append the result of collecting a sequence of code points + // that are not U+0022 (") or U+005C (\) from input, given + // position, to value. + value += collectASequenceOfCodePoints( + (char) => char !== '"' && char !== '\\', + input, + position + ); + + // 2. If position is past the end of input, then break. + if (position.position >= input.length) { + break + } + + // 3. Let quoteOrBackslash be the code point at position within + // input. + const quoteOrBackslash = input[position.position]; + + // 4. Advance position by 1. + position.position++; + + // 5. If quoteOrBackslash is U+005C (\), then: + if (quoteOrBackslash === '\\') { + // 1. If position is past the end of input, then append + // U+005C (\) to value and break. + if (position.position >= input.length) { + value += '\\'; + break + } + + // 2. Append the code point at position within input to value. + value += input[position.position]; + + // 3. Advance position by 1. + position.position++; + + // 6. Otherwise: + } else { + // 1. Assert: quoteOrBackslash is U+0022 ("). + assert(quoteOrBackslash === '"'); + + // 2. Break. + break } } - } - /** - * @see https://infra.spec.whatwg.org/#isomorphic-encode - * @param {string} input - */ - function isomorphicEncode (input) { - // 1. Assert: input contains no code points greater than U+00FF. - for (let i = 0; i < input.length; i++) { - assert(input.charCodeAt(i) <= 0xFF); + // 6. If the extract-value flag is set, then return value. + if (extractValue) { + return value } - // 2. Return a byte sequence whose length is equal to input’s code - // point length and whose bytes have the same values as the - // values of input’s code points, in the same order - return input + // 7. Return the code points from positionStart to position, + // inclusive, within input. + return input.slice(positionStart, position.position) } /** - * @see https://streams.spec.whatwg.org/#readablestreamdefaultreader-read-all-bytes - * @see https://streams.spec.whatwg.org/#read-loop - * @param {ReadableStreamDefaultReader} reader + * @see https://mimesniff.spec.whatwg.org/#serialize-a-mime-type */ - async function readAllBytes (reader) { - const bytes = []; - let byteLength = 0; + function serializeAMimeType (mimeType) { + assert(mimeType !== 'failure'); + const { parameters, essence } = mimeType; - while (true) { - const { done, value: chunk } = await reader.read(); + // 1. Let serialization be the concatenation of mimeType’s + // type, U+002F (/), and mimeType’s subtype. + let serialization = essence; - if (done) { - // 1. Call successSteps with bytes. - return Buffer.concat(bytes, byteLength) - } + // 2. For each name → value of mimeType’s parameters: + for (let [name, value] of parameters.entries()) { + // 1. Append U+003B (;) to serialization. + serialization += ';'; - // 1. If chunk is not a Uint8Array object, call failureSteps - // with a TypeError and abort these steps. - if (!isUint8Array(chunk)) { - throw new TypeError('Received non-Uint8Array chunk') - } + // 2. Append name to serialization. + serialization += name; - // 2. Append the bytes represented by chunk to bytes. - bytes.push(chunk); - byteLength += chunk.length; + // 3. Append U+003D (=) to serialization. + serialization += '='; - // 3. Read-loop given reader, bytes, successSteps, and failureSteps. + // 4. If value does not solely contain HTTP token code + // points or value is the empty string, then: + if (!HTTP_TOKEN_CODEPOINTS.test(value)) { + // 1. Precede each occurrence of U+0022 (") or + // U+005C (\) in value with U+005C (\). + value = value.replace(/(\\|")/g, '\\$1'); + + // 2. Prepend U+0022 (") to value. + value = '"' + value; + + // 3. Append U+0022 (") to value. + value += '"'; + } + + // 5. Append value to serialization. + serialization += value; } + + // 3. Return serialization. + return serialization } /** - * @see https://fetch.spec.whatwg.org/#is-local - * @param {URL} url + * @see https://fetch.spec.whatwg.org/#http-whitespace + * @param {number} char */ - function urlIsLocal (url) { - assert('protocol' in url); // ensure it's a url object - - const protocol = url.protocol; - - return protocol === 'about:' || protocol === 'blob:' || protocol === 'data:' + function isHTTPWhiteSpace (char) { + // "\r\n\t " + return char === 0x00d || char === 0x00a || char === 0x009 || char === 0x020 } /** - * @param {string|URL} url + * @see https://fetch.spec.whatwg.org/#http-whitespace + * @param {string} str + * @param {boolean} [leading=true] + * @param {boolean} [trailing=true] */ - function urlHasHttpsScheme (url) { - if (typeof url === 'string') { - return url.startsWith('https:') - } - - return url.protocol === 'https:' + function removeHTTPWhitespace (str, leading = true, trailing = true) { + return removeChars(str, leading, trailing, isHTTPWhiteSpace) } /** - * @see https://fetch.spec.whatwg.org/#http-scheme - * @param {URL} url + * @see https://infra.spec.whatwg.org/#ascii-whitespace + * @param {number} char */ - function urlIsHttpHttpsScheme (url) { - assert('protocol' in url); // ensure it's a url object - - const protocol = url.protocol; + function isASCIIWhitespace (char) { + // "\r\n\t\f " + return char === 0x00d || char === 0x00a || char === 0x009 || char === 0x00c || char === 0x020 + } - return protocol === 'http:' || protocol === 'https:' + /** + * @see https://infra.spec.whatwg.org/#strip-leading-and-trailing-ascii-whitespace + * @param {string} str + * @param {boolean} [leading=true] + * @param {boolean} [trailing=true] + */ + function removeASCIIWhitespace (str, leading = true, trailing = true) { + return removeChars(str, leading, trailing, isASCIIWhitespace) } /** - * Fetch supports node >= 16.8.0, but Object.hasOwn was added in v16.9.0. + * @param {string} str + * @param {boolean} leading + * @param {boolean} trailing + * @param {(charCode: number) => boolean} predicate + * @returns */ - const hasOwn = Object.hasOwn || ((dict, key) => Object.prototype.hasOwnProperty.call(dict, key)); + function removeChars (str, leading, trailing, predicate) { + let lead = 0; + let trail = str.length - 1; - util$6 = { - isAborted, - isCancelled, - createDeferredPromise, - ReadableStreamFrom, - toUSVString, - tryUpgradeRequestToAPotentiallyTrustworthyURL, - coarsenedSharedCurrentTime, - determineRequestsReferrer, - makePolicyContainer, - clonePolicyContainer, - appendFetchMetadata, - appendRequestOriginHeader, - TAOCheck, - corsCheck, - crossOriginResourcePolicyCheck, - createOpaqueTimingInfo, - setRequestReferrerPolicyOnRedirect, - isValidHTTPToken, - requestBadPort, - requestCurrentURL, - responseURL, - responseLocationURL, - isBlobLike, - isURLPotentiallyTrustworthy, - isValidReasonPhrase, - sameOrigin, - normalizeMethod, - serializeJavascriptValueToJSONString, - makeIterator, - isValidHeaderName, - isValidHeaderValue, - hasOwn, - isErrorLike, - fullyReadBody, - bytesMatch, - isReadableStreamLike, - readableStreamClose, - isomorphicEncode, - isomorphicDecode, - urlIsLocal, - urlHasHttpsScheme, - urlIsHttpHttpsScheme, - readAllBytes, - normalizeMethodRecord, - parseMetadata - }; - return util$6; -} + if (leading) { + while (lead < str.length && predicate(str.charCodeAt(lead))) lead++; + } -var symbols$3; -var hasRequiredSymbols$3; + if (trailing) { + while (trail > 0 && predicate(str.charCodeAt(trail))) trail--; + } -function requireSymbols$3 () { - if (hasRequiredSymbols$3) return symbols$3; - hasRequiredSymbols$3 = 1; + return lead === 0 && trail === str.length - 1 ? str : str.slice(lead, trail + 1) + } - symbols$3 = { - kUrl: Symbol('url'), - kHeaders: Symbol('headers'), - kSignal: Symbol('signal'), - kState: Symbol('state'), - kGuard: Symbol('guard'), - kRealm: Symbol('realm') + /** + * @see https://infra.spec.whatwg.org/#isomorphic-decode + * @param {Uint8Array} input + * @returns {string} + */ + function isomorphicDecode (input) { + // 1. To isomorphic decode a byte sequence input, return a string whose code point + // length is equal to input’s length and whose code points have the same values + // as the values of input’s bytes, in the same order. + 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 + } + + /** + * @see https://mimesniff.spec.whatwg.org/#minimize-a-supported-mime-type + * @param {Exclude, 'failure'>} mimeType + */ + 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': + // 1. If mimeType is a JavaScript MIME type, then return "text/javascript". + return 'text/javascript' + case 'application/json': + case 'text/json': + // 2. If mimeType is a JSON MIME type, then return "application/json". + return 'application/json' + case 'image/svg+xml': + // 3. If mimeType’s essence is "image/svg+xml", then return "image/svg+xml". + return 'image/svg+xml' + case 'text/xml': + case 'application/xml': + // 4. If mimeType is an XML MIME type, then return "application/xml". + return 'application/xml' + } + + // 2. If mimeType is a JSON MIME type, then return "application/json". + if (mimeType.subtype.endsWith('+json')) { + return 'application/json' + } + + // 4. If mimeType is an XML MIME type, then return "application/xml". + if (mimeType.subtype.endsWith('+xml')) { + return 'application/xml' + } + + // 5. If mimeType is supported by the user agent, then return mimeType’s essence. + // Technically, node doesn't support any mimetypes. + + // 6. Return the empty string. + return '' + } + + dataUrl = { + dataURLProcessor, + URLSerializer, + collectASequenceOfCodePoints, + collectASequenceOfCodePointsFast, + stringPercentDecode, + parseMIMEType, + collectAnHTTPQuotedString, + serializeAMimeType, + removeChars, + removeHTTPWhitespace, + minimizeSupportedMimeType, + HTTP_TOKEN_CODEPOINTS, + isomorphicDecode }; - return symbols$3; + return dataUrl; } var webidl_1; @@ -4596,10 +5060,11 @@ function requireWebidl () { if (hasRequiredWebidl) return webidl_1; hasRequiredWebidl = 1; - const { types } = require$$0$2; - const { hasOwn, toUSVString } = requireUtil$6(); + const { types, inspect } = require$$0$6; + const { markAsUncloneable } = require$$1$1; + const { toUSVString } = requireUtil$8(); - /** @type {import('../../types/webidl').Webidl} */ + /** @type {import('../../../types/webidl').Webidl} */ const webidl = {}; webidl.converters = {}; webidl.util = {}; @@ -4629,11 +5094,19 @@ function requireWebidl () { }; // https://webidl.spec.whatwg.org/#implements - webidl.brandCheck = function (V, I, opts = undefined) { - if (opts?.strict !== false && !(V instanceof I)) { - throw new TypeError('Illegal invocation') + 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'; // node compat. + throw err + } } else { - return V?.[Symbol.toStringTag] === I.prototype[Symbol.toStringTag] + if (V?.[Symbol.toStringTag] !== I.prototype[Symbol.toStringTag]) { + const err = new TypeError('Illegal invocation'); + err.code = 'ERR_INVALID_THIS'; // node compat. + throw err + } } }; @@ -4642,7 +5115,7 @@ function requireWebidl () { throw webidl.errors.exception({ message: `${min} argument${min !== 1 ? 's' : ''} required, ` + `but${length ? ' only' : ''} ${length} found.`, - ...ctx + header: ctx }) } }; @@ -4674,8 +5147,9 @@ function requireWebidl () { } }; + webidl.util.markAsUncloneable = markAsUncloneable || (() => {}); // https://webidl.spec.whatwg.org/#abstract-opdef-converttoint - webidl.util.ConvertToInt = function (V, bitLength, signedness, opts = {}) { + webidl.util.ConvertToInt = function (V, bitLength, signedness, opts) { let upperBound; let lowerBound; @@ -4719,7 +5193,7 @@ function requireWebidl () { // 6. If the conversion is to an IDL type associated // with the [EnforceRange] extended attribute, then: - if (opts.enforceRange === true) { + if (opts?.enforceRange === true) { // 1. If x is NaN, +∞, or −∞, then throw a TypeError. if ( Number.isNaN(x) || @@ -4728,7 +5202,7 @@ function requireWebidl () { ) { throw webidl.errors.exception({ header: 'Integer conversion', - message: `Could not convert ${V} to an integer.` + message: `Could not convert ${webidl.util.Stringify(V)} to an integer.` }) } @@ -4751,7 +5225,7 @@ function requireWebidl () { // 7. If x is not NaN and the conversion is to an IDL // type associated with the [Clamp] extended // attribute, then: - if (!Number.isNaN(x) && opts.clamp === true) { + if (!Number.isNaN(x) && opts?.clamp === true) { // 1. Set x to min(max(x, lowerBound), upperBound). x = Math.min(Math.max(x, lowerBound), upperBound); @@ -4808,21 +5282,37 @@ function requireWebidl () { 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}` + } + }; + // https://webidl.spec.whatwg.org/#es-sequence webidl.sequenceConverter = function (converter) { - return (V) => { + return (V, prefix, argument, Iterable) => { // 1. If Type(V) is not Object, throw a TypeError. if (webidl.util.Type(V) !== 'Object') { throw webidl.errors.exception({ - header: 'Sequence', - message: `Value of type ${webidl.util.Type(V)} is not an Object.` + header: prefix, + message: `${argument} (${webidl.util.Stringify(V)}) is not iterable.` }) } // 2. Let method be ? GetMethod(V, @@iterator). /** @type {Generator} */ - const method = V?.[Symbol.iterator]?.(); + const method = typeof Iterable === 'function' ? Iterable() : V?.[Symbol.iterator]?.(); const seq = []; + let index = 0; // 3. If method is undefined, throw a TypeError. if ( @@ -4830,8 +5320,8 @@ function requireWebidl () { typeof method.next !== 'function' ) { throw webidl.errors.exception({ - header: 'Sequence', - message: 'Object is not an iterator.' + header: prefix, + message: `${argument} is not iterable.` }) } @@ -4843,7 +5333,7 @@ function requireWebidl () { break } - seq.push(converter(value)); + seq.push(converter(value, prefix, `${argument}[${index++}]`)); } return seq @@ -4852,12 +5342,12 @@ function requireWebidl () { // https://webidl.spec.whatwg.org/#es-to-record webidl.recordConverter = function (keyConverter, valueConverter) { - return (O) => { + return (O, prefix, argument) => { // 1. If Type(O) is not Object, throw a TypeError. if (webidl.util.Type(O) !== 'Object') { throw webidl.errors.exception({ - header: 'Record', - message: `Value of type ${webidl.util.Type(O)} is not an Object.` + header: prefix, + message: `${argument} ("${webidl.util.Type(O)}") is not an Object.` }) } @@ -4865,16 +5355,16 @@ function requireWebidl () { const result = {}; if (!types.isProxy(O)) { - // Object.keys only returns enumerable properties - const keys = Object.keys(O); + // 1. Let desc be ? O.[[GetOwnProperty]](key). + const keys = [...Object.getOwnPropertyNames(O), ...Object.getOwnPropertySymbols(O)]; for (const key of keys) { // 1. Let typedKey be key converted to an IDL value of type K. - const typedKey = keyConverter(key); + const typedKey = keyConverter(key, prefix, argument); // 2. Let value be ? Get(O, key). // 3. Let typedValue be value converted to an IDL value of type V. - const typedValue = valueConverter(O[key]); + const typedValue = valueConverter(O[key], prefix, argument); // 4. Set result[typedKey] to typedValue. result[typedKey] = typedValue; @@ -4895,11 +5385,11 @@ function requireWebidl () { // 2. If desc is not undefined and desc.[[Enumerable]] is true: if (desc?.enumerable) { // 1. Let typedKey be key converted to an IDL value of type K. - const typedKey = keyConverter(key); + const typedKey = keyConverter(key, prefix, argument); // 2. Let value be ? Get(O, key). // 3. Let typedValue be value converted to an IDL value of type V. - const typedValue = valueConverter(O[key]); + const typedValue = valueConverter(O[key], prefix, argument); // 4. Set result[typedKey] to typedValue. result[typedKey] = typedValue; @@ -4912,11 +5402,11 @@ function requireWebidl () { }; webidl.interfaceConverter = function (i) { - return (V, opts = {}) => { - if (opts.strict !== false && !(V instanceof i)) { + return (V, prefix, argument, opts) => { + if (opts?.strict !== false && !(V instanceof i)) { throw webidl.errors.exception({ - header: i.name, - message: `Expected ${V} to be an instance of ${i.name}.` + header: prefix, + message: `Expected ${argument} ("${webidl.util.Stringify(V)}") to be an instance of ${i.name}.` }) } @@ -4925,7 +5415,7 @@ function requireWebidl () { }; webidl.dictionaryConverter = function (converters) { - return (dictionary) => { + return (dictionary, prefix, argument) => { const type = webidl.util.Type(dictionary); const dict = {}; @@ -4933,7 +5423,7 @@ function requireWebidl () { return dict } else if (type !== 'Object') { throw webidl.errors.exception({ - header: 'Dictionary', + header: prefix, message: `Expected ${dictionary} to be one of: Null, Undefined, Object.` }) } @@ -4942,35 +5432,35 @@ function requireWebidl () { const { key, defaultValue, required, converter } = options; if (required === true) { - if (!hasOwn(dictionary, key)) { + if (!Object.hasOwn(dictionary, key)) { throw webidl.errors.exception({ - header: 'Dictionary', + header: prefix, message: `Missing required key "${key}".` }) } } let value = dictionary[key]; - const hasDefault = hasOwn(options, 'defaultValue'); + const hasDefault = Object.hasOwn(options, 'defaultValue'); // Only use defaultValue if value is undefined and // a defaultValue options was provided. if (hasDefault && value !== null) { - value = value ?? defaultValue; + value ??= defaultValue(); } // A key can be optional and have no default value. // When this happens, do not perform a conversion, // and do not assign the key a value. if (required || hasDefault || value !== undefined) { - value = converter(value); + value = converter(value, prefix, `${argument}.${key}`); if ( options.allowedValues && !options.allowedValues.includes(value) ) { throw webidl.errors.exception({ - header: 'Dictionary', + header: prefix, message: `${value} is not an accepted type. Expected one of ${options.allowedValues.join(', ')}.` }) } @@ -4984,28 +5474,31 @@ function requireWebidl () { }; webidl.nullableConverter = function (converter) { - return (V) => { + return (V, prefix, argument) => { if (V === null) { return V } - return converter(V) + return converter(V, prefix, argument) } }; // https://webidl.spec.whatwg.org/#es-DOMString - webidl.converters.DOMString = function (V, opts = {}) { + webidl.converters.DOMString = function (V, prefix, argument, opts) { // 1. If V is null and the conversion is to an IDL type // associated with the [LegacyNullToEmptyString] // extended attribute, then return the DOMString value // that represents the empty string. - if (V === null && opts.legacyNullToEmptyString) { + if (V === null && opts?.legacyNullToEmptyString) { return '' } // 2. Let x be ? ToString(V). if (typeof V === 'symbol') { - throw new TypeError('Could not convert argument of type symbol to string.') + throw webidl.errors.exception({ + header: prefix, + message: `${argument} is a symbol, which cannot be converted to a DOMString.` + }) } // 3. Return the IDL DOMString value that represents the @@ -5015,10 +5508,10 @@ function requireWebidl () { }; // https://webidl.spec.whatwg.org/#es-ByteString - webidl.converters.ByteString = function (V) { + webidl.converters.ByteString = function (V, prefix, argument) { // 1. Let x be ? ToString(V). // Note: DOMString converter perform ? ToString(V) - const x = webidl.converters.DOMString(V); + const x = webidl.converters.DOMString(V, prefix, argument); // 2. If the value of any element of x is greater than // 255, then throw a TypeError. @@ -5038,6 +5531,7 @@ function requireWebidl () { }; // https://webidl.spec.whatwg.org/#es-USVString + // TODO: rewrite this so we can control the errors thrown webidl.converters.USVString = toUSVString; // https://webidl.spec.whatwg.org/#es-boolean @@ -5056,9 +5550,9 @@ function requireWebidl () { }; // https://webidl.spec.whatwg.org/#es-long-long - webidl.converters['long long'] = function (V) { + webidl.converters['long long'] = function (V, prefix, argument) { // 1. Let x be ? ConvertToInt(V, 64, "signed"). - const x = webidl.util.ConvertToInt(V, 64, 'signed'); + const x = webidl.util.ConvertToInt(V, 64, 'signed', undefined, prefix, argument); // 2. Return the IDL long long value that represents // the same numeric value as x. @@ -5066,9 +5560,9 @@ function requireWebidl () { }; // https://webidl.spec.whatwg.org/#es-unsigned-long-long - webidl.converters['unsigned long long'] = function (V) { + webidl.converters['unsigned long long'] = function (V, prefix, argument) { // 1. Let x be ? ConvertToInt(V, 64, "unsigned"). - const x = webidl.util.ConvertToInt(V, 64, 'unsigned'); + const x = webidl.util.ConvertToInt(V, 64, 'unsigned', undefined, prefix, argument); // 2. Return the IDL unsigned long long value that // represents the same numeric value as x. @@ -5076,9 +5570,9 @@ function requireWebidl () { }; // https://webidl.spec.whatwg.org/#es-unsigned-long - webidl.converters['unsigned long'] = function (V) { + webidl.converters['unsigned long'] = function (V, prefix, argument) { // 1. Let x be ? ConvertToInt(V, 32, "unsigned"). - const x = webidl.util.ConvertToInt(V, 32, 'unsigned'); + const x = webidl.util.ConvertToInt(V, 32, 'unsigned', undefined, prefix, argument); // 2. Return the IDL unsigned long value that // represents the same numeric value as x. @@ -5086,9 +5580,9 @@ function requireWebidl () { }; // https://webidl.spec.whatwg.org/#es-unsigned-short - webidl.converters['unsigned short'] = function (V, opts) { + webidl.converters['unsigned short'] = function (V, prefix, argument, opts) { // 1. Let x be ? ConvertToInt(V, 16, "unsigned"). - const x = webidl.util.ConvertToInt(V, 16, 'unsigned', opts); + const x = webidl.util.ConvertToInt(V, 16, 'unsigned', opts, prefix, argument); // 2. Return the IDL unsigned short value that represents // the same numeric value as x. @@ -5096,7 +5590,7 @@ function requireWebidl () { }; // https://webidl.spec.whatwg.org/#idl-ArrayBuffer - webidl.converters.ArrayBuffer = function (V, opts = {}) { + webidl.converters.ArrayBuffer = function (V, prefix, argument, opts) { // 1. If Type(V) is not Object, or V does not have an // [[ArrayBufferData]] internal slot, then throw a // TypeError. @@ -5107,8 +5601,8 @@ function requireWebidl () { !types.isAnyArrayBuffer(V) ) { throw webidl.errors.conversionFailed({ - prefix: `${V}`, - argument: `${V}`, + prefix, + argument: `${argument} ("${webidl.util.Stringify(V)}")`, types: ['ArrayBuffer'] }) } @@ -5117,7 +5611,7 @@ function requireWebidl () { // with the [AllowShared] extended attribute, and // IsSharedArrayBuffer(V) is true, then throw a // TypeError. - if (opts.allowShared === false && types.isSharedArrayBuffer(V)) { + if (opts?.allowShared === false && types.isSharedArrayBuffer(V)) { throw webidl.errors.exception({ header: 'ArrayBuffer', message: 'SharedArrayBuffer is not allowed.' @@ -5128,14 +5622,19 @@ function requireWebidl () { // with the [AllowResizable] extended attribute, and // IsResizableArrayBuffer(V) is true, then throw a // TypeError. - // Note: resizable ArrayBuffers are currently a proposal. + if (V.resizable || V.growable) { + throw webidl.errors.exception({ + header: 'ArrayBuffer', + message: 'Received a resizable ArrayBuffer.' + }) + } // 4. Return the IDL ArrayBuffer value that is a // reference to the same object as V. return V }; - webidl.converters.TypedArray = function (V, T, opts = {}) { + webidl.converters.TypedArray = function (V, T, prefix, name, opts) { // 1. Let T be the IDL type V is being converted to. // 2. If Type(V) is not Object, or V does not have a @@ -5147,8 +5646,8 @@ function requireWebidl () { V.constructor.name !== T.name ) { throw webidl.errors.conversionFailed({ - prefix: `${T.name}`, - argument: `${V}`, + prefix, + argument: `${name} ("${webidl.util.Stringify(V)}")`, types: [T.name] }) } @@ -5157,7 +5656,7 @@ function requireWebidl () { // with the [AllowShared] extended attribute, and // IsSharedArrayBuffer(V.[[ViewedArrayBuffer]]) is // true, then throw a TypeError. - if (opts.allowShared === false && types.isSharedArrayBuffer(V.buffer)) { + if (opts?.allowShared === false && types.isSharedArrayBuffer(V.buffer)) { throw webidl.errors.exception({ header: 'ArrayBuffer', message: 'SharedArrayBuffer is not allowed.' @@ -5168,20 +5667,25 @@ function requireWebidl () { // with the [AllowResizable] extended attribute, and // IsResizableArrayBuffer(V.[[ViewedArrayBuffer]]) is // true, then throw a TypeError. - // Note: resizable array buffers are currently a proposal + if (V.buffer.resizable || V.buffer.growable) { + throw webidl.errors.exception({ + header: 'ArrayBuffer', + message: 'Received a resizable ArrayBuffer.' + }) + } // 5. Return the IDL value of type T that is a reference // to the same object as V. return V }; - webidl.converters.DataView = function (V, opts = {}) { + webidl.converters.DataView = function (V, prefix, name, opts) { // 1. If Type(V) is not Object, or V does not have a // [[DataView]] internal slot, then throw a TypeError. if (webidl.util.Type(V) !== 'Object' || !types.isDataView(V)) { throw webidl.errors.exception({ - header: 'DataView', - message: 'Object is not a DataView.' + header: prefix, + message: `${name} is not a DataView.` }) } @@ -5189,7 +5693,7 @@ function requireWebidl () { // with the [AllowShared] extended attribute, and // IsSharedArrayBuffer(V.[[ViewedArrayBuffer]]) is true, // then throw a TypeError. - if (opts.allowShared === false && types.isSharedArrayBuffer(V.buffer)) { + if (opts?.allowShared === false && types.isSharedArrayBuffer(V.buffer)) { throw webidl.errors.exception({ header: 'ArrayBuffer', message: 'SharedArrayBuffer is not allowed.' @@ -5200,7 +5704,12 @@ function requireWebidl () { // with the [AllowResizable] extended attribute, and // IsResizableArrayBuffer(V.[[ViewedArrayBuffer]]) is // true, then throw a TypeError. - // Note: resizable ArrayBuffers are currently a proposal + if (V.buffer.resizable || V.buffer.growable) { + throw webidl.errors.exception({ + header: 'ArrayBuffer', + message: 'Received a resizable ArrayBuffer.' + }) + } // 4. Return the IDL DataView value that is a reference // to the same object as V. @@ -5208,20 +5717,24 @@ function requireWebidl () { }; // https://webidl.spec.whatwg.org/#BufferSource - webidl.converters.BufferSource = function (V, opts = {}) { + webidl.converters.BufferSource = function (V, prefix, name, opts) { if (types.isAnyArrayBuffer(V)) { - return webidl.converters.ArrayBuffer(V, opts) + return webidl.converters.ArrayBuffer(V, prefix, name, { ...opts, allowShared: false }) } if (types.isTypedArray(V)) { - return webidl.converters.TypedArray(V, V.constructor) + return webidl.converters.TypedArray(V, V.constructor, prefix, name, { ...opts, allowShared: false }) } if (types.isDataView(V)) { - return webidl.converters.DataView(V, opts) + return webidl.converters.DataView(V, prefix, name, { ...opts, allowShared: false }) } - throw new TypeError(`Could not convert ${V} to a BufferSource.`) + throw webidl.errors.conversionFailed({ + prefix, + argument: `${name} ("${webidl.util.Stringify(V)}")`, + types: ['BufferSource'] + }) }; webidl.converters['sequence'] = webidl.sequenceConverter( @@ -5243,742 +5756,1674 @@ function requireWebidl () { return webidl_1; } -var dataURL; -var hasRequiredDataURL; +var util$7; +var hasRequiredUtil$7; + +function requireUtil$7 () { + if (hasRequiredUtil$7) return util$7; + hasRequiredUtil$7 = 1; -function requireDataURL () { - if (hasRequiredDataURL) return dataURL; - hasRequiredDataURL = 1; + const { Transform } = require$$0$4; + const zlib = require$$1$2; + const { redirectStatusSet, referrerPolicySet: referrerPolicyTokens, badPortsSet } = requireConstants$2(); + const { getGlobalOrigin } = requireGlobal$1(); + const { collectASequenceOfCodePoints, collectAnHTTPQuotedString, removeChars, parseMIMEType } = requireDataUrl(); + const { performance } = require$$5$1; + const { isBlobLike, ReadableStreamFrom, isValidHTTPToken, normalizedMethodRecordsBase } = requireUtil$8(); const assert = require$$0$3; - const { atob } = require$$7; - const { isomorphicDecode } = requireUtil$6(); + const { isUint8Array } = require$$8$1; + const { webidl } = requireWebidl(); - const encoder = new TextEncoder(); + let supportedHashes = []; - /** - * @see https://mimesniff.spec.whatwg.org/#http-token-code-point - */ - const HTTP_TOKEN_CODEPOINTS = /^[!#$%&'*+-.^_|~A-Za-z0-9]+$/; - const HTTP_WHITESPACE_REGEX = /(\u000A|\u000D|\u0009|\u0020)/; // eslint-disable-line - /** - * @see https://mimesniff.spec.whatwg.org/#http-quoted-string-token-code-point - */ - const HTTP_QUOTED_STRING_TOKENS = /[\u0009|\u0020-\u007E|\u0080-\u00FF]/; // eslint-disable-line + // https://nodejs.org/api/crypto.html#determining-if-crypto-support-is-unavailable + /** @type {import('crypto')} */ + let crypto; + try { + crypto = require('node:crypto'); + const possibleRelevantHashes = ['sha256', 'sha384', 'sha512']; + supportedHashes = crypto.getHashes().filter((hash) => possibleRelevantHashes.includes(hash)); + /* c8 ignore next 3 */ + } catch { - // https://fetch.spec.whatwg.org/#data-url-processor - /** @param {URL} dataURL */ - function dataURLProcessor (dataURL) { - // 1. Assert: dataURL’s scheme is "data". - assert(dataURL.protocol === 'data:'); - - // 2. Let input be the result of running the URL - // serializer on dataURL with exclude fragment - // set to true. - let input = URLSerializer(dataURL, true); - - // 3. Remove the leading "data:" string from input. - input = input.slice(5); - - // 4. Let position point at the start of input. - const position = { position: 0 }; - - // 5. Let mimeType be the result of collecting a - // sequence of code points that are not equal - // to U+002C (,), given position. - let mimeType = collectASequenceOfCodePointsFast( - ',', - input, - position - ); + } - // 6. Strip leading and trailing ASCII whitespace - // from mimeType. - // Undici implementation note: we need to store the - // length because if the mimetype has spaces removed, - // the wrong amount will be sliced from the input in - // step #9 - const mimeTypeLength = mimeType.length; - mimeType = removeASCIIWhitespace(mimeType, true, true); + function responseURL (response) { + // https://fetch.spec.whatwg.org/#responses + // A response has an associated URL. It is a pointer to the last URL + // in response’s URL list and null if response’s URL list is empty. + const urlList = response.urlList; + const length = urlList.length; + return length === 0 ? null : urlList[length - 1].toString() + } - // 7. If position is past the end of input, then - // return failure - if (position.position >= input.length) { - return 'failure' + // https://fetch.spec.whatwg.org/#concept-response-location-url + function responseLocationURL (response, requestFragment) { + // 1. If response’s status is not a redirect status, then return null. + if (!redirectStatusSet.has(response.status)) { + return null } - // 8. Advance position by 1. - position.position++; + // 2. Let location be the result of extracting header list values given + // `Location` and response’s header list. + let location = response.headersList.get('location', true); - // 9. Let encodedBody be the remainder of input. - const encodedBody = input.slice(mimeTypeLength + 1); + // 3. If location is a header value, then set location to the result of + // parsing location with response’s URL. + if (location !== null && isValidHeaderValue(location)) { + if (!isValidEncodedURL(location)) { + // Some websites respond location header in UTF-8 form without encoding them as ASCII + // and major browsers redirect them to correctly UTF-8 encoded addresses. + // Here, we handle that behavior in the same way. + location = normalizeBinaryStringToUtf8(location); + } + location = new URL(location, responseURL(response)); + } - // 10. Let body be the percent-decoding of encodedBody. - let body = stringPercentDecode(encodedBody); + // 4. If location is a URL whose fragment is null, then set location’s + // fragment to requestFragment. + if (location && !location.hash) { + location.hash = requestFragment; + } - // 11. If mimeType ends with U+003B (;), followed by - // zero or more U+0020 SPACE, followed by an ASCII - // case-insensitive match for "base64", then: - if (/;(\u0020){0,}base64$/i.test(mimeType)) { - // 1. Let stringBody be the isomorphic decode of body. - const stringBody = isomorphicDecode(body); + // 5. Return location. + return location + } - // 2. Set body to the forgiving-base64 decode of - // stringBody. - body = forgivingBase64(stringBody); + /** + * @see https://www.rfc-editor.org/rfc/rfc1738#section-2.2 + * @param {string} url + * @returns {boolean} + */ + function isValidEncodedURL (url) { + for (let i = 0; i < url.length; ++i) { + const code = url.charCodeAt(i); - // 3. If body is failure, then return failure. - if (body === 'failure') { - return 'failure' + if ( + code > 0x7E || // Non-US-ASCII + DEL + code < 0x20 // Control characters NUL - US + ) { + return false } + } + return true + } - // 4. Remove the last 6 code points from mimeType. - mimeType = mimeType.slice(0, -6); + /** + * If string contains non-ASCII characters, assumes it's UTF-8 encoded and decodes it. + * Since UTF-8 is a superset of ASCII, this will work for ASCII strings as well. + * @param {string} value + * @returns {string} + */ + function normalizeBinaryStringToUtf8 (value) { + return Buffer.from(value, 'binary').toString('utf8') + } - // 5. Remove trailing U+0020 SPACE code points from mimeType, - // if any. - mimeType = mimeType.replace(/(\u0020)+$/, ''); + /** @returns {URL} */ + function requestCurrentURL (request) { + return request.urlList[request.urlList.length - 1] + } - // 6. Remove the last U+003B (;) code point from mimeType. - mimeType = mimeType.slice(0, -1); - } + function requestBadPort (request) { + // 1. Let url be request’s current URL. + const url = requestCurrentURL(request); - // 12. If mimeType starts with U+003B (;), then prepend - // "text/plain" to mimeType. - if (mimeType.startsWith(';')) { - mimeType = 'text/plain' + mimeType; + // 2. If url’s scheme is an HTTP(S) scheme and url’s port is a bad port, + // then return blocked. + if (urlIsHttpHttpsScheme(url) && badPortsSet.has(url.port)) { + return 'blocked' } - // 13. Let mimeTypeRecord be the result of parsing - // mimeType. - let mimeTypeRecord = parseMIMEType(mimeType); + // 3. Return allowed. + return 'allowed' + } - // 14. If mimeTypeRecord is failure, then set - // mimeTypeRecord to text/plain;charset=US-ASCII. - if (mimeTypeRecord === 'failure') { - mimeTypeRecord = parseMIMEType('text/plain;charset=US-ASCII'); - } + function isErrorLike (object) { + return object instanceof Error || ( + object?.constructor?.name === 'Error' || + object?.constructor?.name === 'DOMException' + ) + } - // 15. Return a new data: URL struct whose MIME - // type is mimeTypeRecord and body is body. - // https://fetch.spec.whatwg.org/#data-url-struct - return { mimeType: mimeTypeRecord, body } + // Check whether |statusText| is a ByteString and + // matches the Reason-Phrase token production. + // RFC 2616: https://tools.ietf.org/html/rfc2616 + // RFC 7230: https://tools.ietf.org/html/rfc7230 + // "reason-phrase = *( HTAB / SP / VCHAR / obs-text )" + // https://github.com/chromium/chromium/blob/94.0.4604.1/third_party/blink/renderer/core/fetch/response.cc#L116 + function isValidReasonPhrase (statusText) { + for (let i = 0; i < statusText.length; ++i) { + const c = statusText.charCodeAt(i); + if ( + !( + ( + c === 0x09 || // HTAB + (c >= 0x20 && c <= 0x7e) || // SP / VCHAR + (c >= 0x80 && c <= 0xff) + ) // obs-text + ) + ) { + return false + } + } + return true } - // https://url.spec.whatwg.org/#concept-url-serializer /** - * @param {URL} url - * @param {boolean} excludeFragment + * @see https://fetch.spec.whatwg.org/#header-name + * @param {string} potentialValue */ - function URLSerializer (url, excludeFragment = false) { - if (!excludeFragment) { - return url.href - } - - const href = url.href; - const hashLength = url.hash.length; + const isValidHeaderName = isValidHTTPToken; - return hashLength === 0 ? href : href.substring(0, href.length - hashLength) - } - - // https://infra.spec.whatwg.org/#collect-a-sequence-of-code-points /** - * @param {(char: string) => boolean} condition - * @param {string} input - * @param {{ position: number }} position + * @see https://fetch.spec.whatwg.org/#header-value + * @param {string} potentialValue */ - function collectASequenceOfCodePoints (condition, input, position) { - // 1. Let result be the empty string. - let result = ''; + function isValidHeaderValue (potentialValue) { + // - Has no leading or trailing HTTP tab or space bytes. + // - Contains no 0x00 (NUL) or HTTP newline bytes. + return ( + potentialValue[0] === '\t' || + potentialValue[0] === ' ' || + potentialValue[potentialValue.length - 1] === '\t' || + potentialValue[potentialValue.length - 1] === ' ' || + potentialValue.includes('\n') || + potentialValue.includes('\r') || + potentialValue.includes('\0') + ) === false + } - // 2. While position doesn’t point past the end of input and the - // code point at position within input meets the condition condition: - while (position.position < input.length && condition(input[position.position])) { - // 1. Append that code point to the end of result. - result += input[position.position]; + // https://w3c.github.io/webappsec-referrer-policy/#set-requests-referrer-policy-on-redirect + function setRequestReferrerPolicyOnRedirect (request, actualResponse) { + // Given a request request and a response actualResponse, this algorithm + // updates request’s referrer policy according to the Referrer-Policy + // header (if any) in actualResponse. - // 2. Advance position by 1. - position.position++; - } + // 1. Let policy be the result of executing § 8.1 Parse a referrer policy + // from a Referrer-Policy header on actualResponse. - // 3. Return result. - return result - } + // 8.1 Parse a referrer policy from a Referrer-Policy header + // 1. Let policy-tokens be the result of extracting header list values given `Referrer-Policy` and response’s header list. + const { headersList } = actualResponse; + // 2. Let policy be the empty string. + // 3. For each token in policy-tokens, if token is a referrer policy and token is not the empty string, then set policy to token. + // 4. Return policy. + const policyHeader = (headersList.get('referrer-policy', true) ?? '').split(','); - /** - * A faster collectASequenceOfCodePoints that only works when comparing a single character. - * @param {string} char - * @param {string} input - * @param {{ position: number }} position - */ - function collectASequenceOfCodePointsFast (char, input, position) { - const idx = input.indexOf(char, position.position); - const start = position.position; + // Note: As the referrer-policy can contain multiple policies + // separated by comma, we need to loop through all of them + // and pick the first valid one. + // Ref: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Referrer-Policy#specify_a_fallback_policy + let policy = ''; + if (policyHeader.length > 0) { + // The right-most policy takes precedence. + // The left-most policy is the fallback. + for (let i = policyHeader.length; i !== 0; i--) { + const token = policyHeader[i - 1].trim(); + if (referrerPolicyTokens.has(token)) { + policy = token; + break + } + } + } - if (idx === -1) { - position.position = input.length; - return input.slice(start) + // 2. If policy is not the empty string, then set request’s referrer policy to policy. + if (policy !== '') { + request.referrerPolicy = policy; } + } - position.position = idx; - return input.slice(start, position.position) + // https://fetch.spec.whatwg.org/#cross-origin-resource-policy-check + function crossOriginResourcePolicyCheck () { + // TODO + return 'allowed' } - // https://url.spec.whatwg.org/#string-percent-decode - /** @param {string} input */ - function stringPercentDecode (input) { - // 1. Let bytes be the UTF-8 encoding of input. - const bytes = encoder.encode(input); + // https://fetch.spec.whatwg.org/#concept-cors-check + function corsCheck () { + // TODO + return 'success' + } - // 2. Return the percent-decoding of bytes. - return percentDecode(bytes) + // https://fetch.spec.whatwg.org/#concept-tao-check + function TAOCheck () { + // TODO + return 'success' } - // https://url.spec.whatwg.org/#percent-decode - /** @param {Uint8Array} input */ - function percentDecode (input) { - // 1. Let output be an empty byte sequence. - /** @type {number[]} */ - const output = []; + function appendFetchMetadata (httpRequest) { + // https://w3c.github.io/webappsec-fetch-metadata/#sec-fetch-dest-header + // TODO - // 2. For each byte byte in input: - for (let i = 0; i < input.length; i++) { - const byte = input[i]; + // https://w3c.github.io/webappsec-fetch-metadata/#sec-fetch-mode-header - // 1. If byte is not 0x25 (%), then append byte to output. - if (byte !== 0x25) { - output.push(byte); + // 1. Assert: r’s url is a potentially trustworthy URL. + // TODO - // 2. Otherwise, if byte is 0x25 (%) and the next two bytes - // after byte in input are not in the ranges - // 0x30 (0) to 0x39 (9), 0x41 (A) to 0x46 (F), - // and 0x61 (a) to 0x66 (f), all inclusive, append byte - // to output. - } else if ( - byte === 0x25 && - !/^[0-9A-Fa-f]{2}$/i.test(String.fromCharCode(input[i + 1], input[i + 2])) - ) { - output.push(0x25); + // 2. Let header be a Structured Header whose value is a token. + let header = null; - // 3. Otherwise: - } else { - // 1. Let bytePoint be the two bytes after byte in input, - // decoded, and then interpreted as hexadecimal number. - const nextTwoBytes = String.fromCharCode(input[i + 1], input[i + 2]); - const bytePoint = Number.parseInt(nextTwoBytes, 16); + // 3. Set header’s value to r’s mode. + header = httpRequest.mode; - // 2. Append a byte whose value is bytePoint to output. - output.push(bytePoint); + // 4. Set a structured field value `Sec-Fetch-Mode`/header in r’s header list. + httpRequest.headersList.set('sec-fetch-mode', header, true); - // 3. Skip the next two bytes in input. - i += 2; - } - } + // https://w3c.github.io/webappsec-fetch-metadata/#sec-fetch-site-header + // TODO - // 3. Return output. - return Uint8Array.from(output) + // https://w3c.github.io/webappsec-fetch-metadata/#sec-fetch-user-header + // TODO } - // https://mimesniff.spec.whatwg.org/#parse-a-mime-type - /** @param {string} input */ - function parseMIMEType (input) { - // 1. Remove any leading and trailing HTTP whitespace - // from input. - input = removeHTTPWhitespace(input, true, true); + // https://fetch.spec.whatwg.org/#append-a-request-origin-header + function appendRequestOriginHeader (request) { + // 1. Let serializedOrigin be the result of byte-serializing a request origin + // with request. + // TODO: implement "byte-serializing a request origin" + let serializedOrigin = request.origin; - // 2. Let position be a position variable for input, - // initially pointing at the start of input. - const position = { position: 0 }; + // - "'client' is changed to an origin during fetching." + // This doesn't happen in undici (in most cases) because undici, by default, + // has no concept of origin. + // - request.origin can also be set to request.client.origin (client being + // an environment settings object), which is undefined without using + // setGlobalOrigin. + if (serializedOrigin === 'client' || serializedOrigin === undefined) { + return + } - // 3. Let type be the result of collecting a sequence - // of code points that are not U+002F (/) from - // input, given position. - const type = collectASequenceOfCodePointsFast( - '/', - input, - position - ); + // 2. If request’s response tainting is "cors" or request’s mode is "websocket", + // then append (`Origin`, serializedOrigin) to request’s header list. + // 3. Otherwise, if request’s method is neither `GET` nor `HEAD`, then: + if (request.responseTainting === 'cors' || request.mode === 'websocket') { + request.headersList.append('origin', serializedOrigin, true); + } else if (request.method !== 'GET' && request.method !== 'HEAD') { + // 1. Switch on request’s referrer policy: + switch (request.referrerPolicy) { + case 'no-referrer': + // Set serializedOrigin to `null`. + serializedOrigin = null; + break + case 'no-referrer-when-downgrade': + case 'strict-origin': + case 'strict-origin-when-cross-origin': + // If request’s origin is a tuple origin, its scheme is "https", and + // request’s current URL’s scheme is not "https", then set + // serializedOrigin to `null`. + if (request.origin && urlHasHttpsScheme(request.origin) && !urlHasHttpsScheme(requestCurrentURL(request))) { + serializedOrigin = null; + } + break + case 'same-origin': + // If request’s origin is not same origin with request’s current URL’s + // origin, then set serializedOrigin to `null`. + if (!sameOrigin(request, requestCurrentURL(request))) { + serializedOrigin = null; + } + break + // Do nothing. + } - // 4. If type is the empty string or does not solely - // contain HTTP token code points, then return failure. - // https://mimesniff.spec.whatwg.org/#http-token-code-point - if (type.length === 0 || !HTTP_TOKEN_CODEPOINTS.test(type)) { - return 'failure' + // 2. Append (`Origin`, serializedOrigin) to request’s header list. + request.headersList.append('origin', serializedOrigin, true); } + } - // 5. If position is past the end of input, then return - // failure - if (position.position > input.length) { - return 'failure' - } + // https://w3c.github.io/hr-time/#dfn-coarsen-time + function coarsenTime (timestamp, crossOriginIsolatedCapability) { + // TODO + return timestamp + } - // 6. Advance position by 1. (This skips past U+002F (/).) - position.position++; + // https://fetch.spec.whatwg.org/#clamp-and-coarsen-connection-timing-info + 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 + } + } - // 7. Let subtype be the result of collecting a sequence of - // code points that are not U+003B (;) from input, given - // position. - let subtype = collectASequenceOfCodePointsFast( - ';', - input, - position - ); + return { + domainLookupStartTime: coarsenTime(connectionTimingInfo.domainLookupStartTime), + domainLookupEndTime: coarsenTime(connectionTimingInfo.domainLookupEndTime), + connectionStartTime: coarsenTime(connectionTimingInfo.connectionStartTime), + connectionEndTime: coarsenTime(connectionTimingInfo.connectionEndTime), + secureConnectionStartTime: coarsenTime(connectionTimingInfo.secureConnectionStartTime), + ALPNNegotiatedProtocol: connectionTimingInfo.ALPNNegotiatedProtocol + } + } - // 8. Remove any trailing HTTP whitespace from subtype. - subtype = removeHTTPWhitespace(subtype, false, true); + // https://w3c.github.io/hr-time/#dfn-coarsened-shared-current-time + function coarsenedSharedCurrentTime (crossOriginIsolatedCapability) { + return coarsenTime(performance.now()) + } - // 9. If subtype is the empty string or does not solely - // contain HTTP token code points, then return failure. - if (subtype.length === 0 || !HTTP_TOKEN_CODEPOINTS.test(subtype)) { - return 'failure' + // https://fetch.spec.whatwg.org/#create-an-opaque-timing-info + 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 } + } - const typeLowercase = type.toLowerCase(); - const subtypeLowercase = subtype.toLowerCase(); + // https://html.spec.whatwg.org/multipage/origin.html#policy-container + function makePolicyContainer () { + // Note: the fetch spec doesn't make use of embedder policy or CSP list + return { + referrerPolicy: 'strict-origin-when-cross-origin' + } + } - // 10. Let mimeType be a new MIME type record whose type - // is type, in ASCII lowercase, and subtype is subtype, - // in ASCII lowercase. - // https://mimesniff.spec.whatwg.org/#mime-type - const mimeType = { - type: typeLowercase, - subtype: subtypeLowercase, - /** @type {Map} */ - parameters: new Map(), - // https://mimesniff.spec.whatwg.org/#mime-type-essence - essence: `${typeLowercase}/${subtypeLowercase}` - }; + // https://html.spec.whatwg.org/multipage/origin.html#clone-a-policy-container + function clonePolicyContainer (policyContainer) { + return { + referrerPolicy: policyContainer.referrerPolicy + } + } - // 11. While position is not past the end of input: - while (position.position < input.length) { - // 1. Advance position by 1. (This skips past U+003B (;).) - position.position++; + // https://w3c.github.io/webappsec-referrer-policy/#determine-requests-referrer + function determineRequestsReferrer (request) { + // 1. Let policy be request's referrer policy. + const policy = request.referrerPolicy; - // 2. Collect a sequence of code points that are HTTP - // whitespace from input given position. - collectASequenceOfCodePoints( - // https://fetch.spec.whatwg.org/#http-whitespace - char => HTTP_WHITESPACE_REGEX.test(char), - input, - position - ); + // Note: policy cannot (shouldn't) be null or an empty string. + assert(policy); - // 3. Let parameterName be the result of collecting a - // sequence of code points that are not U+003B (;) - // or U+003D (=) from input, given position. - let parameterName = collectASequenceOfCodePoints( - (char) => char !== ';' && char !== '=', - input, - position - ); + // 2. Let environment be request’s client. - // 4. Set parameterName to parameterName, in ASCII - // lowercase. - parameterName = parameterName.toLowerCase(); + let referrerSource = null; - // 5. If position is not past the end of input, then: - if (position.position < input.length) { - // 1. If the code point at position within input is - // U+003B (;), then continue. - if (input[position.position] === ';') { - continue - } + // 3. Switch on request’s referrer: + if (request.referrer === 'client') { + // Note: node isn't a browser and doesn't implement document/iframes, + // so we bypass this step and replace it with our own. - // 2. Advance position by 1. (This skips past U+003D (=).) - position.position++; - } + const globalOrigin = getGlobalOrigin(); - // 6. If position is past the end of input, then break. - if (position.position > input.length) { - break + if (!globalOrigin || globalOrigin.origin === 'null') { + return 'no-referrer' } - // 7. Let parameterValue be null. - let parameterValue = null; + // note: we need to clone it as it's mutated + referrerSource = new URL(globalOrigin); + } else if (request.referrer instanceof URL) { + // Let referrerSource be request’s referrer. + referrerSource = request.referrer; + } - // 8. If the code point at position within input is - // U+0022 ("), then: - if (input[position.position] === '"') { - // 1. Set parameterValue to the result of collecting - // an HTTP quoted string from input, given position - // and the extract-value flag. - parameterValue = collectAnHTTPQuotedString(input, position, true); + // 4. Let request’s referrerURL be the result of stripping referrerSource for + // use as a referrer. + let referrerURL = stripURLForReferrer(referrerSource); - // 2. Collect a sequence of code points that are not - // U+003B (;) from input, given position. - collectASequenceOfCodePointsFast( - ';', - input, - position - ); + // 5. Let referrerOrigin be the result of stripping referrerSource for use as + // a referrer, with the origin-only flag set to true. + const referrerOrigin = stripURLForReferrer(referrerSource, true); - // 9. Otherwise: - } else { - // 1. Set parameterValue to the result of collecting - // a sequence of code points that are not U+003B (;) - // from input, given position. - parameterValue = collectASequenceOfCodePointsFast( - ';', - input, - position - ); + // 6. If the result of serializing referrerURL is a string whose length is + // greater than 4096, set referrerURL to referrerOrigin. + if (referrerURL.toString().length > 4096) { + referrerURL = referrerOrigin; + } - // 2. Remove any trailing HTTP whitespace from parameterValue. - parameterValue = removeHTTPWhitespace(parameterValue, false, true); + const areSameOrigin = sameOrigin(request, referrerURL); + const isNonPotentiallyTrustWorthy = isURLPotentiallyTrustworthy(referrerURL) && + !isURLPotentiallyTrustworthy(request.url); - // 3. If parameterValue is the empty string, then continue. - if (parameterValue.length === 0) { - continue + // 8. Execute the switch statements corresponding to the value of policy: + 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); + + // 1. If the origin of referrerURL and the origin of request’s current + // URL are the same, then return referrerURL. + if (sameOrigin(referrerURL, currentURL)) { + return referrerURL } - } - // 10. If all of the following are true - // - parameterName is not the empty string - // - parameterName solely contains HTTP token code points - // - parameterValue solely contains HTTP quoted-string token code points - // - mimeType’s parameters[parameterName] does not exist - // then set mimeType’s parameters[parameterName] to parameterValue. - 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); + // 2. If referrerURL is a potentially trustworthy URL and request’s + // current URL is not a potentially trustworthy URL, then return no + // referrer. + if (isURLPotentiallyTrustworthy(referrerURL) && !isURLPotentiallyTrustworthy(currentURL)) { + return 'no-referrer' + } + + // 3. Return referrerOrigin. + 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 + */ - // 12. Return mimeType. - return mimeType + default: // eslint-disable-line + return isNonPotentiallyTrustWorthy ? 'no-referrer' : referrerOrigin + } } - // https://infra.spec.whatwg.org/#forgiving-base64-decode - /** @param {string} data */ - function forgivingBase64 (data) { - // 1. Remove all ASCII whitespace from data. - data = data.replace(/[\u0009\u000A\u000C\u000D\u0020]/g, ''); // eslint-disable-line + /** + * @see https://w3c.github.io/webappsec-referrer-policy/#strip-url + * @param {URL} url + * @param {boolean|undefined} originOnly + */ + function stripURLForReferrer (url, originOnly) { + // 1. Assert: url is a URL. + assert(url instanceof URL); - // 2. If data’s code point length divides by 4 leaving - // no remainder, then: - if (data.length % 4 === 0) { - // 1. If data ends with one or two U+003D (=) code points, - // then remove them from data. - data = data.replace(/=?=$/, ''); - } + url = new URL(url); - // 3. If data’s code point length divides by 4 leaving - // a remainder of 1, then return failure. - if (data.length % 4 === 1) { - return 'failure' + // 2. If url’s scheme is a local scheme, then return no referrer. + if (url.protocol === 'file:' || url.protocol === 'about:' || url.protocol === 'blank:') { + return 'no-referrer' } - // 4. If data contains a code point that is not one of - // U+002B (+) - // U+002F (/) - // ASCII alphanumeric - // then return failure. - if (/[^+/0-9A-Za-z]/.test(data)) { - return 'failure' - } + // 3. Set url’s username to the empty string. + url.username = ''; - const binary = atob(data); - const bytes = new Uint8Array(binary.length); + // 4. Set url’s password to the empty string. + url.password = ''; + + // 5. Set url’s fragment to null. + url.hash = ''; + + // 6. If the origin-only flag is true, then: + if (originOnly) { + // 1. Set url’s path to « the empty string ». + url.pathname = ''; - for (let byte = 0; byte < binary.length; byte++) { - bytes[byte] = binary.charCodeAt(byte); + // 2. Set url’s query to null. + url.search = ''; } - return bytes + // 7. Return url. + return url } - // https://fetch.spec.whatwg.org/#collect-an-http-quoted-string - // tests: https://fetch.spec.whatwg.org/#example-http-quoted-string - /** - * @param {string} input - * @param {{ position: number }} position - * @param {boolean?} extractValue - */ - function collectAnHTTPQuotedString (input, position, extractValue) { - // 1. Let positionStart be position. - const positionStart = position.position; + function isURLPotentiallyTrustworthy (url) { + if (!(url instanceof URL)) { + return false + } - // 2. Let value be the empty string. - let value = ''; + // If child of about, return true + if (url.href === 'about:blank' || url.href === 'about:srcdoc') { + return true + } - // 3. Assert: the code point at position within input - // is U+0022 ("). - assert(input[position.position] === '"'); + // If scheme is data, return true + if (url.protocol === 'data:') return true - // 4. Advance position by 1. - position.position++; + // If file, return true + if (url.protocol === 'file:') return true - // 5. While true: - while (true) { - // 1. Append the result of collecting a sequence of code points - // that are not U+0022 (") or U+005C (\) from input, given - // position, to value. - value += collectASequenceOfCodePoints( - (char) => char !== '"' && char !== '\\', - input, - position - ); + return isOriginPotentiallyTrustworthy(url.origin) - // 2. If position is past the end of input, then break. - if (position.position >= input.length) { - break + function isOriginPotentiallyTrustworthy (origin) { + // If origin is explicitly null, return false + if (origin == null || origin === 'null') return false + + const originAsURL = new URL(origin); + + // If secure, return true + if (originAsURL.protocol === 'https:' || originAsURL.protocol === 'wss:') { + return true } - // 3. Let quoteOrBackslash be the code point at position within - // input. - const quoteOrBackslash = input[position.position]; + // If localhost or variants, 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 + } - // 4. Advance position by 1. - position.position++; + // If any other, return false + return false + } + } - // 5. If quoteOrBackslash is U+005C (\), then: - if (quoteOrBackslash === '\\') { - // 1. If position is past the end of input, then append - // U+005C (\) to value and break. - if (position.position >= input.length) { - value += '\\'; - break - } + /** + * @see https://w3c.github.io/webappsec-subresource-integrity/#does-response-match-metadatalist + * @param {Uint8Array} bytes + * @param {string} metadataList + */ + function bytesMatch (bytes, metadataList) { + // If node is not built with OpenSSL support, we cannot check + // a request's integrity, so allow it by default (the spec will + // allow requests if an invalid hash is given, as precedence). + /* istanbul ignore if: only if node is built with --without-ssl */ + if (crypto === undefined) { + return true + } - // 2. Append the code point at position within input to value. - value += input[position.position]; + // 1. Let parsedMetadata be the result of parsing metadataList. + const parsedMetadata = parseMetadata(metadataList); - // 3. Advance position by 1. - position.position++; + // 2. If parsedMetadata is no metadata, return true. + if (parsedMetadata === 'no metadata') { + return true + } - // 6. Otherwise: - } else { - // 1. Assert: quoteOrBackslash is U+0022 ("). - assert(quoteOrBackslash === '"'); + // 3. If response is not eligible for integrity validation, return false. + // TODO - // 2. Break. - break - } + // 4. If parsedMetadata is the empty set, return true. + if (parsedMetadata.length === 0) { + return true } - // 6. If the extract-value flag is set, then return value. - if (extractValue) { - return value + // 5. Let metadata be the result of getting the strongest + // metadata from parsedMetadata. + const strongest = getStrongestMetadata(parsedMetadata); + const metadata = filterMetadataListByAlgorithm(parsedMetadata, strongest); + + // 6. For each item in metadata: + for (const item of metadata) { + // 1. Let algorithm be the alg component of item. + const algorithm = item.algo; + + // 2. Let expectedValue be the val component of item. + const expectedValue = item.hash; + + // See https://github.com/web-platform-tests/wpt/commit/e4c5cc7a5e48093220528dfdd1c4012dc3837a0e + // "be liberal with padding". This is annoying, and it's not even in the spec. + + // 3. Let actualValue be the result of applying algorithm to bytes. + let actualValue = crypto.createHash(algorithm).update(bytes).digest('base64'); + + if (actualValue[actualValue.length - 1] === '=') { + if (actualValue[actualValue.length - 2] === '=') { + actualValue = actualValue.slice(0, -2); + } else { + actualValue = actualValue.slice(0, -1); + } + } + + // 4. If actualValue is a case-sensitive match for expectedValue, + // return true. + if (compareBase64Mixed(actualValue, expectedValue)) { + return true + } } - // 7. Return the code points from positionStart to position, - // inclusive, within input. - return input.slice(positionStart, position.position) + // 7. Return false. + return false } + // https://w3c.github.io/webappsec-subresource-integrity/#grammardef-hash-with-options + // https://www.w3.org/TR/CSP2/#source-list-syntax + // https://www.rfc-editor.org/rfc/rfc5234#appendix-B.1 + const parseHashWithOptions = /(?sha256|sha384|sha512)-((?[A-Za-z0-9+/]+|[A-Za-z0-9_-]+)={0,2}(?:\s|$)( +[!-~]*)?)?/i; + /** - * @see https://mimesniff.spec.whatwg.org/#serialize-a-mime-type + * @see https://w3c.github.io/webappsec-subresource-integrity/#parse-metadata + * @param {string} metadata */ - function serializeAMimeType (mimeType) { - assert(mimeType !== 'failure'); - const { parameters, essence } = mimeType; - - // 1. Let serialization be the concatenation of mimeType’s - // type, U+002F (/), and mimeType’s subtype. - let serialization = essence; + function parseMetadata (metadata) { + // 1. Let result be the empty set. + /** @type {{ algo: string, hash: string }[]} */ + const result = []; - // 2. For each name → value of mimeType’s parameters: - for (let [name, value] of parameters.entries()) { - // 1. Append U+003B (;) to serialization. - serialization += ';'; + // 2. Let empty be equal to true. + let empty = true; - // 2. Append name to serialization. - serialization += name; + // 3. For each token returned by splitting metadata on spaces: + for (const token of metadata.split(' ')) { + // 1. Set empty to false. + empty = false; - // 3. Append U+003D (=) to serialization. - serialization += '='; + // 2. Parse token as a hash-with-options. + const parsedToken = parseHashWithOptions.exec(token); - // 4. If value does not solely contain HTTP token code - // points or value is the empty string, then: - if (!HTTP_TOKEN_CODEPOINTS.test(value)) { - // 1. Precede each occurence of U+0022 (") or - // U+005C (\) in value with U+005C (\). - value = value.replace(/(\\|")/g, '\\$1'); + // 3. If token does not parse, continue to the next token. + if ( + parsedToken === null || + parsedToken.groups === undefined || + parsedToken.groups.algo === undefined + ) { + // Note: Chromium blocks the request at this point, but Firefox + // gives a warning that an invalid integrity was given. The + // correct behavior is to ignore these, and subsequently not + // check the integrity of the resource. + continue + } - // 2. Prepend U+0022 (") to value. - value = '"' + value; + // 4. Let algorithm be the hash-algo component of token. + const algorithm = parsedToken.groups.algo.toLowerCase(); - // 3. Append U+0022 (") to value. - value += '"'; + // 5. If algorithm is a hash function recognized by the user + // agent, add the parsed token to result. + if (supportedHashes.includes(algorithm)) { + result.push(parsedToken.groups); } + } - // 5. Append value to serialization. - serialization += value; + // 4. Return no metadata if empty is true, otherwise return result. + if (empty === true) { + return 'no metadata' } - // 3. Return serialization. - return serialization + return result } /** - * @see https://fetch.spec.whatwg.org/#http-whitespace - * @param {string} char + * @param {{ algo: 'sha256' | 'sha384' | 'sha512' }[]} metadataList */ - function isHTTPWhiteSpace (char) { - return char === '\r' || char === '\n' || char === '\t' || char === ' ' - } + function getStrongestMetadata (metadataList) { + // Let algorithm be the algo component of the first item in metadataList. + // Can be sha256 + let algorithm = metadataList[0].algo; + // If the algorithm is sha512, then it is the strongest + // and we can return immediately + if (algorithm[3] === '5') { + return algorithm + } - /** - * @see https://fetch.spec.whatwg.org/#http-whitespace - * @param {string} str - */ - function removeHTTPWhitespace (str, leading = true, trailing = true) { - let lead = 0; - let trail = str.length - 1; + for (let i = 1; i < metadataList.length; ++i) { + const metadata = metadataList[i]; + // If the algorithm is sha512, then it is the strongest + // and we can break the loop immediately + if (metadata.algo[3] === '5') { + algorithm = 'sha512'; + break + // If the algorithm is sha384, then a potential sha256 or sha384 is ignored + } else if (algorithm[3] === '3') { + continue + // algorithm is sha256, check if algorithm is sha384 and if so, set it as + // the strongest + } else if (metadata.algo[3] === '3') { + algorithm = 'sha384'; + } + } + return algorithm + } - if (leading) { - for (; lead < str.length && isHTTPWhiteSpace(str[lead]); lead++); + function filterMetadataListByAlgorithm (metadataList, algorithm) { + if (metadataList.length === 1) { + return metadataList } - if (trailing) { - for (; trail > 0 && isHTTPWhiteSpace(str[trail]); trail--); + let pos = 0; + for (let i = 0; i < metadataList.length; ++i) { + if (metadataList[i].algo === algorithm) { + metadataList[pos++] = metadataList[i]; + } } - return str.slice(lead, trail + 1) + metadataList.length = pos; + + return metadataList } /** - * @see https://infra.spec.whatwg.org/#ascii-whitespace - * @param {string} char + * Compares two base64 strings, allowing for base64url + * in the second string. + * + * @param {string} actualValue always base64 + * @param {string} expectedValue base64 or base64url + * @returns {boolean} */ - function isASCIIWhitespace (char) { - return char === '\r' || char === '\n' || char === '\t' || char === '\f' || char === ' ' + 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 + } + + // https://w3c.github.io/webappsec-upgrade-insecure-requests/#upgrade-request + function tryUpgradeRequestToAPotentiallyTrustworthyURL (request) { + // TODO } /** - * @see https://infra.spec.whatwg.org/#strip-leading-and-trailing-ascii-whitespace + * @link {https://html.spec.whatwg.org/multipage/origin.html#same-origin} + * @param {URL} A + * @param {URL} B */ - function removeASCIIWhitespace (str, leading = true, trailing = true) { - let lead = 0; - let trail = str.length - 1; - - if (leading) { - for (; lead < str.length && isASCIIWhitespace(str[lead]); lead++); + function sameOrigin (A, B) { + // 1. If A and B are the same opaque origin, then return true. + if (A.origin === B.origin && A.origin === 'null') { + return true } - if (trailing) { - for (; trail > 0 && isASCIIWhitespace(str[trail]); trail--); + // 2. If A and B are both tuple origins and their schemes, + // hosts, and port are identical, then return true. + if (A.protocol === B.protocol && A.hostname === B.hostname && A.port === B.port) { + return true } - return str.slice(lead, trail + 1) + // 3. Return false. + return false } - dataURL = { - dataURLProcessor, - URLSerializer, - collectASequenceOfCodePoints, - collectASequenceOfCodePointsFast, - stringPercentDecode, - parseMIMEType, - collectAnHTTPQuotedString, - serializeAMimeType - }; - return dataURL; -} + function createDeferredPromise () { + let res; + let rej; + const promise = new Promise((resolve, reject) => { + res = resolve; + rej = reject; + }); -var file; -var hasRequiredFile; + return { promise, resolve: res, reject: rej } + } -function requireFile () { - if (hasRequiredFile) return file; - hasRequiredFile = 1; + function isAborted (fetchParams) { + return fetchParams.controller.state === 'aborted' + } - const { Blob, File: NativeFile } = require$$7; - const { types } = require$$0$2; - const { kState } = requireSymbols$3(); - const { isBlobLike } = requireUtil$6(); - const { webidl } = requireWebidl(); - const { parseMIMEType, serializeAMimeType } = requireDataURL(); - const { kEnumerableProperty } = requireUtil$7(); - const encoder = new TextEncoder(); + function isCancelled (fetchParams) { + return fetchParams.controller.state === 'aborted' || + fetchParams.controller.state === 'terminated' + } - class File extends Blob { - constructor (fileBits, fileName, options = {}) { - // The File constructor is invoked with two or three parameters, depending - // on whether the optional dictionary parameter is used. When the File() - // constructor is invoked, user agents must run the following steps: - webidl.argumentLengthCheck(arguments, 2, { header: 'File constructor' }); + /** + * @see https://fetch.spec.whatwg.org/#concept-method-normalize + * @param {string} method + */ + function normalizeMethod (method) { + return normalizedMethodRecordsBase[method.toLowerCase()] ?? method + } - fileBits = webidl.converters['sequence'](fileBits); - fileName = webidl.converters.USVString(fileName); - options = webidl.converters.FilePropertyBag(options); + // https://infra.spec.whatwg.org/#serialize-a-javascript-value-to-a-json-string + function serializeJavascriptValueToJSONString (value) { + // 1. Let result be ? Call(%JSON.stringify%, undefined, « value »). + const result = JSON.stringify(value); - // 1. Let bytes be the result of processing blob parts given fileBits and - // options. - // Note: Blob handles this for us + // 2. If result is undefined, then throw a TypeError. + if (result === undefined) { + throw new TypeError('Value is not JSON serializable') + } - // 2. Let n be the fileName argument to the constructor. - const n = fileName; + // 3. Assert: result is a string. + assert(typeof result === 'string'); - // 3. Process FilePropertyBag dictionary argument by running the following - // substeps: + // 4. Return result. + return result + } - // 1. If the type member is provided and is not the empty string, let t - // be set to the type dictionary member. If t contains any characters - // outside the range U+0020 to U+007E, then set t to the empty string - // and return from these substeps. - // 2. Convert every character in t to ASCII lowercase. - let t = options.type; - let d; + // https://tc39.es/ecma262/#sec-%25iteratorprototype%25-object + const esIteratorPrototype = Object.getPrototypeOf(Object.getPrototypeOf([][Symbol.iterator]())); + + /** + * @see https://webidl.spec.whatwg.org/#dfn-iterator-prototype-object + * @param {string} name name of the instance + * @param {symbol} kInternalIterator + * @param {string | number} [keyIndex] + * @param {string | number} [valueIndex] + */ + 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 () { + // 1. Let interface be the interface for which the iterator prototype object exists. + // 2. Let thisValue be the this value. + // 3. Let object be ? ToObject(thisValue). + // 4. If object is a platform object, then perform a security + // check, passing: + // 5. If object is not a default iterator object for interface, + // then throw a TypeError. + if (typeof this !== 'object' || this === null || !(#target in this)) { + throw new TypeError( + `'next' called on an object that does not implement interface ${name} Iterator.` + ) + } + + // 6. Let index be object’s index. + // 7. Let kind be object’s kind. + // 8. Let values be object’s target's value pairs to iterate over. + const index = this.#index; + const values = this.#target[kInternalIterator]; - // eslint-disable-next-line no-labels - substep: { - if (t) { - t = parseMIMEType(t); + // 9. Let len be the length of values. + const len = values.length; - if (t === 'failure') { - t = ''; - // eslint-disable-next-line no-labels - break substep + // 10. If index is greater than or equal to len, then return + // CreateIterResultObject(undefined, true). + if (index >= len) { + return { + value: undefined, + done: true } + } - t = serializeAMimeType(t).toLowerCase(); + // 11. Let pair be the entry in values at index index. + const { [keyIndex]: key, [valueIndex]: value } = values[index]; + + // 12. Set object’s index to index + 1. + this.#index = index + 1; + + // 13. Return the iterator result for pair and kind. + + // https://webidl.spec.whatwg.org/#iterator-result + + // 1. Let result be a value determined by the value of kind: + let result; + switch (this.#kind) { + case 'key': + // 1. Let idlKey be pair’s key. + // 2. Let key be the result of converting idlKey to an + // ECMAScript value. + // 3. result is key. + result = key; + break + case 'value': + // 1. Let idlValue be pair’s value. + // 2. Let value be the result of converting idlValue to + // an ECMAScript value. + // 3. result is value. + result = value; + break + case 'key+value': + // 1. Let idlKey be pair’s key. + // 2. Let idlValue be pair’s value. + // 3. Let key be the result of converting idlKey to an + // ECMAScript value. + // 4. Let value be the result of converting idlValue to + // an ECMAScript value. + // 5. Let array be ! ArrayCreate(2). + // 6. Call ! CreateDataProperty(array, "0", key). + // 7. Call ! CreateDataProperty(array, "1", value). + // 8. result is array. + result = [key, value]; + break } - // 3. If the lastModified member is provided, let d be set to the - // lastModified dictionary member. If it is not provided, set d to the - // current date and time represented as the number of milliseconds since - // the Unix Epoch (which is the equivalent of Date.now() [ECMA-262]). - d = options.lastModified; + // 2. Return CreateIterResultObject(result, false). + return { + value: result, + done: false + } } + } - // 4. Return a new File object F such that: - // F refers to the bytes byte sequence. - // F.size is set to the number of total bytes in bytes. - // F.name is set to n. - // F.type is set to t. - // F.lastModified is set to d. + // https://webidl.spec.whatwg.org/#dfn-iterator-prototype-object + // @ts-ignore + delete FastIterableIterator.prototype.constructor; - super(processBlobParts(fileBits, options), { type: t }); - this[kState] = { - name: n, - lastModified: d, - type: t - }; + 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 } + }); + + /** + * @param {unknown} target + * @param {'key' | 'value' | 'key+value'} kind + * @returns {IterableIterator} + */ + return function (target, kind) { + return new FastIterableIterator(target, kind) } + } - get name () { - webidl.brandCheck(this, File); + /** + * @see https://webidl.spec.whatwg.org/#dfn-iterator-prototype-object + * @param {string} name name of the instance + * @param {any} object class + * @param {symbol} kInternalIterator + * @param {string | number} [keyIndex] + * @param {string | number} [valueIndex] + */ + function iteratorMixin (name, object, kInternalIterator, keyIndex = 0, valueIndex = 1) { + const makeIterator = createIterator(name, kInternalIterator, keyIndex, valueIndex); - return this[kState].name + 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 + } + }) + } + + /** + * @see https://fetch.spec.whatwg.org/#body-fully-read + */ + async function fullyReadBody (body, processBody, processBodyError) { + // 1. If taskDestination is null, then set taskDestination to + // the result of starting a new parallel queue. + + // 2. Let successSteps given a byte sequence bytes be to queue a + // fetch task to run processBody given bytes, with taskDestination. + const successSteps = processBody; + + // 3. Let errorSteps be to queue a fetch task to run processBodyError, + // with taskDestination. + const errorSteps = processBodyError; + + // 4. Let reader be the result of getting a reader for body’s stream. + // If that threw an exception, then run errorSteps with that + // exception and return. + let reader; + + try { + reader = body.stream.getReader(); + } catch (e) { + errorSteps(e); + return } - get lastModified () { - webidl.brandCheck(this, File); + // 5. Read all bytes from reader, given successSteps and errorSteps. + try { + successSteps(await readAllBytes(reader)); + } catch (e) { + errorSteps(e); + } + } - return this[kState].lastModified + function isReadableStreamLike (stream) { + return stream instanceof ReadableStream || ( + stream[Symbol.toStringTag] === 'ReadableStream' && + typeof stream.tee === 'function' + ) + } + + /** + * @param {ReadableStreamController} controller + */ + function readableStreamClose (controller) { + try { + controller.close(); + controller.byobRequest?.respond(0); + } catch (err) { + // TODO: add comment explaining why this error occurs. + if (!err.message.includes('Controller is already closed') && !err.message.includes('ReadableStream is already closed')) { + throw err + } } + } - get type () { - webidl.brandCheck(this, File); + const invalidIsomorphicEncodeValueRegex = /[^\x00-\xFF]/; // eslint-disable-line - return this[kState].type + /** + * @see https://infra.spec.whatwg.org/#isomorphic-encode + * @param {string} input + */ + function isomorphicEncode (input) { + // 1. Assert: input contains no code points greater than U+00FF. + assert(!invalidIsomorphicEncodeValueRegex.test(input)); + + // 2. Return a byte sequence whose length is equal to input’s code + // point length and whose bytes have the same values as the + // values of input’s code points, in the same order + return input + } + + /** + * @see https://streams.spec.whatwg.org/#readablestreamdefaultreader-read-all-bytes + * @see https://streams.spec.whatwg.org/#read-loop + * @param {ReadableStreamDefaultReader} reader + */ + async function readAllBytes (reader) { + const bytes = []; + let byteLength = 0; + + while (true) { + const { done, value: chunk } = await reader.read(); + + if (done) { + // 1. Call successSteps with bytes. + return Buffer.concat(bytes, byteLength) + } + + // 1. If chunk is not a Uint8Array object, call failureSteps + // with a TypeError and abort these steps. + if (!isUint8Array(chunk)) { + throw new TypeError('Received non-Uint8Array chunk') + } + + // 2. Append the bytes represented by chunk to bytes. + bytes.push(chunk); + byteLength += chunk.length; + + // 3. Read-loop given reader, bytes, successSteps, and failureSteps. + } + } + + /** + * @see https://fetch.spec.whatwg.org/#is-local + * @param {URL} url + */ + function urlIsLocal (url) { + assert('protocol' in url); // ensure it's a url object + + const protocol = url.protocol; + + return protocol === 'about:' || protocol === 'blob:' || protocol === 'data:' + } + + /** + * @param {string|URL} url + * @returns {boolean} + */ + 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:' + ) + } + + /** + * @see https://fetch.spec.whatwg.org/#http-scheme + * @param {URL} url + */ + function urlIsHttpHttpsScheme (url) { + assert('protocol' in url); // ensure it's a url object + + const protocol = url.protocol; + + return protocol === 'http:' || protocol === 'https:' + } + + /** + * @see https://fetch.spec.whatwg.org/#simple-range-header-value + * @param {string} value + * @param {boolean} allowWhitespace + */ + function simpleRangeHeaderValue (value, allowWhitespace) { + // 1. Let data be the isomorphic decoding of value. + // Note: isomorphic decoding takes a sequence of bytes (ie. a Uint8Array) and turns it into a string, + // nothing more. We obviously don't need to do that if value is a string already. + const data = value; + + // 2. If data does not start with "bytes", then return failure. + if (!data.startsWith('bytes')) { + return 'failure' + } + + // 3. Let position be a position variable for data, initially pointing at the 5th code point of data. + const position = { position: 5 }; + + // 4. If allowWhitespace is true, collect a sequence of code points that are HTTP tab or space, + // from data given position. + if (allowWhitespace) { + collectASequenceOfCodePoints( + (char) => char === '\t' || char === ' ', + data, + position + ); + } + + // 5. If the code point at position within data is not U+003D (=), then return failure. + if (data.charCodeAt(position.position) !== 0x3D) { + return 'failure' + } + + // 6. Advance position by 1. + position.position++; + + // 7. If allowWhitespace is true, collect a sequence of code points that are HTTP tab or space, from + // data given position. + if (allowWhitespace) { + collectASequenceOfCodePoints( + (char) => char === '\t' || char === ' ', + data, + position + ); + } + + // 8. Let rangeStart be the result of collecting a sequence of code points that are ASCII digits, + // from data given position. + const rangeStart = collectASequenceOfCodePoints( + (char) => { + const code = char.charCodeAt(0); + + return code >= 0x30 && code <= 0x39 + }, + data, + position + ); + + // 9. Let rangeStartValue be rangeStart, interpreted as decimal number, if rangeStart is not the + // empty string; otherwise null. + const rangeStartValue = rangeStart.length ? Number(rangeStart) : null; + + // 10. If allowWhitespace is true, collect a sequence of code points that are HTTP tab or space, + // from data given position. + if (allowWhitespace) { + collectASequenceOfCodePoints( + (char) => char === '\t' || char === ' ', + data, + position + ); + } + + // 11. If the code point at position within data is not U+002D (-), then return failure. + if (data.charCodeAt(position.position) !== 0x2D) { + return 'failure' + } + + // 12. Advance position by 1. + position.position++; + + // 13. If allowWhitespace is true, collect a sequence of code points that are HTTP tab + // or space, from data given position. + // Note from Khafra: its the same step as in #8 again lol + if (allowWhitespace) { + collectASequenceOfCodePoints( + (char) => char === '\t' || char === ' ', + data, + position + ); + } + + // 14. Let rangeEnd be the result of collecting a sequence of code points that are + // ASCII digits, from data given position. + // Note from Khafra: you wouldn't guess it, but this is also the same step as #8 + const rangeEnd = collectASequenceOfCodePoints( + (char) => { + const code = char.charCodeAt(0); + + return code >= 0x30 && code <= 0x39 + }, + data, + position + ); + + // 15. Let rangeEndValue be rangeEnd, interpreted as decimal number, if rangeEnd + // is not the empty string; otherwise null. + // Note from Khafra: THE SAME STEP, AGAIN!!! + // Note: why interpret as a decimal if we only collect ascii digits? + const rangeEndValue = rangeEnd.length ? Number(rangeEnd) : null; + + // 16. If position is not past the end of data, then return failure. + if (position.position < data.length) { + return 'failure' + } + + // 17. If rangeEndValue and rangeStartValue are null, then return failure. + if (rangeEndValue === null && rangeStartValue === null) { + return 'failure' + } + + // 18. If rangeStartValue and rangeEndValue are numbers, and rangeStartValue is + // greater than rangeEndValue, then return failure. + // Note: ... when can they not be numbers? + if (rangeStartValue > rangeEndValue) { + return 'failure' + } + + // 19. Return (rangeStartValue, rangeEndValue). + return { rangeStartValue, rangeEndValue } + } + + /** + * @see https://fetch.spec.whatwg.org/#build-a-content-range + * @param {number} rangeStart + * @param {number} rangeEnd + * @param {number} fullLength + */ + function buildContentRange (rangeStart, rangeEnd, fullLength) { + // 1. Let contentRange be `bytes `. + let contentRange = 'bytes '; + + // 2. Append rangeStart, serialized and isomorphic encoded, to contentRange. + contentRange += isomorphicEncode(`${rangeStart}`); + + // 3. Append 0x2D (-) to contentRange. + contentRange += '-'; + + // 4. Append rangeEnd, serialized and isomorphic encoded to contentRange. + contentRange += isomorphicEncode(`${rangeEnd}`); + + // 5. Append 0x2F (/) to contentRange. + contentRange += '/'; + + // 6. Append fullLength, serialized and isomorphic encoded to contentRange. + contentRange += isomorphicEncode(`${fullLength}`); + + // 7. Return contentRange. + return contentRange + } + + // A Stream, which pipes the response to zlib.createInflate() or + // zlib.createInflateRaw() depending on the first byte of the Buffer. + // If the lower byte of the first byte is 0x08, then the stream is + // interpreted as a zlib stream, otherwise it's interpreted as a + // raw deflate stream. + class InflateStream 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] & 0x0F) === 0x08 + ? 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(); + } + } + + /** + * @param {zlib.ZlibOptions} [zlibOptions] + * @returns {InflateStream} + */ + function createInflate (zlibOptions) { + return new InflateStream(zlibOptions) + } + + /** + * @see https://fetch.spec.whatwg.org/#concept-header-extract-mime-type + * @param {import('./headers').HeadersList} headers + */ + function extractMimeType (headers) { + // 1. Let charset be null. + let charset = null; + + // 2. Let essence be null. + let essence = null; + + // 3. Let mimeType be null. + let mimeType = null; + + // 4. Let values be the result of getting, decoding, and splitting `Content-Type` from headers. + const values = getDecodeSplit('content-type', headers); + + // 5. If values is null, then return failure. + if (values === null) { + return 'failure' + } + + // 6. For each value of values: + for (const value of values) { + // 6.1. Let temporaryMimeType be the result of parsing value. + const temporaryMimeType = parseMIMEType(value); + + // 6.2. If temporaryMimeType is failure or its essence is "*/*", then continue. + if (temporaryMimeType === 'failure' || temporaryMimeType.essence === '*/*') { + continue + } + + // 6.3. Set mimeType to temporaryMimeType. + mimeType = temporaryMimeType; + + // 6.4. If mimeType’s essence is not essence, then: + if (mimeType.essence !== essence) { + // 6.4.1. Set charset to null. + charset = null; + + // 6.4.2. If mimeType’s parameters["charset"] exists, then set charset to + // mimeType’s parameters["charset"]. + if (mimeType.parameters.has('charset')) { + charset = mimeType.parameters.get('charset'); + } + + // 6.4.3. Set essence to mimeType’s essence. + essence = mimeType.essence; + } else if (!mimeType.parameters.has('charset') && charset !== null) { + // 6.5. Otherwise, if mimeType’s parameters["charset"] does not exist, and + // charset is non-null, set mimeType’s parameters["charset"] to charset. + mimeType.parameters.set('charset', charset); + } + } + + // 7. If mimeType is null, then return failure. + if (mimeType == null) { + return 'failure' + } + + // 8. Return mimeType. + return mimeType + } + + /** + * @see https://fetch.spec.whatwg.org/#header-value-get-decode-and-split + * @param {string|null} value + */ + function gettingDecodingSplitting (value) { + // 1. Let input be the result of isomorphic decoding value. + const input = value; + + // 2. Let position be a position variable for input, initially pointing at the start of input. + const position = { position: 0 }; + + // 3. Let values be a list of strings, initially empty. + const values = []; + + // 4. Let temporaryValue be the empty string. + let temporaryValue = ''; + + // 5. While position is not past the end of input: + while (position.position < input.length) { + // 5.1. Append the result of collecting a sequence of code points that are not U+0022 (") + // or U+002C (,) from input, given position, to temporaryValue. + temporaryValue += collectASequenceOfCodePoints( + (char) => char !== '"' && char !== ',', + input, + position + ); + + // 5.2. If position is not past the end of input, then: + if (position.position < input.length) { + // 5.2.1. If the code point at position within input is U+0022 ("), then: + if (input.charCodeAt(position.position) === 0x22) { + // 5.2.1.1. Append the result of collecting an HTTP quoted string from input, given position, to temporaryValue. + temporaryValue += collectAnHTTPQuotedString( + input, + position + ); + + // 5.2.1.2. If position is not past the end of input, then continue. + if (position.position < input.length) { + continue + } + } else { + // 5.2.2. Otherwise: + + // 5.2.2.1. Assert: the code point at position within input is U+002C (,). + assert(input.charCodeAt(position.position) === 0x2C); + + // 5.2.2.2. Advance position by 1. + position.position++; + } + } + + // 5.3. Remove all HTTP tab or space from the start and end of temporaryValue. + temporaryValue = removeChars(temporaryValue, true, true, (char) => char === 0x9 || char === 0x20); + + // 5.4. Append temporaryValue to values. + values.push(temporaryValue); + + // 5.6. Set temporaryValue to the empty string. + temporaryValue = ''; + } + + // 6. Return values. + return values + } + + /** + * @see https://fetch.spec.whatwg.org/#concept-header-list-get-decode-split + * @param {string} name lowercase header name + * @param {import('./headers').HeadersList} list + */ + function getDecodeSplit (name, list) { + // 1. Let value be the result of getting name from list. + const value = list.get(name, true); + + // 2. If value is null, then return null. + if (value === null) { + return null + } + + // 3. Return the result of getting, decoding, and splitting value. + return gettingDecodingSplitting(value) + } + + const textDecoder = new TextDecoder(); + + /** + * @see https://encoding.spec.whatwg.org/#utf-8-decode + * @param {Buffer} buffer + */ + function utf8DecodeBytes (buffer) { + if (buffer.length === 0) { + return '' + } + + // 1. Let buffer be the result of peeking three bytes from + // ioQueue, converted to a byte sequence. + + // 2. If buffer is 0xEF 0xBB 0xBF, then read three + // bytes from ioQueue. (Do nothing with those bytes.) + if (buffer[0] === 0xEF && buffer[1] === 0xBB && buffer[2] === 0xBF) { + buffer = buffer.subarray(3); + } + + // 3. Process a queue with an instance of UTF-8’s + // decoder, ioQueue, output, and "replacement". + const output = textDecoder.decode(buffer); + + // 4. Return output. + return output + } + + class EnvironmentSettingsObjectBase { + get baseUrl () { + return getGlobalOrigin() } + + get origin () { + return this.baseUrl?.origin + } + + policyContainer = makePolicyContainer() } + class EnvironmentSettingsObject { + settingsObject = new EnvironmentSettingsObjectBase() + } + + const environmentSettingsObject = new EnvironmentSettingsObject(); + + util$7 = { + 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 + }; + return util$7; +} + +var symbols$3; +var hasRequiredSymbols$3; + +function requireSymbols$3 () { + if (hasRequiredSymbols$3) return symbols$3; + hasRequiredSymbols$3 = 1; + + symbols$3 = { + kUrl: Symbol('url'), + kHeaders: Symbol('headers'), + kSignal: Symbol('signal'), + kState: Symbol('state'), + kDispatcher: Symbol('dispatcher') + }; + return symbols$3; +} + +var file; +var hasRequiredFile; + +function requireFile () { + if (hasRequiredFile) return file; + hasRequiredFile = 1; + + const { Blob, File } = require$$0$2; + const { kState } = requireSymbols$3(); + const { webidl } = requireWebidl(); + + // TODO(@KhafraDev): remove class FileLike { constructor (blobLike, fileName, options = {}) { // TODO: argument idl type check @@ -6080,154 +7525,24 @@ function requireFile () { } } - Object.defineProperties(File.prototype, { - [Symbol.toStringTag]: { - value: 'File', - configurable: true - }, - name: kEnumerableProperty, - lastModified: kEnumerableProperty - }); - webidl.converters.Blob = webidl.interfaceConverter(Blob); - webidl.converters.BlobPart = function (V, opts) { - if (webidl.util.Type(V) === 'Object') { - if (isBlobLike(V)) { - return webidl.converters.Blob(V, { strict: false }) - } + // If this function is moved to ./util.js, some tools (such as + // rollup) will warn about circular dependencies. See: + // https://github.com/nodejs/undici/issues/1629 + function isFileLike (object) { + return ( + (object instanceof File) || + ( + object && + (typeof object.stream === 'function' || + typeof object.arrayBuffer === 'function') && + object[Symbol.toStringTag] === 'File' + ) + ) + } - if ( - ArrayBuffer.isView(V) || - types.isAnyArrayBuffer(V) - ) { - return webidl.converters.BufferSource(V, opts) - } - } - - return webidl.converters.USVString(V, opts) - }; - - webidl.converters['sequence'] = webidl.sequenceConverter( - webidl.converters.BlobPart - ); - - // https://www.w3.org/TR/FileAPI/#dfn-FilePropertyBag - webidl.converters.FilePropertyBag = webidl.dictionaryConverter([ - { - key: 'lastModified', - converter: webidl.converters['long long'], - get defaultValue () { - return Date.now() - } - }, - { - key: 'type', - converter: webidl.converters.DOMString, - defaultValue: '' - }, - { - key: 'endings', - converter: (value) => { - value = webidl.converters.DOMString(value); - value = value.toLowerCase(); - - if (value !== 'native') { - value = 'transparent'; - } - - return value - }, - defaultValue: 'transparent' - } - ]); - - /** - * @see https://www.w3.org/TR/FileAPI/#process-blob-parts - * @param {(NodeJS.TypedArray|Blob|string)[]} parts - * @param {{ type: string, endings: string }} options - */ - function processBlobParts (parts, options) { - // 1. Let bytes be an empty sequence of bytes. - /** @type {NodeJS.TypedArray[]} */ - const bytes = []; - - // 2. For each element in parts: - for (const element of parts) { - // 1. If element is a USVString, run the following substeps: - if (typeof element === 'string') { - // 1. Let s be element. - let s = element; - - // 2. If the endings member of options is "native", set s - // to the result of converting line endings to native - // of element. - if (options.endings === 'native') { - s = convertLineEndingsNative(s); - } - - // 3. Append the result of UTF-8 encoding s to bytes. - bytes.push(encoder.encode(s)); - } else if ( - types.isAnyArrayBuffer(element) || - types.isTypedArray(element) - ) { - // 2. If element is a BufferSource, get a copy of the - // bytes held by the buffer source, and append those - // bytes to bytes. - if (!element.buffer) { // ArrayBuffer - bytes.push(new Uint8Array(element)); - } else { - bytes.push( - new Uint8Array(element.buffer, element.byteOffset, element.byteLength) - ); - } - } else if (isBlobLike(element)) { - // 3. If element is a Blob, append the bytes it represents - // to bytes. - bytes.push(element); - } - } - - // 3. Return bytes. - return bytes - } - - /** - * @see https://www.w3.org/TR/FileAPI/#convert-line-endings-to-native - * @param {string} s - */ - function convertLineEndingsNative (s) { - // 1. Let native line ending be be the code point U+000A LF. - let nativeLineEnding = '\n'; - - // 2. If the underlying platform’s conventions are to - // represent newlines as a carriage return and line feed - // sequence, set native line ending to the code point - // U+000D CR followed by the code point U+000A LF. - if (process.platform === 'win32') { - nativeLineEnding = '\r\n'; - } - - return s.replace(/\r?\n/g, nativeLineEnding) - } - - // If this function is moved to ./util.js, some tools (such as - // rollup) will warn about circular dependencies. See: - // https://github.com/nodejs/undici/issues/1629 - function isFileLike (object) { - return ( - (NativeFile && object instanceof NativeFile) || - object instanceof File || ( - object && - (typeof object.stream === 'function' || - typeof object.arrayBuffer === 'function') && - object[Symbol.toStringTag] === 'File' - ) - ) - } - - file = { File, FileLike, isFileLike }; + file = { FileLike, isFileLike }; return file; } @@ -6238,18 +7553,22 @@ function requireFormdata () { if (hasRequiredFormdata) return formdata; hasRequiredFormdata = 1; - const { isBlobLike, toUSVString, makeIterator } = requireUtil$6(); + const { isBlobLike, iteratorMixin } = requireUtil$7(); const { kState } = requireSymbols$3(); - const { File: UndiciFile, FileLike, isFileLike } = requireFile(); + const { kEnumerableProperty } = requireUtil$8(); + const { FileLike, isFileLike } = requireFile(); const { webidl } = requireWebidl(); - const { Blob, File: NativeFile } = require$$7; + const { File: NativeFile } = require$$0$2; + const nodeUtil = require$$0$6; /** @type {globalThis['File']} */ - const File = NativeFile ?? UndiciFile; + const File = globalThis.File ?? NativeFile; // https://xhr.spec.whatwg.org/#formdata class FormData { constructor (form) { + webidl.util.markAsUncloneable(this); + if (form !== undefined) { throw webidl.errors.conversionFailed({ prefix: 'FormData constructor', @@ -6264,7 +7583,8 @@ function requireFormdata () { append (name, value, filename = undefined) { webidl.brandCheck(this, FormData); - webidl.argumentLengthCheck(arguments, 2, { header: 'FormData.append' }); + const prefix = 'FormData.append'; + webidl.argumentLengthCheck(arguments, 2, prefix); if (arguments.length === 3 && !isBlobLike(value)) { throw new TypeError( @@ -6274,12 +7594,12 @@ function requireFormdata () { // 1. Let value be value if given; otherwise blobValue. - name = webidl.converters.USVString(name); + name = webidl.converters.USVString(name, prefix, 'name'); value = isBlobLike(value) - ? webidl.converters.Blob(value, { strict: false }) - : webidl.converters.USVString(value); + ? webidl.converters.Blob(value, prefix, 'value', { strict: false }) + : webidl.converters.USVString(value, prefix, 'value'); filename = arguments.length === 3 - ? webidl.converters.USVString(filename) + ? webidl.converters.USVString(filename, prefix, 'filename') : undefined; // 2. Let entry be the result of creating an entry with @@ -6293,9 +7613,10 @@ function requireFormdata () { delete (name) { webidl.brandCheck(this, FormData); - webidl.argumentLengthCheck(arguments, 1, { header: 'FormData.delete' }); + const prefix = 'FormData.delete'; + webidl.argumentLengthCheck(arguments, 1, prefix); - name = webidl.converters.USVString(name); + name = webidl.converters.USVString(name, prefix, 'name'); // The delete(name) method steps are to remove all entries whose name // is name from this’s entry list. @@ -6305,9 +7626,10 @@ function requireFormdata () { get (name) { webidl.brandCheck(this, FormData); - webidl.argumentLengthCheck(arguments, 1, { header: 'FormData.get' }); + const prefix = 'FormData.get'; + webidl.argumentLengthCheck(arguments, 1, prefix); - name = webidl.converters.USVString(name); + name = webidl.converters.USVString(name, prefix, 'name'); // 1. If there is no entry whose name is name in this’s entry list, // then return null. @@ -6324,9 +7646,10 @@ function requireFormdata () { getAll (name) { webidl.brandCheck(this, FormData); - webidl.argumentLengthCheck(arguments, 1, { header: 'FormData.getAll' }); + const prefix = 'FormData.getAll'; + webidl.argumentLengthCheck(arguments, 1, prefix); - name = webidl.converters.USVString(name); + name = webidl.converters.USVString(name, prefix, 'name'); // 1. If there is no entry whose name is name in this’s entry list, // then return the empty list. @@ -6340,9 +7663,10 @@ function requireFormdata () { has (name) { webidl.brandCheck(this, FormData); - webidl.argumentLengthCheck(arguments, 1, { header: 'FormData.has' }); + const prefix = 'FormData.has'; + webidl.argumentLengthCheck(arguments, 1, prefix); - name = webidl.converters.USVString(name); + name = webidl.converters.USVString(name, prefix, 'name'); // The has(name) method steps are to return true if there is an entry // whose name is name in this’s entry list; otherwise false. @@ -6352,7 +7676,8 @@ function requireFormdata () { set (name, value, filename = undefined) { webidl.brandCheck(this, FormData); - webidl.argumentLengthCheck(arguments, 2, { header: 'FormData.set' }); + const prefix = 'FormData.set'; + webidl.argumentLengthCheck(arguments, 2, prefix); if (arguments.length === 3 && !isBlobLike(value)) { throw new TypeError( @@ -6365,12 +7690,12 @@ function requireFormdata () { // 1. Let value be value if given; otherwise blobValue. - name = webidl.converters.USVString(name); + name = webidl.converters.USVString(name, prefix, 'name'); value = isBlobLike(value) - ? webidl.converters.Blob(value, { strict: false }) - : webidl.converters.USVString(value); + ? webidl.converters.Blob(value, prefix, 'name', { strict: false }) + : webidl.converters.USVString(value, prefix, 'name'); filename = arguments.length === 3 - ? toUSVString(filename) + ? webidl.converters.USVString(filename, prefix, 'name') : undefined; // 2. Let entry be the result of creating an entry with name, value, and @@ -6392,60 +7717,40 @@ function requireFormdata () { } } - entries () { - webidl.brandCheck(this, FormData); - - return makeIterator( - () => this[kState].map(pair => [pair.name, pair.value]), - 'FormData', - 'key+value' - ) - } - - keys () { - webidl.brandCheck(this, FormData); - - return makeIterator( - () => this[kState].map(pair => [pair.name, pair.value]), - 'FormData', - 'key' - ) - } - - values () { - webidl.brandCheck(this, FormData); - - return makeIterator( - () => this[kState].map(pair => [pair.name, pair.value]), - 'FormData', - 'value' - ) - } + [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; + } - /** - * @param {(value: string, key: string, self: FormData) => void} callbackFn - * @param {unknown} thisArg - */ - forEach (callbackFn, thisArg = globalThis) { - webidl.brandCheck(this, FormData); + return a + }, { __proto__: null }); - webidl.argumentLengthCheck(arguments, 1, { header: 'FormData.forEach' }); + options.depth ??= depth; + options.colors ??= true; - if (typeof callbackFn !== 'function') { - throw new TypeError( - "Failed to execute 'forEach' on 'FormData': parameter 1 is not of type 'Function'." - ) - } + const output = nodeUtil.formatWithOptions(options, state); - for (const [key, value] of this) { - callbackFn.apply(thisArg, [value, key, this]); - } + // remove [Object null prototype] + return `FormData ${output.slice(output.indexOf(']') + 2)}` } } - FormData.prototype[Symbol.iterator] = FormData.prototype.entries; + 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 @@ -6461,16 +7766,11 @@ function requireFormdata () { */ function makeEntry (name, value, filename) { // 1. Set name to the result of converting name into a scalar value string. - // "To convert a string into a scalar value string, replace any surrogates - // with U+FFFD." - // see: https://nodejs.org/dist/latest-v18.x/docs/api/buffer.html#buftostringencoding-start-end - name = Buffer.from(name).toString('utf8'); + // Note: This operation was done by the webidl converter USVString. // 2. If value is a string, then set value to the result of converting // value into a scalar value string. - if (typeof value === 'string') { - value = Buffer.from(value).toString('utf8'); - } else { + if (typeof value === 'string') ; else { // 3. Otherwise: // 1. If value is not a File object, then set value to a new File object, @@ -6490,7 +7790,7 @@ function requireFormdata () { lastModified: value.lastModified }; - value = (NativeFile && value instanceof NativeFile) || value instanceof UndiciFile + value = value instanceof NativeFile ? new File([value], filename, options) : new FileLike(value, filename, options); } @@ -6500,10 +7800,492 @@ function requireFormdata () { return { name, value } } - formdata = { FormData }; + formdata = { FormData, makeEntry }; return formdata; } +var formdataParser; +var hasRequiredFormdataParser; + +function requireFormdataParser () { + if (hasRequiredFormdataParser) return formdataParser; + hasRequiredFormdataParser = 1; + + const { isUSVString, bufferToLowerCasedHeaderName } = requireUtil$8(); + const { utf8DecodeBytes } = requireUtil$7(); + const { HTTP_TOKEN_CODEPOINTS, isomorphicDecode } = requireDataUrl(); + const { isFileLike } = requireFile(); + const { makeEntry } = requireFormdata(); + const assert = require$$0$3; + const { File: NodeFile } = require$$0$2; + + const File = globalThis.File ?? NodeFile; + + const formDataNameBuffer = Buffer.from('form-data; name="'); + const filenameBuffer = Buffer.from('; filename'); + const dd = Buffer.from('--'); + const ddcrlf = Buffer.from('--\r\n'); + + /** + * @param {string} chars + */ + function isAsciiString (chars) { + for (let i = 0; i < chars.length; ++i) { + if ((chars.charCodeAt(i) & -128) !== 0) { + return false + } + } + return true + } + + /** + * @see https://andreubotella.github.io/multipart-form-data/#multipart-form-data-boundary + * @param {string} boundary + */ + function validateBoundary (boundary) { + const length = boundary.length; + + // - its length is greater or equal to 27 and lesser or equal to 70, and + if (length < 27 || length > 70) { + return false + } + + // - it is composed by bytes in the ranges 0x30 to 0x39, 0x41 to 0x5A, or + // 0x61 to 0x7A, inclusive (ASCII alphanumeric), or which are 0x27 ('), + // 0x2D (-) or 0x5F (_). + for (let i = 0; i < length; ++i) { + const cp = boundary.charCodeAt(i); + + if (!( + (cp >= 0x30 && cp <= 0x39) || + (cp >= 0x41 && cp <= 0x5a) || + (cp >= 0x61 && cp <= 0x7a) || + cp === 0x27 || + cp === 0x2d || + cp === 0x5f + )) { + return false + } + } + + return true + } + + /** + * @see https://andreubotella.github.io/multipart-form-data/#multipart-form-data-parser + * @param {Buffer} input + * @param {ReturnType} mimeType + */ + function multipartFormDataParser (input, mimeType) { + // 1. Assert: mimeType’s essence is "multipart/form-data". + assert(mimeType !== 'failure' && mimeType.essence === 'multipart/form-data'); + + const boundaryString = mimeType.parameters.get('boundary'); + + // 2. If mimeType’s parameters["boundary"] does not exist, return failure. + // Otherwise, let boundary be the result of UTF-8 decoding mimeType’s + // parameters["boundary"]. + if (boundaryString === undefined) { + return 'failure' + } + + const boundary = Buffer.from(`--${boundaryString}`, 'utf8'); + + // 3. Let entry list be an empty entry list. + const entryList = []; + + // 4. Let position be a pointer to a byte in input, initially pointing at + // the first byte. + const position = { position: 0 }; + + // Note: undici addition, allows leading and trailing CRLFs. + while (input[position.position] === 0x0d && input[position.position + 1] === 0x0a) { + position.position += 2; + } + + let trailing = input.length; + + while (input[trailing - 1] === 0x0a && input[trailing - 2] === 0x0d) { + trailing -= 2; + } + + if (trailing !== input.length) { + input = input.subarray(0, trailing); + } + + // 5. While true: + while (true) { + // 5.1. If position points to a sequence of bytes starting with 0x2D 0x2D + // (`--`) followed by boundary, advance position by 2 + the length of + // boundary. Otherwise, return failure. + // Note: boundary is padded with 2 dashes already, no need to add 2. + if (input.subarray(position.position, position.position + boundary.length).equals(boundary)) { + position.position += boundary.length; + } else { + return 'failure' + } + + // 5.2. If position points to the sequence of bytes 0x2D 0x2D 0x0D 0x0A + // (`--` followed by CR LF) followed by the end of input, return entry list. + // Note: a body does NOT need to end with CRLF. It can end with --. + if ( + (position.position === input.length - 2 && bufferStartsWith(input, dd, position)) || + (position.position === input.length - 4 && bufferStartsWith(input, ddcrlf, position)) + ) { + return entryList + } + + // 5.3. If position does not point to a sequence of bytes starting with 0x0D + // 0x0A (CR LF), return failure. + if (input[position.position] !== 0x0d || input[position.position + 1] !== 0x0a) { + return 'failure' + } + + // 5.4. Advance position by 2. (This skips past the newline.) + position.position += 2; + + // 5.5. Let name, filename and contentType be the result of parsing + // multipart/form-data headers on input and position, if the result + // is not failure. Otherwise, return failure. + const result = parseMultipartFormDataHeaders(input, position); + + if (result === 'failure') { + return 'failure' + } + + let { name, filename, contentType, encoding } = result; + + // 5.6. Advance position by 2. (This skips past the empty line that marks + // the end of the headers.) + position.position += 2; + + // 5.7. Let body be the empty byte sequence. + let body; + + // 5.8. Body loop: While position is not past the end of input: + // TODO: the steps here are completely wrong + { + 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; + + // Note: position must be advanced by the body's length before being + // decoded, otherwise the parsing will fail. + if (encoding === 'base64') { + body = Buffer.from(body.toString(), 'base64'); + } + } + + // 5.9. If position does not point to a sequence of bytes starting with + // 0x0D 0x0A (CR LF), return failure. Otherwise, advance position by 2. + if (input[position.position] !== 0x0d || input[position.position + 1] !== 0x0a) { + return 'failure' + } else { + position.position += 2; + } + + // 5.10. If filename is not null: + let value; + + if (filename !== null) { + // 5.10.1. If contentType is null, set contentType to "text/plain". + contentType ??= 'text/plain'; + + // 5.10.2. If contentType is not an ASCII string, set contentType to the empty string. + + // Note: `buffer.isAscii` can be used at zero-cost, but converting a string to a buffer is a high overhead. + // Content-Type is a relatively small string, so it is faster to use `String#charCodeAt`. + if (!isAsciiString(contentType)) { + contentType = ''; + } + + // 5.10.3. Let value be a new File object with name filename, type contentType, and body body. + value = new File([body], filename, { type: contentType }); + } else { + // 5.11. Otherwise: + + // 5.11.1. Let value be the UTF-8 decoding without BOM of body. + value = utf8DecodeBytes(Buffer.from(body)); + } + + // 5.12. Assert: name is a scalar value string and value is either a scalar value string or a File object. + assert(isUSVString(name)); + assert((typeof value === 'string' && isUSVString(value)) || isFileLike(value)); + + // 5.13. Create an entry with name and value, and append it to entry list. + entryList.push(makeEntry(name, value, filename)); + } + } + + /** + * @see https://andreubotella.github.io/multipart-form-data/#parse-multipart-form-data-headers + * @param {Buffer} input + * @param {{ position: number }} position + */ + function parseMultipartFormDataHeaders (input, position) { + // 1. Let name, filename and contentType be null. + let name = null; + let filename = null; + let contentType = null; + let encoding = null; + + // 2. While true: + while (true) { + // 2.1. If position points to a sequence of bytes starting with 0x0D 0x0A (CR LF): + if (input[position.position] === 0x0d && input[position.position + 1] === 0x0a) { + // 2.1.1. If name is null, return failure. + if (name === null) { + return 'failure' + } + + // 2.1.2. Return name, filename and contentType. + return { name, filename, contentType, encoding } + } + + // 2.2. Let header name be the result of collecting a sequence of bytes that are + // not 0x0A (LF), 0x0D (CR) or 0x3A (:), given position. + let headerName = collectASequenceOfBytes( + (char) => char !== 0x0a && char !== 0x0d && char !== 0x3a, + input, + position + ); + + // 2.3. Remove any HTTP tab or space bytes from the start or end of header name. + headerName = removeChars(headerName, true, true, (char) => char === 0x9 || char === 0x20); + + // 2.4. If header name does not match the field-name token production, return failure. + if (!HTTP_TOKEN_CODEPOINTS.test(headerName.toString())) { + return 'failure' + } + + // 2.5. If the byte at position is not 0x3A (:), return failure. + if (input[position.position] !== 0x3a) { + return 'failure' + } + + // 2.6. Advance position by 1. + position.position++; + + // 2.7. Collect a sequence of bytes that are HTTP tab or space bytes given position. + // (Do nothing with those bytes.) + collectASequenceOfBytes( + (char) => char === 0x20 || char === 0x09, + input, + position + ); + + // 2.8. Byte-lowercase header name and switch on the result: + switch (bufferToLowerCasedHeaderName(headerName)) { + case 'content-disposition': { + // 1. Set name and filename to null. + name = filename = null; + + // 2. If position does not point to a sequence of bytes starting with + // `form-data; name="`, return failure. + if (!bufferStartsWith(input, formDataNameBuffer, position)) { + return 'failure' + } + + // 3. Advance position so it points at the byte after the next 0x22 (") + // byte (the one in the sequence of bytes matched above). + position.position += 17; + + // 4. Set name to the result of parsing a multipart/form-data name given + // input and position, if the result is not failure. Otherwise, return + // failure. + name = parseMultipartFormDataName(input, position); + + if (name === null) { + return 'failure' + } + + // 5. If position points to a sequence of bytes starting with `; filename="`: + if (bufferStartsWith(input, filenameBuffer, position)) { + // Note: undici also handles filename* + let check = position.position + filenameBuffer.length; + + if (input[check] === 0x2a) { + position.position += 1; + check += 1; + } + + if (input[check] !== 0x3d || input[check + 1] !== 0x22) { // =" + return 'failure' + } + + // 1. Advance position so it points at the byte after the next 0x22 (") byte + // (the one in the sequence of bytes matched above). + position.position += 12; + + // 2. Set filename to the result of parsing a multipart/form-data name given + // input and position, if the result is not failure. Otherwise, return failure. + filename = parseMultipartFormDataName(input, position); + + if (filename === null) { + return 'failure' + } + } + + break + } + case 'content-type': { + // 1. Let header value be the result of collecting a sequence of bytes that are + // not 0x0A (LF) or 0x0D (CR), given position. + let headerValue = collectASequenceOfBytes( + (char) => char !== 0x0a && char !== 0x0d, + input, + position + ); + + // 2. Remove any HTTP tab or space bytes from the end of header value. + headerValue = removeChars(headerValue, false, true, (char) => char === 0x9 || char === 0x20); + + // 3. Set contentType to the isomorphic decoding of header value. + contentType = isomorphicDecode(headerValue); + + break + } + case 'content-transfer-encoding': { + let headerValue = collectASequenceOfBytes( + (char) => char !== 0x0a && char !== 0x0d, + input, + position + ); + + headerValue = removeChars(headerValue, false, true, (char) => char === 0x9 || char === 0x20); + + encoding = isomorphicDecode(headerValue); + + break + } + default: { + // Collect a sequence of bytes that are not 0x0A (LF) or 0x0D (CR), given position. + // (Do nothing with those bytes.) + collectASequenceOfBytes( + (char) => char !== 0x0a && char !== 0x0d, + input, + position + ); + } + } + + // 2.9. If position does not point to a sequence of bytes starting with 0x0D 0x0A + // (CR LF), return failure. Otherwise, advance position by 2 (past the newline). + if (input[position.position] !== 0x0d && input[position.position + 1] !== 0x0a) { + return 'failure' + } else { + position.position += 2; + } + } + } + + /** + * @see https://andreubotella.github.io/multipart-form-data/#parse-a-multipart-form-data-name + * @param {Buffer} input + * @param {{ position: number }} position + */ + function parseMultipartFormDataName (input, position) { + // 1. Assert: The byte at (position - 1) is 0x22 ("). + assert(input[position.position - 1] === 0x22); + + // 2. Let name be the result of collecting a sequence of bytes that are not 0x0A (LF), 0x0D (CR) or 0x22 ("), given position. + /** @type {string | Buffer} */ + let name = collectASequenceOfBytes( + (char) => char !== 0x0a && char !== 0x0d && char !== 0x22, + input, + position + ); + + // 3. If the byte at position is not 0x22 ("), return failure. Otherwise, advance position by 1. + if (input[position.position] !== 0x22) { + return null // name could be 'failure' + } else { + position.position++; + } + + // 4. Replace any occurrence of the following subsequences in name with the given byte: + // - `%0A`: 0x0A (LF) + // - `%0D`: 0x0D (CR) + // - `%22`: 0x22 (") + name = new TextDecoder().decode(name) + .replace(/%0A/ig, '\n') + .replace(/%0D/ig, '\r') + .replace(/%22/g, '"'); + + // 5. Return the UTF-8 decoding without BOM of name. + return name + } + + /** + * @param {(char: number) => boolean} condition + * @param {Buffer} input + * @param {{ position: number }} position + */ + 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)) + } + + /** + * @param {Buffer} buf + * @param {boolean} leading + * @param {boolean} trailing + * @param {(charCode: number) => boolean} predicate + * @returns {Buffer} + */ + function removeChars (buf, leading, trailing, predicate) { + let lead = 0; + let trail = buf.length - 1; + + if (leading) { + while (lead < buf.length && predicate(buf[lead])) lead++; + } + + { + while (trail > 0 && predicate(buf[trail])) trail--; + } + + return lead === 0 && trail === buf.length - 1 ? buf : buf.subarray(lead, trail + 1) + } + + /** + * Checks if {@param buffer} starts with {@param start} + * @param {Buffer} buffer + * @param {Buffer} start + * @param {{ position: number }} position + */ + 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 + } + + formdataParser = { + multipartFormDataParser, + validateBoundary + }; + return formdataParser; +} + var body; var hasRequiredBody; @@ -6511,29 +8293,28 @@ function requireBody () { if (hasRequiredBody) return body; hasRequiredBody = 1; - const Busboy = requireMain(); - const util = requireUtil$7(); + const util = requireUtil$8(); const { ReadableStreamFrom, isBlobLike, isReadableStreamLike, readableStreamClose, createDeferredPromise, - fullyReadBody - } = requireUtil$6(); + fullyReadBody, + extractMimeType, + utf8DecodeBytes + } = requireUtil$7(); const { FormData } = requireFormdata(); const { kState } = requireSymbols$3(); const { webidl } = requireWebidl(); - const { DOMException, structuredClone } = requireConstants$3(); - const { Blob, File: NativeFile } = require$$7; - const { kBodyUsed } = requireSymbols$4(); + const { Blob } = require$$0$2; const assert = require$$0$3; - const { isErrored } = requireUtil$7(); - const { isUint8Array, isArrayBuffer } = require$$5; - const { File: UndiciFile } = requireFile(); - const { parseMIMEType, serializeAMimeType } = requireDataURL(); - + const { isErrored, isDisturbed } = require$$0$4; + const { isArrayBuffer } = require$$8$1; + const { serializeAMimeType } = requireDataUrl(); + const { multipartFormDataParser } = requireFormdataParser(); let random; + try { const crypto = require('node:crypto'); random = (max) => crypto.randomInt(0, max); @@ -6541,19 +8322,23 @@ function requireBody () { random = (max) => Math.floor(Math.random(max)); } - let ReadableStream = globalThis.ReadableStream; - - /** @type {globalThis['File']} */ - const File = NativeFile ?? UndiciFile; const textEncoder = new TextEncoder(); - const textDecoder = new TextDecoder(); + function noop () {} + + const hasFinalizationRegistry = globalThis.FinalizationRegistry && process.version.indexOf('v18') !== 0; + let 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); + } + }); + } // https://fetch.spec.whatwg.org/#concept-bodyinit-extract function extractBody (object, keepalive = false) { - if (!ReadableStream) { - ReadableStream = require$$14.ReadableStream; - } - // 1. Let stream be null. let stream = null; @@ -6566,16 +8351,19 @@ function requireBody () { stream = object.stream(); } else { // 4. Otherwise, set stream to a new ReadableStream object, and set - // up stream. + // up stream with byte reading support. stream = new ReadableStream({ async pull (controller) { - controller.enqueue( - typeof source === 'string' ? textEncoder.encode(source) : source - ); + const buffer = typeof source === 'string' ? textEncoder.encode(source) : source; + + if (buffer.byteLength) { + controller.enqueue(buffer); + } + queueMicrotask(() => readableStreamClose(controller)); }, start () {}, - type: undefined + type: 'bytes' }); } @@ -6667,7 +8455,10 @@ function requireBody () { } } - const chunk = textEncoder.encode(`--${boundary}--`); + // CRLF is appended to the body to function with legacy servers and match other implementations. + // https://github.com/curl/curl/blob/3434c6b46e682452973972e8313613dfa58cd690/lib/mime.c#L1029-L1030 + // https://github.com/form-data/form-data/issues/63 + const chunk = textEncoder.encode(`--${boundary}--\r\n`); blobParts.push(chunk); length += chunk.byteLength; if (hasUnknownSizeValue) { @@ -6690,7 +8481,7 @@ function requireBody () { // Set type to `multipart/form-data; boundary=`, // followed by the multipart/form-data boundary string generated // by the multipart/form-data encoding algorithm. - type = 'multipart/form-data; boundary=' + boundary; + type = `multipart/form-data; boundary=${boundary}`; } else if (isBlobLike(object)) { // Blob @@ -6742,13 +8533,17 @@ function requireBody () { // When running action is done, close stream. queueMicrotask(() => { controller.close(); + controller.byobRequest?.respond(0); }); } else { // Whenever one or more bytes are available and stream is not errored, // enqueue a Uint8Array wrapping an ArrayBuffer containing the available // bytes into stream. if (!isErrored(stream)) { - controller.enqueue(new Uint8Array(value)); + const buffer = new Uint8Array(value); + if (buffer.byteLength) { + controller.enqueue(buffer); + } } } return controller.desiredSize > 0 @@ -6756,7 +8551,7 @@ function requireBody () { async cancel (reason) { await iterator.return(); }, - type: undefined + type: 'bytes' }); } @@ -6770,11 +8565,6 @@ function requireBody () { // https://fetch.spec.whatwg.org/#bodyinit-safely-extract function safelyExtractBody (object, keepalive = false) { - if (!ReadableStream) { - // istanbul ignore next - ReadableStream = require$$14.ReadableStream; - } - // To safely extract a body and a `Content-Type` value from // a byte sequence or BodyInit object object, run these steps: @@ -6791,52 +8581,25 @@ function requireBody () { return extractBody(object, keepalive) } - function cloneBody (body) { + function cloneBody (instance, body) { // To clone a body body, run these steps: // https://fetch.spec.whatwg.org/#concept-body-clone // 1. Let « out1, out2 » be the result of teeing body’s stream. const [out1, out2] = body.stream.tee(); - const out2Clone = structuredClone(out2, { transfer: [out2] }); - // This, for whatever reasons, unrefs out2Clone which allows - // the process to exit by itself. - const [, finalClone] = out2Clone.tee(); // 2. Set body’s stream to out1. body.stream = out1; // 3. Return a body whose stream is out2 and other members are copied from body. return { - stream: finalClone, + stream: out2, length: body.length, source: body.source } } - async function * consumeBody (body) { - if (body) { - if (isUint8Array(body)) { - yield body; - } else { - const stream = body.stream; - - if (util.isDisturbed(stream)) { - throw new TypeError('The body has already been consumed.') - } - - if (stream.locked) { - throw new TypeError('The stream is locked.') - } - - // Compat. - stream[kBodyUsed] = true; - - yield * stream; - } - } - } - function throwIfAborted (state) { if (state.aborted) { throw new DOMException('The operation was aborted.', 'AbortError') @@ -6851,10 +8614,10 @@ function requireBody () { // given a byte sequence bytes: return a Blob whose // contents are bytes and whose type attribute is this’s // MIME type. - return specConsumeBody(this, (bytes) => { + return consumeBody(this, (bytes) => { let mimeType = bodyMimeType(this); - if (mimeType === 'failure') { + if (mimeType === null) { mimeType = ''; } else if (mimeType) { mimeType = serializeAMimeType(mimeType); @@ -6871,7 +8634,7 @@ function requireBody () { // of running consume body with this and the following step // given a byte sequence bytes: return a new ArrayBuffer // whose contents are bytes. - return specConsumeBody(this, (bytes) => { + return consumeBody(this, (bytes) => { return new Uint8Array(bytes).buffer }, instance) }, @@ -6879,126 +8642,74 @@ function requireBody () { text () { // The text() method steps are to return the result of running // consume body with this and UTF-8 decode. - return specConsumeBody(this, utf8DecodeBytes, instance) + return consumeBody(this, utf8DecodeBytes, instance) }, json () { // The json() method steps are to return the result of running // consume body with this and parse JSON from bytes. - return specConsumeBody(this, parseJSONFromBytes, instance) + return consumeBody(this, parseJSONFromBytes, instance) }, - async formData () { - webidl.brandCheck(this, instance); - - throwIfAborted(this[kState]); - - const contentType = this.headers.get('Content-Type'); - - // If mimeType’s essence is "multipart/form-data", then: - if (/multipart\/form-data/.test(contentType)) { - const headers = {}; - for (const [key, value] of this.headers) headers[key.toLowerCase()] = value; - - const responseFormData = new FormData(); - - let busboy; - - try { - busboy = new Busboy({ - headers, - preservePath: true - }); - } catch (err) { - throw new DOMException(`${err}`, 'AbortError') - } - - busboy.on('field', (name, value) => { - responseFormData.append(name, value); - }); - busboy.on('file', (name, value, filename, encoding, mimeType) => { - const chunks = []; - - if (encoding === 'base64' || encoding.toLowerCase() === 'base64') { - let base64chunk = ''; - - value.on('data', (chunk) => { - base64chunk += chunk.toString().replace(/[\r\n]/gm, ''); + formData () { + // The formData() method steps are to return the result of running + // consume body with this and the following step given a byte sequence bytes: + return consumeBody(this, (value) => { + // 1. Let mimeType be the result of get the MIME type with this. + const mimeType = bodyMimeType(this); + + // 2. If mimeType is non-null, then switch on mimeType’s essence and run + // the corresponding steps: + if (mimeType !== null) { + switch (mimeType.essence) { + case 'multipart/form-data': { + // 1. ... [long step] + const parsed = multipartFormDataParser(value, mimeType); + + // 2. If that fails for some reason, then throw a TypeError. + if (parsed === 'failure') { + throw new TypeError('Failed to parse body as FormData.') + } - const end = base64chunk.length - base64chunk.length % 4; - chunks.push(Buffer.from(base64chunk.slice(0, end), 'base64')); + // 3. Return a new FormData object, appending each entry, + // resulting from the parsing operation, to its entry list. + const fd = new FormData(); + fd[kState] = parsed; - base64chunk = base64chunk.slice(end); - }); - value.on('end', () => { - chunks.push(Buffer.from(base64chunk, 'base64')); - responseFormData.append(name, new File(chunks, filename, { type: mimeType })); - }); - } else { - value.on('data', (chunk) => { - chunks.push(chunk); - }); - value.on('end', () => { - responseFormData.append(name, new File(chunks, filename, { type: mimeType })); - }); - } - }); + return fd + } + case 'application/x-www-form-urlencoded': { + // 1. Let entries be the result of parsing bytes. + const entries = new URLSearchParams(value.toString()); - const busboyResolve = new Promise((resolve, reject) => { - busboy.on('finish', resolve); - busboy.on('error', (err) => reject(new TypeError(err))); - }); + // 2. If entries is failure, then throw a TypeError. - if (this.body !== null) for await (const chunk of consumeBody(this[kState].body)) busboy.write(chunk); - busboy.end(); - await busboyResolve; + // 3. Return a new FormData object whose entry list is entries. + const fd = new FormData(); - return responseFormData - } else if (/application\/x-www-form-urlencoded/.test(contentType)) { - // Otherwise, if mimeType’s essence is "application/x-www-form-urlencoded", then: + for (const [name, value] of entries) { + fd.append(name, value); + } - // 1. Let entries be the result of parsing bytes. - let entries; - try { - let text = ''; - // application/x-www-form-urlencoded parser will keep the BOM. - // https://url.spec.whatwg.org/#concept-urlencoded-parser - // Note that streaming decoder is stateful and cannot be reused - const streamingDecoder = new TextDecoder('utf-8', { ignoreBOM: true }); - - for await (const chunk of consumeBody(this[kState].body)) { - if (!isUint8Array(chunk)) { - throw new TypeError('Expected Uint8Array chunk') + return fd } - text += streamingDecoder.decode(chunk, { stream: true }); } - text += streamingDecoder.decode(); - entries = new URLSearchParams(text); - } catch (err) { - // istanbul ignore next: Unclear when new URLSearchParams can fail on a string. - // 2. If entries is failure, then throw a TypeError. - throw Object.assign(new TypeError(), { cause: err }) - } - - // 3. Return a new FormData object whose entries are entries. - const formData = new FormData(); - for (const [name, value] of entries) { - formData.append(name, value); } - return formData - } else { - // Wait a tick before checking if the request has been aborted. - // Otherwise, a TypeError can be thrown when an AbortError should. - await Promise.resolve(); - throwIfAborted(this[kState]); + // 3. Throw a TypeError. + throw new TypeError( + 'Content-Type was not one of "multipart/form-data" or "application/x-www-form-urlencoded".' + ) + }, instance) + }, - // Otherwise, throw a TypeError. - throw webidl.errors.exception({ - header: `${instance.name}.formData`, - message: 'Could not parse content as FormData.' - }) - } + bytes () { + // The bytes() method steps are to return the result of running consume body + // with this and the following step given a byte sequence bytes: return the + // result of creating a Uint8Array from bytes in this’s relevant realm. + return consumeBody(this, (bytes) => { + return new Uint8Array(bytes) + }, instance) } }; @@ -7015,17 +8726,17 @@ function requireBody () { * @param {(value: unknown) => unknown} convertBytesToJSValue * @param {Response|Request} instance */ - async function specConsumeBody (object, convertBytesToJSValue, instance) { + async function consumeBody (object, convertBytesToJSValue, instance) { webidl.brandCheck(object, instance); - throwIfAborted(object[kState]); - // 1. If object is unusable, then return a promise rejected // with a TypeError. - if (bodyUnusable(object[kState].body)) { - throw new TypeError('Body is unusable') + if (bodyUnusable(object)) { + throw new TypeError('Body is unusable: Body has already been read') } + throwIfAborted(object[kState]); + // 2. Let promise be a new promise. const promise = createDeferredPromise(); @@ -7047,7 +8758,7 @@ function requireBody () { // 5. If object’s body is null, then run successSteps with an // empty byte sequence. if (object[kState].body == null) { - successSteps(new Uint8Array()); + successSteps(Buffer.allocUnsafe(0)); return promise.promise } @@ -7060,39 +8771,15 @@ function requireBody () { } // https://fetch.spec.whatwg.org/#body-unusable - function bodyUnusable (body) { + function bodyUnusable (object) { + const body = object[kState].body; + // An object including the Body interface mixin is // said to be unusable if its body is non-null and // its body’s stream is disturbed or locked. return body != null && (body.stream.locked || util.isDisturbed(body.stream)) } - /** - * @see https://encoding.spec.whatwg.org/#utf-8-decode - * @param {Buffer} buffer - */ - function utf8DecodeBytes (buffer) { - if (buffer.length === 0) { - return '' - } - - // 1. Let buffer be the result of peeking three bytes from - // ioQueue, converted to a byte sequence. - - // 2. If buffer is 0xEF 0xBB 0xBF, then read three - // bytes from ioQueue. (Do nothing with those bytes.) - if (buffer[0] === 0xEF && buffer[1] === 0xBB && buffer[2] === 0xBF) { - buffer = buffer.subarray(3); - } - - // 3. Process a queue with an instance of UTF-8’s - // decoder, ioQueue, output, and "replacement". - const output = textDecoder.decode(buffer); - - // 4. Return output. - return output - } - /** * @see https://infra.spec.whatwg.org/#parse-json-bytes-to-a-javascript-value * @param {Uint8Array} bytes @@ -7103,1615 +8790,1464 @@ function requireBody () { /** * @see https://fetch.spec.whatwg.org/#concept-body-mime-type - * @param {import('./response').Response|import('./request').Request} object + * @param {import('./response').Response|import('./request').Request} requestOrResponse */ - function bodyMimeType (object) { - const { headersList } = object[kState]; - const contentType = headersList.get('content-type'); - - if (contentType === null) { - return 'failure' + function bodyMimeType (requestOrResponse) { + // 1. Let headers be null. + // 2. If requestOrResponse is a Request object, then set headers to requestOrResponse’s request’s header list. + // 3. Otherwise, set headers to requestOrResponse’s response’s header list. + /** @type {import('./headers').HeadersList} */ + const headers = requestOrResponse[kState].headersList; + + // 4. Let mimeType be the result of extracting a MIME type from headers. + const mimeType = extractMimeType(headers); + + // 5. If mimeType is failure, then return null. + if (mimeType === 'failure') { + return null } - return parseMIMEType(contentType) + // 6. Return mimeType. + return mimeType } body = { extractBody, safelyExtractBody, cloneBody, - mixinBody + mixinBody, + streamRegistry, + hasFinalizationRegistry, + bodyUnusable }; return body; } -var request$3; -var hasRequiredRequest$1; +var clientH1; +var hasRequiredClientH1; -function requireRequest$1 () { - if (hasRequiredRequest$1) return request$3; - hasRequiredRequest$1 = 1; +function requireClientH1 () { + if (hasRequiredClientH1) return clientH1; + hasRequiredClientH1 = 1; + /* global WebAssembly */ + + const assert = require$$0$3; + const util = requireUtil$8(); + const { channels } = requireDiagnostics(); + const timers = requireTimers(); const { - InvalidArgumentError, - NotSupportedError + RequestContentLengthMismatchError, + ResponseContentLengthMismatchError, + RequestAbortedError, + HeadersTimeoutError, + HeadersOverflowError, + SocketError, + InformationalError, + BodyTimeoutError, + HTTPParserError, + ResponseExceededMaxSizeError } = requireErrors(); - const assert = require$$0$3; - const { kHTTP2BuildRequest, kHTTP2CopyHeaders, kHTTP1BuildRequest } = requireSymbols$4(); - const util = requireUtil$7(); - - // tokenRegExp and headerCharRegex have been lifted from - // https://github.com/nodejs/node/blob/main/lib/_http_common.js - - /** - * Verifies that the given val is a valid HTTP token - * per the rules defined in RFC 7230 - * See https://tools.ietf.org/html/rfc7230#section-3.2.6 - */ - const tokenRegExp = /^[\^_`a-zA-Z\-0-9!#$%&'*+.|~]+$/; + const { + 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 + } = requireSymbols$4(); - /** - * Matches if val contains an invalid field-vchar - * field-value = *( field-content / obs-fold ) - * field-content = field-vchar [ 1*( SP / HTAB ) field-vchar ] - * field-vchar = VCHAR / obs-text - */ - const headerCharRegex = /[^\t\x20-\x7e\x80-\xff]/; + const constants = requireConstants$3(); + const EMPTY_BUF = Buffer.alloc(0); + const FastBuffer = Buffer[Symbol.species]; + const addListener = util.addListener; + const removeAllListeners = util.removeAllListeners; - // Verifies that a given path is valid does not contain control chars \x00 to \x20 - const invalidPathRegex = /[^\u0021-\u00ff]/; + let extractBody; - const kHandler = Symbol('handler'); + async function lazyllhttp () { + const llhttpWasmData = process.env.JEST_WORKER_ID ? requireLlhttpWasm() : undefined; - const channels = {}; + let mod; + try { + mod = await WebAssembly.compile(requireLlhttp_simdWasm()); + } catch (e) { + /* istanbul ignore next */ - let extractBody; + // We could check if the error was caused by the simd option not + // being enabled, but the occurring of this other error + // * https://github.com/emscripten-core/emscripten/issues/11495 + // got me to remove that check to avoid breaking Node 12. + mod = await WebAssembly.compile(llhttpWasmData || requireLlhttpWasm()); + } - try { - const diagnosticsChannel = require('diagnostics_channel'); - channels.create = diagnosticsChannel.channel('undici:request:create'); - channels.bodySent = diagnosticsChannel.channel('undici:request:bodySent'); - channels.headers = diagnosticsChannel.channel('undici:request:headers'); - channels.trailers = diagnosticsChannel.channel('undici:request:trailers'); - channels.error = diagnosticsChannel.channel('undici:request:error'); - } catch { - channels.create = { hasSubscribers: false }; - channels.bodySent = { hasSubscribers: false }; - channels.headers = { hasSubscribers: false }; - channels.trailers = { hasSubscribers: false }; - channels.error = { hasSubscribers: false }; - } + return await WebAssembly.instantiate(mod, { + env: { + /* eslint-disable camelcase */ - class Request { - constructor (origin, { - path, - method, - body, - headers, - query, - idempotent, - blocking, - upgrade, - headersTimeout, - bodyTimeout, - reset, - throwOnError, - expectContinue - }, handler) { - if (typeof path !== 'string') { - throw new InvalidArgumentError('path must be a string') - } else if ( - path[0] !== '/' && - !(path.startsWith('http://') || path.startsWith('https://')) && - method !== 'CONNECT' - ) { - throw new InvalidArgumentError('path must be an absolute URL or start with a slash') - } else if (invalidPathRegex.exec(path) !== null) { - throw new InvalidArgumentError('invalid request path') - } - - if (typeof method !== 'string') { - throw new InvalidArgumentError('method must be a string') - } else if (tokenRegExp.exec(method) === null) { - throw new InvalidArgumentError('invalid request method') - } - - if (upgrade && typeof upgrade !== 'string') { - throw new InvalidArgumentError('upgrade must be a string') - } + wasm_on_url: (p, at, len) => { + /* istanbul ignore next */ + 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 + } - if (headersTimeout != null && (!Number.isFinite(headersTimeout) || headersTimeout < 0)) { - throw new InvalidArgumentError('invalid headersTimeout') + /* eslint-enable camelcase */ } + }) + } - if (bodyTimeout != null && (!Number.isFinite(bodyTimeout) || bodyTimeout < 0)) { - throw new InvalidArgumentError('invalid bodyTimeout') - } + let llhttpInstance = null; + let llhttpPromise = lazyllhttp(); + llhttpPromise.catch(); - if (reset != null && typeof reset !== 'boolean') { - throw new InvalidArgumentError('invalid reset') - } + let currentParser = null; + let currentBufferRef = null; + let currentBufferSize = 0; + let currentBufferPtr = null; - if (expectContinue != null && typeof expectContinue !== 'boolean') { - throw new InvalidArgumentError('invalid expectContinue') - } + const USE_NATIVE_TIMER = 0; + const USE_FAST_TIMER = 1; - this.headersTimeout = headersTimeout; + // Use fast timers for headers and body to take eventual event loop + // latency into account. + const TIMEOUT_HEADERS = 2 | USE_FAST_TIMER; + const TIMEOUT_BODY = 4 | USE_FAST_TIMER; - this.bodyTimeout = bodyTimeout; + // Use native timers to ignore event loop latency for keep-alive + // handling. + const TIMEOUT_KEEP_ALIVE = 8 | USE_NATIVE_TIMER; - this.throwOnError = throwOnError === true; + class Parser { + constructor (client, socket, { exports: exports$1 }) { + assert(Number.isFinite(client[kMaxHeadersSize]) && client[kMaxHeadersSize] > 0); - this.method = method; + this.llhttp = exports$1; + 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.abort = null; + this.bytesRead = 0; - if (body == null) { - this.body = null; - } else if (util.isStream(body)) { - this.body = body; + this.keepAlive = ''; + this.contentLength = ''; + this.connection = ''; + this.maxResponseSize = client[kMaxResponseSize]; + } - const rState = this.body._readableState; - if (!rState || !rState.autoDestroy) { - this.endHandler = function autoDestroy () { - util.destroy(this); - }; - this.body.on('end', this.endHandler); + setTimeout (delay, type) { + // If the existing timer and the new timer are of different timer type + // (fast or native) or have different delay, we need to clear the existing + // timer and set a new one. + if ( + delay !== this.timeoutValue || + (type & USE_FAST_TIMER) ^ (this.timeoutType & USE_FAST_TIMER) + ) { + // If a timeout is already set, clear it with clearTimeout of the fast + // timer implementation, as it can clear fast and native timers. + if (this.timeout) { + timers.clearTimeout(this.timeout); + this.timeout = null; } - this.errorHandler = err => { - if (this.abort) { - this.abort(err); + if (delay) { + if (type & USE_FAST_TIMER) { + this.timeout = timers.setFastTimeout(onParserTimeout, delay, new WeakRef(this)); } else { - this.error = err; + this.timeout = setTimeout(onParserTimeout, delay, new WeakRef(this)); + this.timeout.unref(); } - }; - this.body.on('error', this.errorHandler); - } else if (util.isBuffer(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 (util.isFormDataLike(body) || util.isIterable(body) || util.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 ? util.buildURL(path, query) : path; + this.timeoutValue = delay; + } else if (this.timeout) { + // istanbul ignore else: only for jest + if (this.timeout.refresh) { + this.timeout.refresh(); + } + } - this.origin = origin; + this.timeoutType = type; + } - this.idempotent = idempotent == null - ? method === 'HEAD' || method === 'GET' - : idempotent; + resume () { + if (this.socket.destroyed || !this.paused) { + return + } - this.blocking = blocking == null ? false : blocking; + assert(this.ptr != null); + assert(currentParser == null); - this.reset = reset == null ? null : reset; + this.llhttp.llhttp_resume(this.ptr); - this.host = null; + assert(this.timeoutType === TIMEOUT_BODY); + if (this.timeout) { + // istanbul ignore else: only for jest + if (this.timeout.refresh) { + this.timeout.refresh(); + } + } - this.contentLength = null; + this.paused = false; + this.execute(this.socket.read() || EMPTY_BUF); // Flush parser. + this.readMore(); + } - this.contentType = null; + readMore () { + while (!this.paused && this.ptr) { + const chunk = this.socket.read(); + if (chunk === null) { + break + } + this.execute(chunk); + } + } - this.headers = ''; + execute (data) { + assert(this.ptr != null); + assert(currentParser == null); + assert(!this.paused); - // Only for H2 - this.expectContinue = expectContinue != null ? expectContinue : false; + const { socket, llhttp } = this; - 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') { - const keys = Object.keys(headers); - for (let i = 0; i < keys.length; i++) { - const key = keys[i]; - processHeader(this, key, headers[key]); + if (data.length > currentBufferSize) { + if (currentBufferPtr) { + llhttp.free(currentBufferPtr); } - } else if (headers != null) { - throw new InvalidArgumentError('headers must be an object or an array') + currentBufferSize = Math.ceil(data.length / 4096) * 4096; + currentBufferPtr = llhttp.malloc(currentBufferSize); } - if (util.isFormDataLike(this.body)) { - if (util.nodeMajor < 16 || (util.nodeMajor === 16 && util.nodeMinor < 8)) { - throw new InvalidArgumentError('Form-Data bodies are only supported in node v16.8 and newer.') - } + new Uint8Array(llhttp.memory.buffer, currentBufferPtr, currentBufferSize).set(data); + + // Call `execute` on the wasm parser. + // We pass the `llhttp_parser` pointer address, the pointer address of buffer view data, + // and finally the length of bytes to parse. + // The return value is an error code or `constants.ERROR.OK`. + try { + let ret; - if (!extractBody) { - extractBody = requireBody().extractBody; + try { + currentBufferRef = data; + currentParser = this; + ret = llhttp.llhttp_execute(this.ptr, currentBufferPtr, data.length); + /* eslint-disable-next-line no-useless-catch */ + } catch (err) { + /* istanbul ignore next: difficult to make a test case for */ + throw err + } finally { + currentParser = null; + currentBufferRef = null; } - const [bodyStream, contentType] = extractBody(body); - if (this.contentType == null) { - this.contentType = contentType; - this.headers += `content-type: ${contentType}\r\n`; + const offset = llhttp.llhttp_get_error_pos(this.ptr) - currentBufferPtr; + + if (ret === constants.ERROR.PAUSED_UPGRADE) { + this.onUpgrade(data.slice(offset)); + } else if (ret === constants.ERROR.PAUSED) { + this.paused = true; + socket.unshift(data.slice(offset)); + } else if (ret !== constants.ERROR.OK) { + const ptr = llhttp.llhttp_get_error_reason(this.ptr); + let message = ''; + /* istanbul ignore else: difficult to make a test case for */ + 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() + + ')'; + } + throw new HTTPParserError(message, constants.ERROR[ret], data.slice(offset)) } - this.body = bodyStream.stream; - this.contentLength = bodyStream.length; - } else if (util.isBlobLike(body) && this.contentType == null && body.type) { - this.contentType = body.type; - this.headers += `content-type: ${body.type}\r\n`; + } catch (err) { + util.destroy(socket, err); } + } - util.validateHandler(handler, method, upgrade); + destroy () { + assert(this.ptr != null); + assert(currentParser == null); - this.servername = util.getServerName(this.host); + this.llhttp.llhttp_free(this.ptr); + this.ptr = null; - this[kHandler] = handler; + this.timeout && timers.clearTimeout(this.timeout); + this.timeout = null; + this.timeoutValue = null; + this.timeoutType = null; - if (channels.create.hasSubscribers) { - channels.create.publish({ request: this }); - } + this.paused = false; } - onBodySent (chunk) { - if (this[kHandler].onBodySent) { - try { - return this[kHandler].onBodySent(chunk) - } catch (err) { - this.abort(err); - } - } + onStatus (buf) { + this.statusText = buf.toString(); } - onRequestSent () { - if (channels.bodySent.hasSubscribers) { - channels.bodySent.publish({ request: this }); + onMessageBegin () { + const { socket, client } = this; + + /* istanbul ignore next: difficult to make a test case for */ + if (socket.destroyed) { + return -1 } - if (this[kHandler].onRequestSent) { - try { - return this[kHandler].onRequestSent() - } catch (err) { - this.abort(err); - } + const request = client[kQueue][client[kRunningIdx]]; + if (!request) { + return -1 } + request.onResponseStarted(); } - onConnect (abort) { - assert(!this.aborted); - assert(!this.completed); + onHeaderField (buf) { + const len = this.headers.length; - if (this.error) { - abort(this.error); + if ((len & 1) === 0) { + this.headers.push(buf); } else { - this.abort = abort; - return this[kHandler].onConnect(abort) + this.headers[len - 1] = Buffer.concat([this.headers[len - 1], buf]); } + + this.trackHeader(buf.length); } - onHeaders (statusCode, headers, resume, statusText) { - assert(!this.aborted); - assert(!this.completed); + onHeaderValue (buf) { + let len = this.headers.length; - if (channels.headers.hasSubscribers) { - channels.headers.publish({ request: this, response: { statusCode, headers, statusText } }); + if ((len & 1) === 1) { + this.headers.push(buf); + len += 1; + } else { + this.headers[len - 1] = Buffer.concat([this.headers[len - 1], buf]); } - try { - return this[kHandler].onHeaders(statusCode, headers, resume, statusText) - } catch (err) { - this.abort(err); + 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(); } - } - onData (chunk) { - assert(!this.aborted); - assert(!this.completed); + this.trackHeader(buf.length); + } - try { - return this[kHandler].onData(chunk) - } catch (err) { - this.abort(err); - return false + trackHeader (len) { + this.headersSize += len; + if (this.headersSize >= this.headersMaxSize) { + util.destroy(this.socket, new HeadersOverflowError()); } } - onUpgrade (statusCode, headers, socket) { - assert(!this.aborted); - assert(!this.completed); + onUpgrade (head) { + const { upgrade, client, socket, headers, statusCode } = this; - return this[kHandler].onUpgrade(statusCode, headers, socket) - } + assert(upgrade); + assert(client[kSocket] === socket); + assert(!socket.destroyed); + assert(!this.paused); + assert((headers.length & 1) === 0); - onComplete (trailers) { - this.onFinally(); + const request = client[kQueue][client[kRunningIdx]]; + assert(request); + assert(request.upgrade || request.method === 'CONNECT'); - assert(!this.aborted); + this.statusCode = null; + this.statusText = ''; + this.shouldKeepAlive = null; - this.completed = true; - if (channels.trailers.hasSubscribers) { - channels.trailers.publish({ request: this, trailers }); - } + this.headers = []; + this.headersSize = 0; + + socket.unshift(head); + + socket[kParser].destroy(); + socket[kParser] = null; + + socket[kClient] = null; + socket[kError] = null; + + removeAllListeners(socket); + + client[kSocket] = null; + client[kHTTPContext] = null; // TODO (fix): This is hacky... + client[kQueue][client[kRunningIdx]++] = null; + client.emit('disconnect', client[kUrl], [client], new InformationalError('upgrade')); try { - return this[kHandler].onComplete(trailers) + request.onUpgrade(statusCode, headers, socket); } catch (err) { - // TODO (fix): This might be a bad idea? - this.onError(err); + util.destroy(socket, err); } + + client[kResume](); } - onError (error) { - this.onFinally(); + onHeadersComplete (statusCode, upgrade, shouldKeepAlive) { + const { client, socket, headers, statusText } = this; - if (channels.error.hasSubscribers) { - channels.error.publish({ request: this, error }); + /* istanbul ignore next: difficult to make a test case for */ + if (socket.destroyed) { + return -1 } - if (this.aborted) { - return + const request = client[kQueue][client[kRunningIdx]]; + + /* istanbul ignore next: difficult to make a test case for */ + if (!request) { + return -1 } - this.aborted = true; - return this[kHandler].onError(error) - } + assert(!this.upgrade); + assert(this.statusCode < 200); - onFinally () { - if (this.errorHandler) { - this.body.off('error', this.errorHandler); - this.errorHandler = null; + if (statusCode === 100) { + util.destroy(socket, new SocketError('bad response', util.getSocketInfo(socket))); + return -1 } - if (this.endHandler) { - this.body.off('end', this.endHandler); - this.endHandler = null; + /* this can only happen if server is misbehaving */ + if (upgrade && !request.upgrade) { + util.destroy(socket, new SocketError('bad upgrade', util.getSocketInfo(socket))); + return -1 } - } - // TODO: adjust to support H2 - addHeader (key, value) { - processHeader(this, key, value); - return this - } + assert(this.timeoutType === TIMEOUT_HEADERS); - static [kHTTP1BuildRequest] (origin, opts, handler) { - // TODO: Migrate header parsing here, to make Requests - // HTTP agnostic - return new Request(origin, opts, handler) - } + 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') + ); - static [kHTTP2BuildRequest] (origin, opts, handler) { - const headers = opts.headers; - opts = { ...opts, headers: null }; + if (this.statusCode >= 200) { + const bodyTimeout = request.bodyTimeout != null + ? request.bodyTimeout + : client[kBodyTimeout]; + this.setTimeout(bodyTimeout, TIMEOUT_BODY); + } else if (this.timeout) { + // istanbul ignore else: only for jest + if (this.timeout.refresh) { + this.timeout.refresh(); + } + } - const request = new Request(origin, opts, handler); + if (request.method === 'CONNECT') { + assert(client[kRunning] === 1); + this.upgrade = true; + return 2 + } - request.headers = {}; + if (upgrade) { + assert(client[kRunning] === 1); + this.upgrade = true; + return 2 + } - 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(request, headers[i], headers[i + 1], true); - } - } else if (headers && typeof headers === 'object') { - const keys = Object.keys(headers); - for (let i = 0; i < keys.length; i++) { - const key = keys[i]; - processHeader(request, key, headers[key], true); + 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 if (headers != null) { - throw new InvalidArgumentError('headers must be an object or an array') + } else { + // Stop more requests from being dispatched. + socket[kReset] = true; } - return request - } + const pause = request.onHeaders(statusCode, headers, this.resume, statusText) === false; - static [kHTTP2CopyHeaders] (raw) { - const rawHeaders = raw.split('\r\n'); - const headers = {}; + if (request.aborted) { + return -1 + } - for (const header of rawHeaders) { - const [key, value] = header.split(': '); + if (request.method === 'HEAD') { + return 1 + } - if (value == null || value.length === 0) continue + if (statusCode < 200) { + return 1 + } - if (headers[key]) headers[key] += `,${value}`; - else headers[key] = value; + if (socket[kBlocking]) { + socket[kBlocking] = false; + client[kResume](); } - return headers + return pause ? constants.ERROR.PAUSED : 0 } - } - function processHeaderValue (key, val, skipAppend) { - if (val && typeof val === 'object') { - throw new InvalidArgumentError(`invalid ${key} header`) - } + onBody (buf) { + const { client, socket, statusCode, maxResponseSize } = this; - val = val != null ? `${val}` : ''; + if (socket.destroyed) { + return -1 + } - if (headerCharRegex.exec(val) !== null) { - throw new InvalidArgumentError(`invalid ${key} header`) - } + const request = client[kQueue][client[kRunningIdx]]; + assert(request); - return skipAppend ? val : `${key}: ${val}\r\n` - } + assert(this.timeoutType === TIMEOUT_BODY); + if (this.timeout) { + // istanbul ignore else: only for jest + if (this.timeout.refresh) { + this.timeout.refresh(); + } + } - function processHeader (request, key, val, skipAppend = false) { - if (val && (typeof val === 'object' && !Array.isArray(val))) { - throw new InvalidArgumentError(`invalid ${key} header`) - } else if (val === undefined) { - return - } + assert(statusCode >= 200); - if ( - request.host === null && - key.length === 4 && - key.toLowerCase() === 'host' - ) { - if (headerCharRegex.exec(val) !== null) { - throw new InvalidArgumentError(`invalid ${key} header`) - } - // Consumed by Client - request.host = val; - } else if ( - request.contentLength === null && - key.length === 14 && - key.toLowerCase() === 'content-length' - ) { - request.contentLength = parseInt(val, 10); - if (!Number.isFinite(request.contentLength)) { - throw new InvalidArgumentError('invalid content-length header') - } - } else if ( - request.contentType === null && - key.length === 12 && - key.toLowerCase() === 'content-type' - ) { - request.contentType = val; - if (skipAppend) request.headers[key] = processHeaderValue(key, val, skipAppend); - else request.headers += processHeaderValue(key, val); - } else if ( - key.length === 17 && - key.toLowerCase() === 'transfer-encoding' - ) { - throw new InvalidArgumentError('invalid transfer-encoding header') - } else if ( - key.length === 10 && - key.toLowerCase() === 'connection' - ) { - const value = typeof val === 'string' ? val.toLowerCase() : null; - if (value !== 'close' && value !== 'keep-alive') { - throw new InvalidArgumentError('invalid connection header') - } else if (value === 'close') { - request.reset = true; + if (maxResponseSize > -1 && this.bytesRead + buf.length > maxResponseSize) { + util.destroy(socket, new ResponseExceededMaxSizeError()); + return -1 } - } else if ( - key.length === 10 && - key.toLowerCase() === 'keep-alive' - ) { - throw new InvalidArgumentError('invalid keep-alive header') - } else if ( - key.length === 7 && - key.toLowerCase() === 'upgrade' - ) { - throw new InvalidArgumentError('invalid upgrade header') - } else if ( - key.length === 6 && - key.toLowerCase() === 'expect' - ) { - throw new NotSupportedError('expect header not supported') - } else if (tokenRegExp.exec(key) === null) { - throw new InvalidArgumentError('invalid header key') - } else { - if (Array.isArray(val)) { - for (let i = 0; i < val.length; i++) { - if (skipAppend) { - if (request.headers[key]) request.headers[key] += `,${processHeaderValue(key, val[i], skipAppend)}`; - else request.headers[key] = processHeaderValue(key, val[i], skipAppend); - } else { - request.headers += processHeaderValue(key, val[i]); - } - } - } else { - if (skipAppend) request.headers[key] = processHeaderValue(key, val, skipAppend); - else request.headers += processHeaderValue(key, val); + + this.bytesRead += buf.length; + + if (request.onData(buf) === false) { + return constants.ERROR.PAUSED } } - } - request$3 = Request; - return request$3; -} + onMessageComplete () { + const { client, socket, statusCode, upgrade, headers, contentLength, bytesRead, shouldKeepAlive } = this; -var dispatcher; -var hasRequiredDispatcher; + if (socket.destroyed && (!statusCode || shouldKeepAlive)) { + return -1 + } -function requireDispatcher () { - if (hasRequiredDispatcher) return dispatcher; - hasRequiredDispatcher = 1; + if (upgrade) { + return + } - const EventEmitter = require$$4$1; + assert(statusCode >= 100); + assert((this.headers.length & 1) === 0); - class Dispatcher extends EventEmitter { - dispatch () { - throw new Error('not implemented') - } + const request = client[kQueue][client[kRunningIdx]]; + assert(request); - close () { - throw new Error('not implemented') - } + this.statusCode = null; + this.statusText = ''; + this.bytesRead = 0; + this.contentLength = ''; + this.keepAlive = ''; + this.connection = ''; - destroy () { - throw new Error('not implemented') - } - } + this.headers = []; + this.headersSize = 0; - dispatcher = Dispatcher; - return dispatcher; -} + if (statusCode < 200) { + return + } -var dispatcherBase; -var hasRequiredDispatcherBase; + /* istanbul ignore next: should be handled by llhttp? */ + if (request.method !== 'HEAD' && contentLength && bytesRead !== parseInt(contentLength, 10)) { + util.destroy(socket, new ResponseContentLengthMismatchError()); + return -1 + } -function requireDispatcherBase () { - if (hasRequiredDispatcherBase) return dispatcherBase; - hasRequiredDispatcherBase = 1; + request.onComplete(headers); - const Dispatcher = requireDispatcher(); - const { - ClientDestroyedError, - ClientClosedError, - InvalidArgumentError - } = requireErrors(); - const { kDestroy, kClose, kDispatch, kInterceptors } = requireSymbols$4(); + client[kQueue][client[kRunningIdx]++] = null; - const kDestroyed = Symbol('destroyed'); - const kClosed = Symbol('closed'); - const kOnDestroyed = Symbol('onDestroyed'); - const kOnClosed = Symbol('onClosed'); - const kInterceptedDispatch = Symbol('Intercepted Dispatch'); + if (socket[kWriting]) { + assert(client[kRunning] === 0); + // Response completed before request. + 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) { + // Destroy socket once all requests have completed. + // The request at the tail of the pipeline is the one + // that requested reset and no further requests should + // have been queued since then. + util.destroy(socket, new InformationalError('reset')); + return constants.ERROR.PAUSED + } else if (client[kPipelining] == null || client[kPipelining] === 1) { + // We must wait a full event loop cycle to reuse this socket to make sure + // that non-spec compliant servers are not closing the connection even if they + // said they won't. + setImmediate(() => client[kResume]()); + } else { + client[kResume](); + } + } + } - class DispatcherBase extends Dispatcher { - constructor () { - super(); + function onParserTimeout (parser) { + const { socket, timeoutType, client, paused } = parser.deref(); - this[kDestroyed] = false; - this[kOnDestroyed] = null; - this[kClosed] = false; - this[kOnClosed] = []; + /* istanbul ignore else */ + 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')); } + } - get destroyed () { - return this[kDestroyed] - } + async function connectH1 (client, socket) { + client[kSocket] = socket; - get closed () { - return this[kClosed] + if (!llhttpInstance) { + llhttpInstance = await llhttpPromise; + llhttpPromise = null; } - get interceptors () { - return this[kInterceptors] - } + socket[kNoRef] = false; + socket[kWriting] = false; + socket[kReset] = false; + socket[kBlocking] = false; + socket[kParser] = new Parser(client, socket, llhttpInstance); - 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') - } - } - } + addListener(socket, 'error', function (err) { + assert(err.code !== 'ERR_TLS_CERT_ALTNAME_INVALID'); - this[kInterceptors] = newInterceptors; - } + const parser = this[kParser]; - close (callback) { - if (callback === undefined) { - return new Promise((resolve, reject) => { - this.close((err, data) => { - return err ? reject(err) : resolve(data) - }); - }) + // On Mac OS, we get an ECONNRESET even if there is a full body to be forwarded + // to the user. + if (err.code === 'ECONNRESET' && parser.statusCode && !parser.shouldKeepAlive) { + // We treat all incoming data so for as a valid response. + parser.onMessageComplete(); + return } - if (typeof callback !== 'function') { - throw new InvalidArgumentError('invalid callback') - } + this[kError] = err; - if (this[kDestroyed]) { - queueMicrotask(() => callback(new ClientDestroyedError(), null)); - return + 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 (this[kClosed]) { - if (this[kOnClosed]) { - this[kOnClosed].push(callback); - } else { - queueMicrotask(() => callback(null, null)); - } + if (parser.statusCode && !parser.shouldKeepAlive) { + // We treat all incoming data so far as a valid response. + parser.onMessageComplete(); return } - this[kClosed] = true; - this[kOnClosed].push(callback); + util.destroy(this, new SocketError('other side closed', util.getSocketInfo(this))); + }); + addListener(socket, 'close', function () { + const client = this[kClient]; + const parser = this[kParser]; - const onClosed = () => { - const callbacks = this[kOnClosed]; - this[kOnClosed] = null; - for (let i = 0; i < callbacks.length; i++) { - callbacks[i](null, null); + if (parser) { + if (!this[kError] && parser.statusCode && !parser.shouldKeepAlive) { + // We treat all incoming data so far as a valid response. + parser.onMessageComplete(); } - }; - - // Should not error. - this[kClose]() - .then(() => this.destroy()) - .then(() => { - queueMicrotask(onClosed); - }); - } - destroy (err, callback) { - if (typeof err === 'function') { - callback = err; - err = null; + this[kParser].destroy(); + this[kParser] = null; } - if (callback === undefined) { - return new Promise((resolve, reject) => { - this.destroy(err, (err, data) => { - return err ? /* istanbul ignore next: should never error */ reject(err) : resolve(data) - }); - }) - } + const err = this[kError] || new SocketError('closed', util.getSocketInfo(this)); - if (typeof callback !== 'function') { - throw new InvalidArgumentError('invalid callback') - } + client[kSocket] = null; + client[kHTTPContext] = null; // TODO (fix): This is hacky... - if (this[kDestroyed]) { - if (this[kOnDestroyed]) { - this[kOnDestroyed].push(callback); - } else { - queueMicrotask(() => callback(null, null)); + if (client.destroyed) { + assert(client[kPending] === 0); + + // Fail entire queue. + const requests = client[kQueue].splice(client[kRunningIdx]); + for (let i = 0; i < requests.length; i++) { + const request = requests[i]; + util.errorRequest(client, request, err); } - return - } + } else if (client[kRunning] > 0 && err.code !== 'UND_ERR_INFO') { + // Fail head of pipeline. + const request = client[kQueue][client[kRunningIdx]]; + client[kQueue][client[kRunningIdx]++] = null; - if (!err) { - err = new ClientDestroyedError(); + util.errorRequest(client, request, err); } - 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); - } - }; + client[kPendingIdx] = client[kRunningIdx]; - // Should not error. - this[kDestroy](err).then(() => { - queueMicrotask(onDestroyed); - }); - } + assert(client[kRunning] === 0); - [kInterceptedDispatch] (opts, handler) { - if (!this[kInterceptors] || this[kInterceptors].length === 0) { - this[kInterceptedDispatch] = this[kDispatch]; - return this[kDispatch](opts, handler) - } + client.emit('disconnect', client[kUrl], [client], err); - 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) - } + client[kResume](); + }); - dispatch (opts, handler) { - if (!handler || typeof handler !== 'object') { - throw new InvalidArgumentError('handler must be an object') - } + let closed = false; + socket.on('close', () => { + closed = true; + }); - try { - if (!opts || typeof opts !== 'object') { - throw new InvalidArgumentError('opts must be an object.') + 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); } - - if (this[kDestroyed] || this[kOnDestroyed]) { - throw new ClientDestroyedError() + }, + get destroyed () { + return socket.destroyed + }, + busy (request) { + if (socket[kWriting] || socket[kReset] || socket[kBlocking]) { + return true } - if (this[kClosed]) { - throw new ClientClosedError() - } + if (request) { + if (client[kRunning] > 0 && !request.idempotent) { + // Non-idempotent request cannot be retried. + // Ensure that no other requests are inflight and + // could cause failure. + return true + } - return this[kInterceptedDispatch](opts, handler) - } catch (err) { - if (typeof handler.onError !== 'function') { - throw new InvalidArgumentError('invalid onError method') - } + if (client[kRunning] > 0 && (request.upgrade || request.method === 'CONNECT')) { + // Don't dispatch an upgrade until all preceding requests have completed. + // A misbehaving server might upgrade the connection before all pipelined + // request has completed. + return true + } - handler.onError(err); + if (client[kRunning] > 0 && util.bodyLength(request.body) !== 0 && + (util.isStream(request.body) || util.isAsyncIterable(request.body) || util.isFormDataLike(request.body))) { + // Request with stream or iterator body can error while other requests + // are inflight and indirectly error those as well. + // Ensure this doesn't happen by waiting for inflight + // to complete before dispatching. + + // Request with stream or iterator body cannot be retried. + // Ensure that no other requests are inflight and + // could cause failure. + return true + } + } return false } } } - dispatcherBase = DispatcherBase; - return dispatcherBase; -} - -var connect; -var hasRequiredConnect; + function resumeH1 (client) { + const socket = client[kSocket]; -function requireConnect () { - if (hasRequiredConnect) return connect; - hasRequiredConnect = 1; + 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; + } - const net = require$$0$4; - const assert = require$$0$3; - const util = requireUtil$7(); - const { InvalidArgumentError, ConnectTimeoutError } = requireErrors(); + 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); + } + } + } + } - let tls; // include tls conditionally since it is not always available + // https://www.rfc-editor.org/rfc/rfc7230#section-3.3.2 + function shouldSendContentLength (method) { + return method !== 'GET' && method !== 'HEAD' && method !== 'OPTIONS' && method !== 'TRACE' && method !== 'CONNECT' + } - // TODO: session re-use does not wait for the first - // connection to resolve the session and might therefore - // resolve the same servername multiple times even when - // re-use is enabled. + function writeH1 (client, request) { + const { method, path, host, upgrade, blocking, reset } = request; - let SessionCache; - // FIXME: remove workaround when the Node bug is fixed - // https://github.com/nodejs/node/issues/49344#issuecomment-1741776308 - if (commonjsGlobal.FinalizationRegistry && !process.env.NODE_V8_COVERAGE) { - SessionCache = class WeakSessionCache { - constructor (maxCachedSessions) { - this._maxCachedSessions = maxCachedSessions; - this._sessionCache = new Map(); - this._sessionRegistry = new commonjsGlobal.FinalizationRegistry((key) => { - if (this._sessionCache.size < this._maxCachedSessions) { - return - } + let { body, headers, contentLength } = request; - const ref = this._sessionCache.get(key); - if (ref !== undefined && ref.deref() === undefined) { - this._sessionCache.delete(key); - } - }); - } + // https://tools.ietf.org/html/rfc7231#section-4.3.1 + // https://tools.ietf.org/html/rfc7231#section-4.3.2 + // https://tools.ietf.org/html/rfc7231#section-4.3.5 - get (sessionKey) { - const ref = this._sessionCache.get(sessionKey); - return ref ? ref.deref() : null - } + // Sending a payload body on a request that does not + // expect it can cause undefined behavior on some + // servers and corrupt connection state. Do not + // re-use the connection for further requests. - set (sessionKey, session) { - if (this._maxCachedSessions === 0) { - return - } + const expectsPayload = ( + method === 'PUT' || + method === 'POST' || + method === 'PATCH' || + method === 'QUERY' || + method === 'PROPFIND' || + method === 'PROPPATCH' + ); - this._sessionCache.set(sessionKey, new WeakRef(session)); - this._sessionRegistry.register(session, sessionKey); - } - }; - } else { - SessionCache = class SimpleSessionCache { - constructor (maxCachedSessions) { - this._maxCachedSessions = maxCachedSessions; - this._sessionCache = new Map(); + if (util.isFormDataLike(body)) { + if (!extractBody) { + extractBody = requireBody().extractBody; } - get (sessionKey) { - return this._sessionCache.get(sessionKey) + 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); + } - set (sessionKey, session) { - if (this._maxCachedSessions === 0) { - return - } + if (body && typeof body.read === 'function') { + // Try to read EOF in order to get length. + body.read(0); + } - if (this._sessionCache.size >= this._maxCachedSessions) { - // remove the oldest session - const { value: oldestKey } = this._sessionCache.keys().next(); - this._sessionCache.delete(oldestKey); - } + const bodyLength = util.bodyLength(body); - this._sessionCache.set(sessionKey, session); - } - }; - } + contentLength = bodyLength ?? contentLength; - function buildConnector ({ allowH2, maxCachedSessions, socketPath, timeout, ...opts }) { - if (maxCachedSessions != null && (!Number.isInteger(maxCachedSessions) || maxCachedSessions < 0)) { - throw new InvalidArgumentError('maxCachedSessions must be a positive integer or zero') + if (contentLength === null) { + contentLength = request.contentLength; } - const options = { path: socketPath, ...opts }; - const sessionCache = new SessionCache(maxCachedSessions == null ? 100 : maxCachedSessions); - timeout = timeout == null ? 10e3 : timeout; - allowH2 = allowH2 != null ? allowH2 : false; - return function connect ({ hostname, host, protocol, port, servername, localAddress, httpSocket }, callback) { - let socket; - if (protocol === 'https:') { - if (!tls) { - tls = require$$1$1; - } - servername = servername || options.servername || util.getServerName(host) || null; - - const sessionKey = servername || hostname; - const session = sessionCache.get(sessionKey) || null; - - assert(sessionKey); + if (contentLength === 0 && !expectsPayload) { + // https://tools.ietf.org/html/rfc7230#section-3.3.2 + // A user agent SHOULD NOT send a Content-Length header field when + // the request message does not contain a payload body and the method + // semantics do not anticipate such a body. - 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: port || 443, - host: hostname - }); + contentLength = null; + } - socket - .on('session', function (session) { - // TODO (fix): Can a session become invalid once established? Don't think so? - sessionCache.set(sessionKey, session); - }); - } else { - assert(!httpSocket, 'httpSocket can only be sent on TLS update'); - socket = net.connect({ - highWaterMark: 64 * 1024, // Same as nodejs fs streams. - ...options, - localAddress, - port: port || 80, - host: hostname - }); + // https://github.com/nodejs/undici/issues/2046 + // A user agent may send a Content-Length header with 0 value, this should be allowed. + if (shouldSendContentLength(method) && contentLength > 0 && request.contentLength !== null && request.contentLength !== contentLength) { + if (client[kStrictContentLength]) { + util.errorRequest(client, request, new RequestContentLengthMismatchError()); + return false } - // Set TCP keep alive options on the socket here instead of in connect() for the case of assigning the socket - if (options.keepAlive == null || options.keepAlive) { - const keepAliveInitialDelay = options.keepAliveInitialDelay === undefined ? 60e3 : options.keepAliveInitialDelay; - socket.setKeepAlive(true, keepAliveInitialDelay); - } + process.emitWarning(new RequestContentLengthMismatchError()); + } - const cancelTimeout = setupTimeout(() => onConnectTimeout(socket), timeout); + const socket = client[kSocket]; - socket - .setNoDelay(true) - .once(protocol === 'https:' ? 'secureConnect' : 'connect', function () { - cancelTimeout(); + const abort = (err) => { + if (request.aborted || request.completed) { + return + } - if (callback) { - const cb = callback; - callback = null; - cb(null, this); - } - }) - .on('error', function (err) { - cancelTimeout(); + util.errorRequest(client, request, err || new RequestAbortedError()); - if (callback) { - const cb = callback; - callback = null; - cb(err); - } - }); + util.destroy(body); + util.destroy(socket, new InformationalError('aborted')); + }; - return socket + try { + request.onConnect(abort); + } catch (err) { + util.errorRequest(client, request, err); } - } - function setupTimeout (onConnectTimeout, timeout) { - if (!timeout) { - return () => {} + if (request.aborted) { + return false } - let s1 = null; - let s2 = null; - const timeoutId = setTimeout(() => { - // setImmediate is added to make sure that we priotorise socket error events over timeouts - s1 = setImmediate(() => { - if (process.platform === 'win32') { - // Windows needs an extra setImmediate probably due to implementation differences in the socket logic - s2 = setImmediate(() => onConnectTimeout()); - } else { - onConnectTimeout(); - } - }); - }, timeout); - return () => { - clearTimeout(timeoutId); - clearImmediate(s1); - clearImmediate(s2); + if (method === 'HEAD') { + // https://github.com/mcollina/undici/issues/258 + // Close after a HEAD request to interop with misbehaving servers + // that may send a body in the response. + + socket[kReset] = true; } - } - function onConnectTimeout (socket) { - util.destroy(socket, new ConnectTimeoutError()); - } + if (upgrade || method === 'CONNECT') { + // On CONNECT or upgrade, block pipeline from dispatching further + // requests on this connection. - connect = buildConnector; - return connect; -} - -var constants$2 = {}; - -var utils$3 = {}; - -var hasRequiredUtils$3; - -function requireUtils$3 () { - if (hasRequiredUtils$3) return utils$3; - hasRequiredUtils$3 = 1; - Object.defineProperty(utils$3, "__esModule", { value: true }); - utils$3.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; - } - utils$3.enumToMap = enumToMap; - - return utils$3; -} - -var hasRequiredConstants$2; - -function requireConstants$2 () { - if (hasRequiredConstants$2) return constants$2; - hasRequiredConstants$2 = 1; - (function (exports$1) { - Object.defineProperty(exports$1, "__esModule", { value: true }); - exports$1.SPECIAL_HEADERS = exports$1.HEADER_STATE = exports$1.MINOR = exports$1.MAJOR = exports$1.CONNECTION_TOKEN_CHARS = exports$1.HEADER_CHARS = exports$1.TOKEN = exports$1.STRICT_TOKEN = exports$1.HEX = exports$1.URL_CHAR = exports$1.STRICT_URL_CHAR = exports$1.USERINFO_CHARS = exports$1.MARK = exports$1.ALPHANUM = exports$1.NUM = exports$1.HEX_MAP = exports$1.NUM_MAP = exports$1.ALPHA = exports$1.FINISH = exports$1.H_METHOD_MAP = exports$1.METHOD_MAP = exports$1.METHODS_RTSP = exports$1.METHODS_ICE = exports$1.METHODS_HTTP = exports$1.METHODS = exports$1.LENIENT_FLAGS = exports$1.FLAGS = exports$1.TYPE = exports$1.ERROR = void 0; - const utils_1 = requireUtils$3(); - (function (ERROR) { - ERROR[ERROR["OK"] = 0] = "OK"; - ERROR[ERROR["INTERNAL"] = 1] = "INTERNAL"; - ERROR[ERROR["STRICT"] = 2] = "STRICT"; - ERROR[ERROR["LF_EXPECTED"] = 3] = "LF_EXPECTED"; - ERROR[ERROR["UNEXPECTED_CONTENT_LENGTH"] = 4] = "UNEXPECTED_CONTENT_LENGTH"; - ERROR[ERROR["CLOSED_CONNECTION"] = 5] = "CLOSED_CONNECTION"; - ERROR[ERROR["INVALID_METHOD"] = 6] = "INVALID_METHOD"; - ERROR[ERROR["INVALID_URL"] = 7] = "INVALID_URL"; - ERROR[ERROR["INVALID_CONSTANT"] = 8] = "INVALID_CONSTANT"; - ERROR[ERROR["INVALID_VERSION"] = 9] = "INVALID_VERSION"; - ERROR[ERROR["INVALID_HEADER_TOKEN"] = 10] = "INVALID_HEADER_TOKEN"; - ERROR[ERROR["INVALID_CONTENT_LENGTH"] = 11] = "INVALID_CONTENT_LENGTH"; - ERROR[ERROR["INVALID_CHUNK_SIZE"] = 12] = "INVALID_CHUNK_SIZE"; - ERROR[ERROR["INVALID_STATUS"] = 13] = "INVALID_STATUS"; - ERROR[ERROR["INVALID_EOF_STATE"] = 14] = "INVALID_EOF_STATE"; - ERROR[ERROR["INVALID_TRANSFER_ENCODING"] = 15] = "INVALID_TRANSFER_ENCODING"; - ERROR[ERROR["CB_MESSAGE_BEGIN"] = 16] = "CB_MESSAGE_BEGIN"; - ERROR[ERROR["CB_HEADERS_COMPLETE"] = 17] = "CB_HEADERS_COMPLETE"; - ERROR[ERROR["CB_MESSAGE_COMPLETE"] = 18] = "CB_MESSAGE_COMPLETE"; - ERROR[ERROR["CB_CHUNK_HEADER"] = 19] = "CB_CHUNK_HEADER"; - ERROR[ERROR["CB_CHUNK_COMPLETE"] = 20] = "CB_CHUNK_COMPLETE"; - ERROR[ERROR["PAUSED"] = 21] = "PAUSED"; - ERROR[ERROR["PAUSED_UPGRADE"] = 22] = "PAUSED_UPGRADE"; - ERROR[ERROR["PAUSED_H2_UPGRADE"] = 23] = "PAUSED_H2_UPGRADE"; - ERROR[ERROR["USER"] = 24] = "USER"; - })(exports$1.ERROR || (exports$1.ERROR = {})); - (function (TYPE) { - TYPE[TYPE["BOTH"] = 0] = "BOTH"; - TYPE[TYPE["REQUEST"] = 1] = "REQUEST"; - TYPE[TYPE["RESPONSE"] = 2] = "RESPONSE"; - })(exports$1.TYPE || (exports$1.TYPE = {})); - (function (FLAGS) { - FLAGS[FLAGS["CONNECTION_KEEP_ALIVE"] = 1] = "CONNECTION_KEEP_ALIVE"; - FLAGS[FLAGS["CONNECTION_CLOSE"] = 2] = "CONNECTION_CLOSE"; - FLAGS[FLAGS["CONNECTION_UPGRADE"] = 4] = "CONNECTION_UPGRADE"; - FLAGS[FLAGS["CHUNKED"] = 8] = "CHUNKED"; - FLAGS[FLAGS["UPGRADE"] = 16] = "UPGRADE"; - FLAGS[FLAGS["CONTENT_LENGTH"] = 32] = "CONTENT_LENGTH"; - FLAGS[FLAGS["SKIPBODY"] = 64] = "SKIPBODY"; - FLAGS[FLAGS["TRAILING"] = 128] = "TRAILING"; - // 1 << 8 is unused - FLAGS[FLAGS["TRANSFER_ENCODING"] = 512] = "TRANSFER_ENCODING"; - })(exports$1.FLAGS || (exports$1.FLAGS = {})); - (function (LENIENT_FLAGS) { - LENIENT_FLAGS[LENIENT_FLAGS["HEADERS"] = 1] = "HEADERS"; - LENIENT_FLAGS[LENIENT_FLAGS["CHUNKED_LENGTH"] = 2] = "CHUNKED_LENGTH"; - LENIENT_FLAGS[LENIENT_FLAGS["KEEP_ALIVE"] = 4] = "KEEP_ALIVE"; - })(exports$1.LENIENT_FLAGS || (exports$1.LENIENT_FLAGS = {})); - var METHODS; - (function (METHODS) { - METHODS[METHODS["DELETE"] = 0] = "DELETE"; - METHODS[METHODS["GET"] = 1] = "GET"; - METHODS[METHODS["HEAD"] = 2] = "HEAD"; - METHODS[METHODS["POST"] = 3] = "POST"; - METHODS[METHODS["PUT"] = 4] = "PUT"; - /* pathological */ - METHODS[METHODS["CONNECT"] = 5] = "CONNECT"; - METHODS[METHODS["OPTIONS"] = 6] = "OPTIONS"; - METHODS[METHODS["TRACE"] = 7] = "TRACE"; - /* WebDAV */ - METHODS[METHODS["COPY"] = 8] = "COPY"; - METHODS[METHODS["LOCK"] = 9] = "LOCK"; - METHODS[METHODS["MKCOL"] = 10] = "MKCOL"; - METHODS[METHODS["MOVE"] = 11] = "MOVE"; - METHODS[METHODS["PROPFIND"] = 12] = "PROPFIND"; - METHODS[METHODS["PROPPATCH"] = 13] = "PROPPATCH"; - METHODS[METHODS["SEARCH"] = 14] = "SEARCH"; - METHODS[METHODS["UNLOCK"] = 15] = "UNLOCK"; - METHODS[METHODS["BIND"] = 16] = "BIND"; - METHODS[METHODS["REBIND"] = 17] = "REBIND"; - METHODS[METHODS["UNBIND"] = 18] = "UNBIND"; - METHODS[METHODS["ACL"] = 19] = "ACL"; - /* subversion */ - METHODS[METHODS["REPORT"] = 20] = "REPORT"; - METHODS[METHODS["MKACTIVITY"] = 21] = "MKACTIVITY"; - METHODS[METHODS["CHECKOUT"] = 22] = "CHECKOUT"; - METHODS[METHODS["MERGE"] = 23] = "MERGE"; - /* upnp */ - METHODS[METHODS["M-SEARCH"] = 24] = "M-SEARCH"; - METHODS[METHODS["NOTIFY"] = 25] = "NOTIFY"; - METHODS[METHODS["SUBSCRIBE"] = 26] = "SUBSCRIBE"; - METHODS[METHODS["UNSUBSCRIBE"] = 27] = "UNSUBSCRIBE"; - /* RFC-5789 */ - METHODS[METHODS["PATCH"] = 28] = "PATCH"; - METHODS[METHODS["PURGE"] = 29] = "PURGE"; - /* CalDAV */ - METHODS[METHODS["MKCALENDAR"] = 30] = "MKCALENDAR"; - /* RFC-2068, section 19.6.1.2 */ - METHODS[METHODS["LINK"] = 31] = "LINK"; - METHODS[METHODS["UNLINK"] = 32] = "UNLINK"; - /* icecast */ - METHODS[METHODS["SOURCE"] = 33] = "SOURCE"; - /* RFC-7540, section 11.6 */ - METHODS[METHODS["PRI"] = 34] = "PRI"; - /* RFC-2326 RTSP */ - METHODS[METHODS["DESCRIBE"] = 35] = "DESCRIBE"; - METHODS[METHODS["ANNOUNCE"] = 36] = "ANNOUNCE"; - METHODS[METHODS["SETUP"] = 37] = "SETUP"; - METHODS[METHODS["PLAY"] = 38] = "PLAY"; - METHODS[METHODS["PAUSE"] = 39] = "PAUSE"; - METHODS[METHODS["TEARDOWN"] = 40] = "TEARDOWN"; - METHODS[METHODS["GET_PARAMETER"] = 41] = "GET_PARAMETER"; - METHODS[METHODS["SET_PARAMETER"] = 42] = "SET_PARAMETER"; - METHODS[METHODS["REDIRECT"] = 43] = "REDIRECT"; - METHODS[METHODS["RECORD"] = 44] = "RECORD"; - /* RAOP */ - METHODS[METHODS["FLUSH"] = 45] = "FLUSH"; - })(METHODS = exports$1.METHODS || (exports$1.METHODS = {})); - exports$1.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$1.METHODS_ICE = [ - METHODS.SOURCE, - ]; - exports$1.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$1.METHOD_MAP = utils_1.enumToMap(METHODS); - exports$1.H_METHOD_MAP = {}; - Object.keys(exports$1.METHOD_MAP).forEach((key) => { - if (/^H/.test(key)) { - exports$1.H_METHOD_MAP[key] = exports$1.METHOD_MAP[key]; - } - }); - (function (FINISH) { - FINISH[FINISH["SAFE"] = 0] = "SAFE"; - FINISH[FINISH["SAFE_WITH_CB"] = 1] = "SAFE_WITH_CB"; - FINISH[FINISH["UNSAFE"] = 2] = "UNSAFE"; - })(exports$1.FINISH || (exports$1.FINISH = {})); - exports$1.ALPHA = []; - for (let i = 'A'.charCodeAt(0); i <= 'Z'.charCodeAt(0); i++) { - // Upper case - exports$1.ALPHA.push(String.fromCharCode(i)); - // Lower case - exports$1.ALPHA.push(String.fromCharCode(i + 0x20)); - } - exports$1.NUM_MAP = { - 0: 0, 1: 1, 2: 2, 3: 3, 4: 4, - 5: 5, 6: 6, 7: 7, 8: 8, 9: 9, - }; - exports$1.HEX_MAP = { - 0: 0, 1: 1, 2: 2, 3: 3, 4: 4, - 5: 5, 6: 6, 7: 7, 8: 8, 9: 9, - A: 0XA, B: 0XB, C: 0XC, D: 0XD, E: 0XE, F: 0XF, - a: 0xa, b: 0xb, c: 0xc, d: 0xd, e: 0xe, f: 0xf, - }; - exports$1.NUM = [ - '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', - ]; - exports$1.ALPHANUM = exports$1.ALPHA.concat(exports$1.NUM); - exports$1.MARK = ['-', '_', '.', '!', '~', '*', '\'', '(', ')']; - exports$1.USERINFO_CHARS = exports$1.ALPHANUM - .concat(exports$1.MARK) - .concat(['%', ';', ':', '&', '=', '+', '$', ',']); - // TODO(indutny): use RFC - exports$1.STRICT_URL_CHAR = [ - '!', '"', '$', '%', '&', '\'', - '(', ')', '*', '+', ',', '-', '.', '/', - ':', ';', '<', '=', '>', - '@', '[', '\\', ']', '^', '_', - '`', - '{', '|', '}', '~', - ].concat(exports$1.ALPHANUM); - exports$1.URL_CHAR = exports$1.STRICT_URL_CHAR - .concat(['\t', '\f']); - // All characters with 0x80 bit set to 1 - for (let i = 0x80; i <= 0xff; i++) { - exports$1.URL_CHAR.push(i); - } - exports$1.HEX = exports$1.NUM.concat(['a', 'b', 'c', 'd', 'e', 'f', 'A', 'B', 'C', 'D', 'E', 'F']); - /* Tokens as defined by rfc 2616. Also lowercases them. - * token = 1* - * separators = "(" | ")" | "<" | ">" | "@" - * | "," | ";" | ":" | "\" | <"> - * | "/" | "[" | "]" | "?" | "=" - * | "{" | "}" | SP | HT - */ - exports$1.STRICT_TOKEN = [ - '!', '#', '$', '%', '&', '\'', - '*', '+', '-', '.', - '^', '_', '`', - '|', '~', - ].concat(exports$1.ALPHANUM); - exports$1.TOKEN = exports$1.STRICT_TOKEN.concat([' ']); - /* - * Verify that a char is a valid visible (printable) US-ASCII - * character or %x80-FF - */ - exports$1.HEADER_CHARS = ['\t']; - for (let i = 32; i <= 255; i++) { - if (i !== 127) { - exports$1.HEADER_CHARS.push(i); - } - } - // ',' = \x44 - exports$1.CONNECTION_TOKEN_CHARS = exports$1.HEADER_CHARS.filter((c) => c !== 44); - exports$1.MAJOR = exports$1.NUM_MAP; - exports$1.MINOR = exports$1.MAJOR; - var HEADER_STATE; - (function (HEADER_STATE) { - HEADER_STATE[HEADER_STATE["GENERAL"] = 0] = "GENERAL"; - HEADER_STATE[HEADER_STATE["CONNECTION"] = 1] = "CONNECTION"; - HEADER_STATE[HEADER_STATE["CONTENT_LENGTH"] = 2] = "CONTENT_LENGTH"; - HEADER_STATE[HEADER_STATE["TRANSFER_ENCODING"] = 3] = "TRANSFER_ENCODING"; - HEADER_STATE[HEADER_STATE["UPGRADE"] = 4] = "UPGRADE"; - HEADER_STATE[HEADER_STATE["CONNECTION_KEEP_ALIVE"] = 5] = "CONNECTION_KEEP_ALIVE"; - HEADER_STATE[HEADER_STATE["CONNECTION_CLOSE"] = 6] = "CONNECTION_CLOSE"; - HEADER_STATE[HEADER_STATE["CONNECTION_UPGRADE"] = 7] = "CONNECTION_UPGRADE"; - HEADER_STATE[HEADER_STATE["TRANSFER_ENCODING_CHUNKED"] = 8] = "TRANSFER_ENCODING_CHUNKED"; - })(HEADER_STATE = exports$1.HEADER_STATE || (exports$1.HEADER_STATE = {})); - exports$1.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, - }; - - } (constants$2)); - return constants$2; -} - -var RedirectHandler_1; -var hasRequiredRedirectHandler; - -function requireRedirectHandler () { - if (hasRequiredRedirectHandler) return RedirectHandler_1; - hasRequiredRedirectHandler = 1; - - const util = requireUtil$7(); - const { kBodyUsed } = requireSymbols$4(); - const assert = require$$0$3; - const { InvalidArgumentError } = requireErrors(); - const EE = require$$4$1; - - const redirectableStatusCodes = [300, 301, 302, 303, 307, 308]; + socket[kReset] = true; + } - const kBody = Symbol('body'); + if (reset != null) { + socket[kReset] = reset; + } - class BodyAsyncIterable { - constructor (body) { - this[kBody] = body; - this[kBodyUsed] = false; + if (client[kMaxRequests] && socket[kCounter]++ >= client[kMaxRequests]) { + socket[kReset] = true; } - async * [Symbol.asyncIterator] () { - assert(!this[kBodyUsed], 'disturbed'); - this[kBodyUsed] = true; - yield * this[kBody]; + if (blocking) { + socket[kBlocking] = true; } - } - class RedirectHandler { - constructor (dispatch, maxRedirections, opts, handler) { - if (maxRedirections != null && (!Number.isInteger(maxRedirections) || maxRedirections < 0)) { - throw new InvalidArgumentError('maxRedirections must be a positive number') - } + let header = `${method} ${path} HTTP/1.1\r\n`; - util.validateHandler(handler, opts.method, opts.upgrade); + if (typeof host === 'string') { + header += `host: ${host}\r\n`; + } else { + header += client[kHostHeader]; + } - this.dispatch = dispatch; - this.location = null; - this.abort = null; - this.opts = { ...opts, maxRedirections: 0 }; // opts must be a copy - this.maxRedirections = maxRedirections; - this.handler = handler; - this.history = []; + if (upgrade) { + header += `connection: upgrade\r\nupgrade: ${upgrade}\r\n`; + } else if (client[kPipelining] && !socket[kReset]) { + header += 'connection: keep-alive\r\n'; + } else { + header += 'connection: close\r\n'; + } - if (util.isStream(this.opts.body)) { - // TODO (fix): Provide some way for the user to cache the file to e.g. /tmp - // so that it can be dispatched again? - // TODO (fix): Do we need 100-expect support to provide a way to do this properly? - if (util.bodyLength(this.opts.body) === 0) { - this.opts.body - .on('data', function () { - assert(false); - }); - } + if (Array.isArray(headers)) { + for (let n = 0; n < headers.length; n += 2) { + const key = headers[n + 0]; + const val = headers[n + 1]; - if (typeof this.opts.body.readableDidRead !== 'boolean') { - this.opts.body[kBodyUsed] = false; - EE.prototype.on.call(this.opts.body, 'data', function () { - this[kBodyUsed] = true; - }); + if (Array.isArray(val)) { + for (let i = 0; i < val.length; i++) { + header += `${key}: ${val[i]}\r\n`; + } + } else { + header += `${key}: ${val}\r\n`; } - } else if (this.opts.body && typeof this.opts.body.pipeTo === 'function') { - // TODO (fix): We can't access ReadableStream internal state - // to determine whether or not it has been disturbed. This is just - // a workaround. - 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) - ) { - // TODO: Should we allow re-using iterable if !this.opts.idempotent - // or through some other flag? - this.opts.body = new BodyAsyncIterable(this.opts.body); } } - onConnect (abort) { - this.abort = abort; - this.handler.onConnect(abort, { history: this.history }); + if (channels.sendHeaders.hasSubscribers) { + channels.sendHeaders.publish({ request, headers: header, socket }); } - onUpgrade (statusCode, headers, socket) { - this.handler.onUpgrade(statusCode, headers, socket); + /* istanbul ignore else: assertion */ + 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); } - onError (error) { - this.handler.onError(error); - } + return true + } - onHeaders (statusCode, headers, resume, statusText) { - this.location = this.history.length >= this.maxRedirections || util.isDisturbed(this.opts.body) - ? null - : parseLocation(statusCode, headers); + function writeStream (abort, body, client, request, socket, contentLength, header, expectsPayload) { + assert(contentLength !== 0 || client[kRunning] === 0, 'stream body cannot be pipelined'); - if (this.opts.origin) { - this.history.push(new URL(this.opts.path, this.opts.origin)); - } + let finished = false; - if (!this.location) { - return this.handler.onHeaders(statusCode, headers, resume, statusText) - } + const writer = new AsyncWriter({ abort, socket, request, contentLength, client, expectsPayload, header }); - const { origin, pathname, search } = util.parseURL(new URL(this.location, this.opts.origin && new URL(this.opts.path, this.opts.origin))); - const path = search ? `${pathname}${search}` : pathname; + const onData = function (chunk) { + if (finished) { + return + } - // Remove headers referring to the original URL. - // By default it is Host only, unless it's a 303 (see below), which removes also all Content-* headers. - // https://tools.ietf.org/html/rfc7231#section-6.4 - this.opts.headers = cleanRequestHeaders(this.opts.headers, statusCode === 303, this.opts.origin !== origin); - this.opts.path = path; - this.opts.origin = origin; - this.opts.maxRedirections = 0; - this.opts.query = null; + try { + if (!writer.write(chunk) && this.pause) { + this.pause(); + } + } catch (err) { + util.destroy(this, err); + } + }; + const onDrain = function () { + if (finished) { + return + } - // https://tools.ietf.org/html/rfc7231#section-6.4.4 - // In case of HTTP 303, always replace method to be either HEAD or GET - if (statusCode === 303 && this.opts.method !== 'HEAD') { - this.opts.method = 'GET'; - this.opts.body = null; + if (body.resume) { + body.resume(); } - } + }; + const onClose = function () { + // 'close' might be emitted *before* 'error' for + // broken streams. Wait a tick to avoid this case. + queueMicrotask(() => { + // It's only safe to remove 'error' listener after + // 'close'. + body.removeListener('error', onFinished); + }); - onData (chunk) { - if (this.location) ; else { - return this.handler.onData(chunk) + if (!finished) { + const err = new RequestAbortedError(); + queueMicrotask(() => onFinished(err)); + } + }; + const onFinished = function (err) { + if (finished) { + return } - } - onComplete (trailers) { - if (this.location) { - /* - https://tools.ietf.org/html/rfc7231#section-6.4 + finished = true; - TLDR: undici always ignores 3xx response trailers as they are not expected in case of redirections - and neither are useful if present. + assert(socket.destroyed || (socket[kWriting] && client[kRunning] <= 1)); - See comment on onData method above for more detailed informations. - */ + socket + .off('drain', onDrain) + .off('error', onFinished); - this.location = null; - this.abort = null; + body + .removeListener('data', onData) + .removeListener('end', onFinished) + .removeListener('close', onClose); - this.dispatch(this.opts, this); - } else { - this.handler.onComplete(trailers); + if (!err) { + try { + writer.end(); + } catch (er) { + err = er; + } } - } - onBodySent (chunk) { - if (this.handler.onBodySent) { - this.handler.onBodySent(chunk); + 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(); } - } - function parseLocation (statusCode, headers) { - if (redirectableStatusCodes.indexOf(statusCode) === -1) { - return null + 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)); } - for (let i = 0; i < headers.length; i += 2) { - if (headers[i].toString().toLowerCase() === 'location') { - return headers[i + 1] + 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\n\r\n`, 'latin1'); + } else { + assert(contentLength === null, 'no body must not have content length'); + socket.write(`${header}\r\n`, '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\n\r\n`, '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); } } - // https://tools.ietf.org/html/rfc7231#section-6.4.4 - function shouldRemoveHeader (header, removeContent, unknownOrigin) { - if (header.length === 4) { - return util.headerNameToString(header) === 'host' + 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\n\r\n`, '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); } - if (removeContent && util.headerNameToString(header).startsWith('content-')) { - return true + } + + 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(); + } } - if (unknownOrigin && (header.length === 13 || header.length === 6 || header.length === 19)) { - const name = util.headerNameToString(header); - return name === 'authorization' || name === 'cookie' || name === 'proxy-authorization' + + 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 { + // It's up to the user to somehow abort the async iterable. + 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); } - return false } - // https://tools.ietf.org/html/rfc7231#section-6.4 - 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]); + class AsyncWriter { + 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 + } + + // We should defer writing chunks. + if (contentLength !== null && bytesWritten + len > contentLength) { + if (client[kStrictContentLength]) { + throw new RequestContentLengthMismatchError() } + + process.emitWarning(new RequestContentLengthMismatchError()); } - } else if (headers && typeof headers === 'object') { - for (const key of Object.keys(headers)) { - if (!shouldRemoveHeader(key, removeContent, unknownOrigin)) { - ret.push(key, headers[key]); + + socket.cork(); + + if (bytesWritten === 0) { + if (!expectsPayload && request.reset !== false) { + socket[kReset] = true; + } + + if (contentLength === null) { + socket.write(`${header}transfer-encoding: chunked\r\n`, 'latin1'); + } else { + socket.write(`${header}content-length: ${contentLength}\r\n\r\n`, 'latin1'); } } - } else { - assert(headers == null, 'headers must be an object or an array'); + + if (contentLength === null) { + socket.write(`\r\n${len.toString(16)}\r\n`, '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) { + // istanbul ignore else: only for jest + if (socket[kParser].timeout.refresh) { + socket[kParser].timeout.refresh(); + } + } + } + + return ret } - return ret - } - RedirectHandler_1 = RedirectHandler; - return RedirectHandler_1; -} + end () { + const { socket, contentLength, client, bytesWritten, expectsPayload, header, request } = this; + request.onRequestSent(); -var redirectInterceptor; -var hasRequiredRedirectInterceptor; + socket[kWriting] = false; -function requireRedirectInterceptor () { - if (hasRequiredRedirectInterceptor) return redirectInterceptor; - hasRequiredRedirectInterceptor = 1; + if (socket[kError]) { + throw socket[kError] + } - const RedirectHandler = requireRedirectHandler(); + if (socket.destroyed) { + return + } - function createRedirectInterceptor ({ maxRedirections: defaultMaxRedirections }) { - return (dispatch) => { - return function Intercept (opts, handler) { - const { maxRedirections = defaultMaxRedirections } = opts; + if (bytesWritten === 0) { + if (expectsPayload) { + // https://tools.ietf.org/html/rfc7230#section-3.3.2 + // A user agent SHOULD send a Content-Length in a request message when + // no Transfer-Encoding is sent and the request method defines a meaning + // for an enclosed payload body. - if (!maxRedirections) { - return dispatch(opts, handler) + socket.write(`${header}content-length: 0\r\n\r\n`, 'latin1'); + } else { + socket.write(`${header}\r\n`, 'latin1'); } + } else if (contentLength === null) { + socket.write('\r\n0\r\n\r\n', 'latin1'); + } - const redirectHandler = new RedirectHandler(dispatch, maxRedirections, opts, handler); - opts = { ...opts, maxRedirections: 0 }; // Stop sub dispatcher from also redirecting. - return dispatch(opts, redirectHandler) + if (contentLength !== null && bytesWritten !== contentLength) { + if (client[kStrictContentLength]) { + throw new RequestContentLengthMismatchError() + } else { + process.emitWarning(new RequestContentLengthMismatchError()); + } } - } - } - redirectInterceptor = createRedirectInterceptor; - return redirectInterceptor; -} + if (socket[kParser].timeout && socket[kParser].timeoutType === TIMEOUT_HEADERS) { + // istanbul ignore else: only for jest + if (socket[kParser].timeout.refresh) { + socket[kParser].timeout.refresh(); + } + } -var llhttpWasm; -var hasRequiredLlhttpWasm; + client[kResume](); + } -function requireLlhttpWasm () { - if (hasRequiredLlhttpWasm) return llhttpWasm; - hasRequiredLlhttpWasm = 1; - llhttpWasm = 'AGFzbQEAAAABMAhgAX8Bf2ADf39/AX9gBH9/f38Bf2AAAGADf39/AGABfwBgAn9/AGAGf39/f39/AALLAQgDZW52GHdhc21fb25faGVhZGVyc19jb21wbGV0ZQACA2VudhV3YXNtX29uX21lc3NhZ2VfYmVnaW4AAANlbnYLd2FzbV9vbl91cmwAAQNlbnYOd2FzbV9vbl9zdGF0dXMAAQNlbnYUd2FzbV9vbl9oZWFkZXJfZmllbGQAAQNlbnYUd2FzbV9vbl9oZWFkZXJfdmFsdWUAAQNlbnYMd2FzbV9vbl9ib2R5AAEDZW52GHdhc21fb25fbWVzc2FnZV9jb21wbGV0ZQAAA0ZFAwMEAAAFAAAAAAAABQEFAAUFBQAABgAAAAAGBgYGAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQABAAABAQcAAAUFAwABBAUBcAESEgUDAQACBggBfwFBgNQECwfRBSIGbWVtb3J5AgALX2luaXRpYWxpemUACRlfX2luZGlyZWN0X2Z1bmN0aW9uX3RhYmxlAQALbGxodHRwX2luaXQAChhsbGh0dHBfc2hvdWxkX2tlZXBfYWxpdmUAQQxsbGh0dHBfYWxsb2MADAZtYWxsb2MARgtsbGh0dHBfZnJlZQANBGZyZWUASA9sbGh0dHBfZ2V0X3R5cGUADhVsbGh0dHBfZ2V0X2h0dHBfbWFqb3IADxVsbGh0dHBfZ2V0X2h0dHBfbWlub3IAEBFsbGh0dHBfZ2V0X21ldGhvZAARFmxsaHR0cF9nZXRfc3RhdHVzX2NvZGUAEhJsbGh0dHBfZ2V0X3VwZ3JhZGUAEwxsbGh0dHBfcmVzZXQAFA5sbGh0dHBfZXhlY3V0ZQAVFGxsaHR0cF9zZXR0aW5nc19pbml0ABYNbGxodHRwX2ZpbmlzaAAXDGxsaHR0cF9wYXVzZQAYDWxsaHR0cF9yZXN1bWUAGRtsbGh0dHBfcmVzdW1lX2FmdGVyX3VwZ3JhZGUAGhBsbGh0dHBfZ2V0X2Vycm5vABsXbGxodHRwX2dldF9lcnJvcl9yZWFzb24AHBdsbGh0dHBfc2V0X2Vycm9yX3JlYXNvbgAdFGxsaHR0cF9nZXRfZXJyb3JfcG9zAB4RbGxodHRwX2Vycm5vX25hbWUAHxJsbGh0dHBfbWV0aG9kX25hbWUAIBJs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ADcDACAAQShqQgA3AwAgAEEgakIANwMAIABBEGpCADcDACAAQQhqQgA3AwAgAEHdATYCHEEAC3sBAX8CQCAAKAIMIgMNAAJAIAAoAgRFDQAgACABNgIECwJAIAAgASACEMSAgIAAIgMNACAAKAIMDwsgACADNgIcQQAhAyAAKAIEIgFFDQAgACABIAIgACgCCBGBgICAAAAiAUUNACAAIAI2AhQgACABNgIMIAEhAwsgAwvk8wEDDn8DfgR/I4CAgIAAQRBrIgMkgICAgAAgASEEIAEhBSABIQYgASEHIAEhCCABIQkgASEKIAEhCyABIQwgASENIAEhDiABIQ8CQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkAgACgCHCIQQX9qDt0B2gEB2QECAwQFBgcICQoLDA0O2AEPENcBERLWARMUFRYXGBkaG+AB3wEcHR7VAR8gISIjJCXUASYnKCkqKyzTAdIBLS7RAdABLzAxMjM0NTY3ODk6Ozw9Pj9AQUJDREVG2wFHSElKzwHOAUvNAUzMAU1OT1BRUlNUVVZXWFlaW1xdXl9gYWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXp7fH1+f4ABgQGCAYMBhAGFAYYBhwGIAYkB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QAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkAC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FCAAIBA2AgxBACEQDLIBCyAAKAIEIRAgAEEANgIEAkAgACAQIAEQp4CAgAAiEA0AIAEhAQxNCyAAQdMANgIcIAAgATYCFCAAIBA2AgxBACEQDLEBCyAAKAIEIRAgAEEANgIEAkAgACAQIAEQp4CAgAAiEA0AIAEhAQxRCyAAQeUANgIcIAAgATYCFCAAIBA2AgxBACEQDLABCyAAQQA2AhwgACABNgIUIABBxoqAgAA2AhAgAEEHNgIMQQAhEAyvAQsgACgCBCEQIABBADYCBAJAIAAgECABEKeAgIAAIhANACABIQEMSQsgAEHSADYCHCAAIAE2AhQgACAQNgIMQQAhEAyuAQsgACgCBCEQIABBADYCBAJAIAAgECABEKeAgIAAIhANACABIQEMSQsgAEHTADYCHCAAIAE2AhQgACAQNgIMQQAhEAytAQsgACgCBCEQIABBADYCBAJAIAAgECABEKeAgIAAIhANACABIQEMTQsgAEHlADYCHCAAIAE2AhQgACAQNgIMQQAhEAysAQsgAEEANgIcIAAgATYCFCAAQdyIgIAANgIQIABBBzYCDEEAIRAMqwELIBBBP0cNASABQQFqIQELQQUhEAyQAQtBACEQIABBADYCHCAAIAE2AhQgAEH9koCAADYCECAAQQc2AgwMqAELIAAoAgQhECAAQQA2AgQCQCAAIBAgARCngICAACIQDQAgASEBDEILIABB0gA2AhwgACABNgIUIAAgEDYCDEEAIRAMpwELIAAoAgQhECAAQQA2AgQCQCAAIBAgARCngICAACIQDQAgASEBDEILIABB0wA2AhwgACABNgIUIAAgEDYCDEEAIRAMpgELIAAoAgQhECAAQQA2AgQCQCAAIBAgARCngICAACIQDQAgASEBDEYLIABB5QA2AhwgACABNgIUIAAgEDYCDEEAIRAMpQELIAAoAgQhASAAQQA2AgQCQCAAIAEgFBCngICAACIBDQAgFCEBDD8LIABB0gA2AhwgACAUNgIUIAAgATYCDEEAIRAMpAELIAAoAgQhASAAQQA2AgQCQCAAIAEgFBCngICAACIBDQAgFCEBDD8LIABB0wA2AhwgACAUNgIUIAAgATYCDEEAIRAMowELIAAoAgQhASAAQQA2AgQCQCAAIAEgFBCngICAACIBDQAgFCEBDEMLIABB5QA2AhwgACAU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YWdlX2JlZ2luYCBjYWxsYmFjayBlcnJvcgBgb25fY2h1bmtfZXh0ZW5zaW9uX3ZhbHVlYCBjYWxsYmFjayBlcnJvcgBgb25fc3RhdHVzX2NvbXBsZXRlYCBjYWxsYmFjayBlcnJvcgBgb25fdmVyc2lvbl9jb21wbGV0ZWAgY2FsbGJhY2sgZXJyb3IAYG9uX3VybF9jb21wbGV0ZWAgY2FsbGJhY2sgZXJyb3IAYG9uX2NodW5rX2NvbXBsZXRlYCBjYWxsYmFjayBlcnJvcgBgb25faGVhZGVyX3ZhbHVlX2NvbXBsZXRlYCBjYWxsYmFjayBlcnJvcgBgb25fbWVzc2FnZV9jb21wbGV0ZWAgY2FsbGJhY2sgZXJyb3IAYG9uX21ldGhvZF9jb21wbGV0ZWAgY2FsbGJhY2sgZXJyb3IAYG9uX2hlYWRlcl9maWVsZF9jb21wbGV0ZWAgY2FsbGJhY2sgZXJyb3IAYG9uX2NodW5rX2V4dGVuc2lvbl9uYW1lYCBjYWxsYmFjayBlcnJvcgBVbmV4cGVjdGVkIGNoYXIgaW4gdXJsIHNlcnZlcgBJbnZhbGlkIGhlYWRlciB2YWx1ZSBjaGFyAEludmFsaWQgaGVhZGVyIGZpZWxkIGNoYXIAU3BhbiBjYWxsYmFjayBlcnJvciBpbiBvbl92ZXJzaW9uAEludmFsaWQgbWlub3IgdmVyc2lvbgBJbnZhbGlkIG1ham9yIHZlcnNpb24ARXhwZWN0ZWQgc3BhY2UgYWZ0ZXIgdmVyc2lvbgBFeHBlY3RlZCBDUkxGIGFmdGVyIHZlcnNpb24ASW52YWxpZCBIVFRQIHZlcnNpb24ASW52YWxpZCBoZWFkZXIgdG9rZW4AU3BhbiBjYWxsYmFjayBlcnJvciBpbiBvbl91cmwASW52YWxpZCBjaGFyYWN0ZXJzIGluIHVybABVbmV4cGVjdGVkIHN0YXJ0IGNoYXIgaW4gdXJsAERvdWJsZSBAIGluIHVybABFbXB0eSBDb250ZW50LUxlbmd0aABJbnZhbGlkIGNoYXJhY3RlciBpbiBDb250ZW50LUxlbmd0aABEdXBsaWNhdGUgQ29udGVudC1MZW5ndGgASW52YWxpZCBjaGFyIGluIHVybCBwYXRoAENvbnRlbnQtTGVuZ3RoIGNhbid0IGJlIHByZXNlbnQgd2l0aCBUcmFuc2Zlci1FbmNvZGluZwBJbnZhbGlkIGNoYXJhY3RlciBpbiBjaHVuayBzaXplAFNwYW4gY2FsbGJhY2sgZXJyb3IgaW4gb25faGVhZGVyX3ZhbHVlAFNwYW4gY2FsbGJhY2sgZXJyb3IgaW4gb25fY2h1bmtfZXh0ZW5zaW9uX3ZhbHVlAEludmFsaWQgY2hhcmFjdGVyIGluIGNodW5rIGV4dGVuc2lvbnMgdmFsdWUATWlzc2luZyBleHBlY3RlZCBMRiBhZnRlciBoZWFkZXIgdmFsdWUASW52YWxpZCBgVHJhbnNmZXItRW5jb2RpbmdgIGhlYWRlciB2YWx1ZQBJbnZhbGlkIGNoYXJhY3RlciBpbiBjaHVuayBleHRlbnNpb25zIHF1b3RlIHZhbHVlAEludmFsaWQgY2hhcmFjdGVyIGluIGNodW5rIGV4dGVuc2lvbnMgcXVvdGVkIHZhbHVlAFBhdXNlZCBieSBvbl9oZWFkZXJzX2NvbXBsZXRlAEludmFsaWQgRU9GIHN0YXRlAG9uX3Jlc2V0IHBhdXNlAG9uX2NodW5rX2hlYWRlciBwYXVzZQBvbl9tZXNzYWdlX2JlZ2luIHBhdXNlAG9uX2NodW5rX2V4dGVuc2lvbl92YWx1ZSBwYXVzZQBvbl9zdGF0dXNfY29tcGxldGUgcGF1c2UAb25fdmVyc2lvbl9jb21wbGV0ZSBwYXVzZQBvbl91cmxfY29tcGxldGUgcGF1c2UAb25fY2h1bmtfY29tcGxldGUgcGF1c2UAb25faGVhZGVyX3ZhbHVlX2NvbXBsZXRlIHBhdXNlAG9uX21lc3NhZ2VfY29tcGxldGUgcGF1c2UAb25fbWV0aG9kX2NvbXBsZXRlIHBhdXNlAG9uX2hlYWRlcl9maWVsZF9jb21wbGV0ZSBwYXVzZQBvbl9jaHVua19leHRlbnNpb25fbmFtZSBwYXVzZQBVbmV4cGVjdGVkIHNwYWNlIGFmdGVyIHN0YXJ0IGxpbmUAU3BhbiBjYWxsYmFjayBlcnJvciBpbiBvbl9jaHVua19leHRlbnNpb25fbmFtZQBJbnZhbGlkIGNoYXJhY3RlciBpbiBjaHVuayBleHRlbnNpb25zIG5hbWUAUGF1c2Ugb24gQ09OTkVDVC9VcGdyYWRlAFBhdXNlIG9uIFBSSS9VcGdyYWRlAEV4cGVjdGVkIEhUVFAvMiBDb25uZWN0aW9uIFByZWZhY2UAU3BhbiBjYWxsYmFjayBlcnJvciBpbiBvbl9tZXRob2QARXhwZWN0ZWQgc3BhY2UgYWZ0ZXIgbWV0aG9kAFNwYW4gY2FsbGJhY2sgZXJyb3IgaW4gb25faGVhZGVyX2ZpZWxkAFBhdXNlZABJbnZhbGlkIHdvcmQgZW5jb3VudGVyZWQASW52YWxpZCBtZXRob2QgZW5jb3VudGVyZWQAVW5leHBlY3RlZCBjaGFyIGluIHVybCBzY2hlbWEAUmVxdWVzdCBoYXMgaW52YWxpZCBgVHJhbnNmZXItRW5jb2RpbmdgAFNXSVRDSF9QUk9YWQBVU0VfUFJPWFkATUtBQ1RJVklUWQBVTlBST0NFU1NBQkxFX0VOVElUWQBDT1BZAE1PVkVEX1BFUk1BTkVOVExZAFRPT19FQVJMWQBOT1RJRlkARkFJTEVEX0RFUEVOREVOQ1kAQkFEX0dBVEVXQVkAUExBWQBQVVQAQ0hFQ0tPVVQAR0FURVdBWV9USU1FT1VUAFJFUVVFU1RfVElNRU9VVABORVRXT1JLX0NPTk5FQ1RfVElNRU9VVABDT05ORUNUSU9OX1RJTUVPVVQATE9HSU5fVElNRU9VVABORVRXT1JLX1JFQURfVElNRU9VVABQT1NUAE1JU0RJUkVDVEVEX1JFUVVFU1QAQ0xJRU5UX0NMT1NFRF9SRVFVRVNUAENMSUVOVF9DTE9TRURfTE9BRF9CQUxBTkNFRF9SRVFVRVNUAEJBRF9SRVFVRVNUAEhUVFBfUkVRVUVTVF9TRU5UX1RPX0hUVFBTX1BPUlQAUkVQT1JUAElNX0FfVEVBUE9UAFJFU0VUX0NPTlRFTlQATk9fQ09OVEVOVABQQVJUSUFMX0NPTlRFTlQASFBFX0lOVkFMSURfQ09OU1RBTlQASFBFX0NCX1JFU0VUAEdFVABIUEVfU1RSSUNUAENPTkZMSUNUAFRFTVBPUkFSWV9SRURJUkVDVABQRVJNQU5FTlRfUkVESVJFQ1QAQ09OTkVDVABNVUxUSV9TVEFUVVMASFBFX0lOVkFMSURfU1RBVFVTAFRPT19NQU5ZX1JFUVVFU1RTAEVBUkxZX0hJTlRTAFVOQVZBSUxBQkxFX0ZPUl9MRUdBTF9SRUFTT05TAE9QVElPTlMAU1dJVENISU5HX1BST1RPQ09MUwBWQVJJQU5UX0FMU09fTkVHT1RJQVRFUwBNVUxUSVBMRV9DSE9JQ0VTAElOVEVSTkFMX1NFUlZFUl9FUlJPUgBXRUJfU0VSVkVSX1VOS05PV05fRVJST1IAUkFJTEdVTl9FUlJPUgBJREVOVElUWV9QUk9WSURFUl9BVVRIRU5USUNBVElPTl9FUlJPUgBTU0xfQ0VSVElGSUNBVEVfRVJST1IASU5WQUxJRF9YX0ZPUldBUkRFRF9GT1IAU0VUX1BBUkFNRVRFUgBHRVRfUEFSQU1FVEVSAEhQRV9VU0VSAFNFRV9PVEhFUgBIUEVfQ0JfQ0hVTktfSEVBREVSAE1LQ0FMRU5EQVIAU0VUVVAAV0VCX1NFUlZFUl9JU19ET1dOAFRFQVJET1dOAEhQRV9DTE9TRURfQ09OTkVDVElPTgBIRVVSSVNUSUNfRVhQSVJBVElPTgBESVNDT05ORUNURURfT1BFUkFUSU9OAE5PTl9BVVRIT1JJVEFUSVZFX0lORk9STUFUSU9OAEhQRV9JTlZBTElEX1ZFUlNJT04ASFBFX0NCX01FU1NBR0VfQkVHSU4AU0lURV9JU19GUk9aRU4ASFBFX0lOVkFMSURfSEVBREVSX1RPS0VOAElOVkFMSURfVE9LRU4ARk9SQklEREVOAEVOSEFOQ0VfWU9VUl9DQUxNAEhQRV9JTlZBTElEX1VSTABCTE9DS0VEX0JZX1BBUkVOVEFMX0NPTlRST0wATUtDT0wAQUNMAEhQRV9JTlRFUk5BTABSRVFVRVNUX0hFQURFUl9GSUVMRFNfVE9PX0xBUkdFX1VOT0ZGSUNJQUwASFBFX09LAFVOTElOSwBVTkxPQ0sAUFJJAFJFVFJZX1dJVEgASFBFX0lOVkFMSURfQ09OVEVOVF9MRU5HVEgASFBFX1VORVhQRUNURURfQ09OVEVOVF9MRU5HVEgARkxVU0gAUFJPUFBBVENIAE0tU0VBUkNIAFVSSV9UT09fTE9ORwBQUk9DRVNTSU5HAE1JU0NFTExBTkVPVVNfUEVSU0lTVEVOVF9XQVJOSU5HAE1JU0NFTExBTkVPVVNfV0FSTklORwBIUEVfSU5WQUxJRF9UUkFOU0ZFUl9FTkNPRElORwBFeHBlY3RlZCBDUkxGAEhQRV9JTlZBTElEX0NIVU5LX1NJWkUATU9WRQBDT05USU5VRQBIUEVfQ0JfU1RBVFVTX0NPTVBMRVRFAEhQRV9DQl9IRUFERVJTX0NPTVBMRVRFAEhQRV9DQl9WRVJTSU9OX0NPTVBMRVRFAEhQRV9DQl9VUkxfQ09NUExFVEUASFBFX0NCX0NIVU5LX0NPTVBMRVRFAEhQRV9DQl9IRUFERVJfVkFMVUVfQ09NUExFVEUASFBFX0NCX0NIVU5LX0VYVEVOU0lPTl9WQUxVRV9DT01QTEVURQBIUEVfQ0JfQ0hVTktfRVhURU5TSU9OX05BTUVfQ09NUExFVEUASFBFX0NCX01FU1NBR0VfQ09NUExFVEUASFBFX0NCX01FVEhPRF9DT01QTEVURQBIUEVfQ0JfSEVBREVSX0ZJRUxEX0NPTVBMRVRFAERFTEVURQBIUEVfSU5WQUxJRF9FT0ZfU1RBVEUASU5WQUxJRF9TU0xfQ0VSVElGSUNBVEUAUEFVU0UATk9fUkVTUE9OU0UAVU5TVVBQT1JURURfTUVESUFfVFlQRQBHT05FAE5PVF9BQ0NFUFRBQkxFAFNFUlZJQ0VfVU5BVkFJTEFCTEUAUkFOR0VfTk9UX1NBVElTRklBQkxFAE9SSUdJTl9JU19VTlJFQUNIQUJMRQBSRVNQT05TRV9JU19TVEFMRQBQVVJHRQBNRVJHRQBSRVFVRVNUX0hFQURFUl9GSUVMRFNfVE9PX0xBUkdFAFJFUVVFU1RfSEVBREVSX1RPT19MQVJHRQBQQVlMT0FEX1RPT19MQVJHRQBJTlNVRkZJQ0lFTlRfU1RPUkFHRQBIUEVfUEFVU0VEX1VQR1JBREUASFBFX1BBVVNFRF9IMl9VUEdSQURFAFNPVVJDRQBBTk5PVU5DRQBUUkFDRQBIUEVfVU5FWFBFQ1RFRF9TUEFDRQBERVNDUklCRQBVTlNVQlNDUklCRQBSRUNPUkQASFBFX0lOVkFMSURfTUVUSE9EAE5PVF9GT1VORABQUk9QRklORABVTkJJTkQAUkVCSU5EAFVOQVVUSE9SSVpFRABNRVRIT0RfTk9UX0FMTE9XRUQASFRUUF9WRVJTSU9OX05PVF9TVVBQT1JURUQAQUxSRUFEWV9SRVBPUlRFRABBQ0NFUFRFRABOT1RfSU1QTEVNRU5URUQATE9PUF9ERVRFQ1RFRABIUEVfQ1JfRVhQRUNURUQASFBFX0xGX0VYUEVDVEVEAENSRUFURUQASU1fVVNFRABIUEVfUEFVU0VEAFRJTUVPVVRfT0NDVVJFRABQQVlNRU5UX1JFUVVJUkVEAFBSRUNPTkRJVElPTl9SRVFVSVJFRABQUk9YWV9BVVRIRU5USUNBVElPTl9SRVFVSVJFRABORVRXT1JLX0FVVEhFTlRJQ0FUSU9OX1JFUVVJUkVEAExFTkdUSF9SRVFVSVJFRABTU0xfQ0VSVElGSUNBVEVfUkVRVUlSRUQAVVBHUkFERV9SRVFVSVJFRABQQUdFX0VYUElSRUQAUFJFQ09ORElUSU9OX0ZBSUxFRABFWFBFQ1RBVElPTl9GQUlMRUQAUkVWQUxJREFUSU9OX0ZBSUxFRABTU0xfSEFORFNIQUtFX0ZBSUxFRABMT0NLRUQAVFJBTlNGT1JNQVRJT05fQVBQTElFRABOT1RfTU9ESUZJRUQATk9UX0VYVEVOREVEAEJBTkRXSURUSF9MSU1JVF9FWENFRURFRABTSVRFX0lTX09WRVJMT0FERUQASEVBRABFeHBlY3RlZCBIVFRQLwAAXhMAACYTAAAwEAAA8BcAAJ0TAAAVEgAAORcAAPASAAAKEAAAdRIAAK0SAACCEwAATxQAAH8QAACgFQAAIxQAAIkSAACLFAAATRUAANQRAADPFAAAEBgAAMkWAADcFgAAwREAAOAXAAC7FAAAdBQAAHwVAADlFAAACBcAAB8QAABlFQAAoxQAACgVAAACFQAAmRUAACwQAACLGQAATw8AANQOAABqEAAAzhAAAAIXAACJDgAAbhMAABwTAABmFAAAVhcAAMETAADNEwAAbBMAAGgXAABmFwAAXxcAACITAADODwAAaQ4AANgOAABjFgAAyxMAAKoOAAAoFwAAJhcAAMUTAABdFgAA6BEAAGcTAABlEwAA8hYAAHMTAAAdFwAA+RYAAPMRAADPDgAAzhUAAAwSAACzEQAApREAAGEQAAAyFwAAuxMAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAQIBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEAAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAIDAgICAgIAAAICAAICAAICAgICAgICAgIABAAAAAAAAgICAgICAgICAgICAgICAgICAgICAgICAgIAAAACAgICAgICAgICAgICAgICAgICAgICAgICAgICAgACAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAACAAICAgICAAACAgACAgACAgICAgICAgICAAMABAAAAAICAgICAgICAgICAgICAgICAgICAgICAgICAAAAAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAAgACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAbG9zZWVlcC1hbGl2ZQAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEAAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEBAQEBAQEBAQEBAQIBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAAEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBY2h1bmtlZAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQEAAQEBAQEAAAEBAAEBAAEBAQEBAQEBAQEAAAAAAAAAAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEAAAABAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQABAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABlY3Rpb25lbnQtbGVuZ3Rob25yb3h5LWNvbm5lY3Rpb24AAAAAAAAAAAAAAAAAAAByYW5zZmVyLWVuY29kaW5ncGdyYWRlDQoNCg0KU00NCg0KVFRQL0NFL1RTUC8AAAAAAAAAAAAAAAABAgABAwAAAAAAAAAAAAAAAAAAAAAAAAQBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAAEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAAAAAAAAAAAAAQIAAQMAAAAAAAAAAAAAAAAAAAAAAAAEAQEFAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQABAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQAAAAAAAAAAAAEAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAEBAAEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQABAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEAAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEAAAAAAAAAAAAAAQAAAgAAAAAAAAAAAAAAAAAAAAAAAAMEAAAEBAQEBAQEBAQEBAUEBAQEBAQEBAQEBAQABAAGBwQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAAEAAQABAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAEAAAAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAADAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwAAAAAAAAMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAABAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAIAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMAAAAAAAADAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABOT1VOQ0VFQ0tPVVRORUNURVRFQ1JJQkVMVVNIRVRFQURTRUFSQ0hSR0VDVElWSVRZTEVOREFSVkVPVElGWVBUSU9OU0NIU0VBWVNUQVRDSEdFT1JESVJFQ1RPUlRSQ0hQQVJBTUVURVJVUkNFQlNDUklCRUFSRE9XTkFDRUlORE5LQ0tVQlNDUklCRUhUVFAvQURUUC8='; - return llhttpWasm; -} + destroy (err) { + const { socket, client, abort } = this; -var llhttp_simdWasm; -var hasRequiredLlhttp_simdWasm; + socket[kWriting] = false; -function requireLlhttp_simdWasm () { - if (hasRequiredLlhttp_simdWasm) return llhttp_simdWasm; - hasRequiredLlhttp_simdWasm = 1; - llhttp_simdWasm = 'AGFzbQEAAAABMAhgAX8Bf2ADf39/AX9gBH9/f38Bf2AAAGADf39/AGABfwBgAn9/AGAGf39/f39/AALLAQgDZW52GHdhc21fb25faGVhZGVyc19jb21wbGV0ZQACA2VudhV3YXNtX29uX21lc3NhZ2VfYmVnaW4AAANlbnYLd2FzbV9vbl91cmwAAQNlbnYOd2FzbV9vbl9zdGF0dXMAAQNlbnYUd2FzbV9vbl9oZWFkZXJfZmllbGQAAQNlbnYUd2FzbV9vbl9oZWFkZXJfdmFsdWUAAQNlbnYMd2FzbV9vbl9ib2R5AAEDZW52GHdhc21fb25fbWVzc2FnZV9jb21wbGV0ZQAAA0ZFAwMEAAAFAAAAAAAABQEFAAUFBQAABgAAAAAGBgYGAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQABAAABAQcAAAUFAwABBAUBcAESEgUDAQACBggBfwFBgNQECwfRBSIGbWVtb3J5AgALX2luaXRpYWxpemUACRlfX2luZGlyZWN0X2Z1bmN0aW9uX3RhYmxlAQALbGxodHRwX2luaXQAChhsbGh0dHBfc2hvdWxkX2tlZXBfYWxpdmUAQQxsbGh0dHBfYWxsb2MADAZtYWxsb2MARgtsbGh0dHBfZnJlZQANBGZyZWUASA9sbGh0dHBfZ2V0X3R5cGUADhVsbGh0dHBfZ2V0X2h0dHBfbWFqb3IADxVsbGh0dHBfZ2V0X2h0dHBfbWlub3IAEBFsbGh0dHBfZ2V0X21ldGhvZAARFmxsaHR0cF9nZXRfc3RhdHVzX2NvZGUAEhJsbGh0dHBfZ2V0X3VwZ3JhZGUAEwxsbGh0dHBfcmVzZXQAFA5sbGh0dHBfZXhlY3V0ZQAVFGxsaHR0cF9zZXR0aW5nc19pbml0ABYNbGxodHRwX2ZpbmlzaAAXDGxsaHR0cF9wYXVzZQAYDWxsaHR0cF9yZXN1bWUAGRtsbGh0dHBfcmVzdW1lX2FmdGVyX3VwZ3JhZGUAGhBsbGh0dHBfZ2V0X2Vycm5vABsXbGxodHRwX2dldF9lcnJvcl9yZWFzb24AHBdsbGh0dHBfc2V0X2Vycm9yX3JlYXNvbgAdFGxsaHR0cF9nZXRfZXJyb3JfcG9zAB4RbGxodHRwX2Vycm5vX25hbWUAHxJsbGh0dHBfbWV0aG9kX25hbWUAIBJs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IAH9CwMAIABBMGogAf0LAwAgAEEgaiAB/QsDACAAQd0BNgIcQQALewEBfwJAIAAoAgwiAw0AAkAgACgCBEUNACAAIAE2AgQLAkAgACABIAIQxICAgAAiAw0AIAAoAgwPCyAAIAM2AhxBACEDIAAoAgQiAUUNACAAIAEgAiAAKAIIEYGAgIAAACIBRQ0AIAAgAjYCFCAAIAE2AgwgASEDCyADC+TzAQMOfwN+BH8jgICAgABBEGsiAySAgICAACABIQQgASEFIAEhBiABIQcgASEIIAEhCSABIQogASELIAEhDCABIQ0gASEOIAEhDwJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQCAAKAIcIhBBf2oO3QHaAQHZAQIDBAUGBwgJCgsMDQ7YAQ8Q1wEREtYBExQVFhcYGRob4AHfARwdHtUBHyAhIiMkJdQBJicoKSorLNMB0gEtLtEB0AEvMDEyMzQ1Njc4OTo7PD0+P0BBQkNERUbbAUdISUrPAc4BS80BTMwBTU5PUFFSU1RVVldYWVpbXF1eX2BhYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5ent8fX5/gAGBAYIBgwGEAYUBhgGHAYgBiQGKAYsBjAGNAY4BjwGQAZEB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QAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAIBAOxwEAAQID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YWNrIGVycm9yAGBvbl9jaHVua19leHRlbnNpb25fdmFsdWVgIGNhbGxiYWNrIGVycm9yAGBvbl9zdGF0dXNfY29tcGxldGVgIGNhbGxiYWNrIGVycm9yAGBvbl92ZXJzaW9uX2NvbXBsZXRlYCBjYWxsYmFjayBlcnJvcgBgb25fdXJsX2NvbXBsZXRlYCBjYWxsYmFjayBlcnJvcgBgb25fY2h1bmtfY29tcGxldGVgIGNhbGxiYWNrIGVycm9yAGBvbl9oZWFkZXJfdmFsdWVfY29tcGxldGVgIGNhbGxiYWNrIGVycm9yAGBvbl9tZXNzYWdlX2NvbXBsZXRlYCBjYWxsYmFjayBlcnJvcgBgb25fbWV0aG9kX2NvbXBsZXRlYCBjYWxsYmFjayBlcnJvcgBgb25faGVhZGVyX2ZpZWxkX2NvbXBsZXRlYCBjYWxsYmFjayBlcnJvcgBgb25fY2h1bmtfZXh0ZW5zaW9uX25hbWVgIGNhbGxiYWNrIGVycm9yAFVuZXhwZWN0ZWQgY2hhciBpbiB1cmwgc2VydmVyAEludmFsaWQgaGVhZGVyIHZhbHVlIGNoYXIASW52YWxpZCBoZWFkZXIgZmllbGQgY2hhcgBTcGFuIGNhbGxiYWNrIGVycm9yIGluIG9uX3ZlcnNpb24ASW52YWxpZCBtaW5vciB2ZXJzaW9uAEludmFsaWQgbWFqb3IgdmVyc2lvbgBFeHBlY3RlZCBzcGFjZSBhZnRlciB2ZXJzaW9uAEV4cGVjdGVkIENSTEYgYWZ0ZXIgdmVyc2lvbgBJbnZhbGlkIEhUVFAgdmVyc2lvbgBJbnZhbGlkIGhlYWRlciB0b2tlbgBTcGFuIGNhbGxiYWNrIGVycm9yIGluIG9uX3VybABJbnZhbGlkIGNoYXJhY3RlcnMgaW4gdXJsAFVuZXhwZWN0ZWQgc3RhcnQgY2hhciBpbiB1cmwARG91YmxlIEAgaW4gdXJsAEVtcHR5IENvbnRlbnQtTGVuZ3RoAEludmFsaWQgY2hhcmFjdGVyIGluIENvbnRlbnQtTGVuZ3RoAER1cGxpY2F0ZSBDb250ZW50LUxlbmd0aABJbnZhbGlkIGNoYXIgaW4gdXJsIHBhdGgAQ29udGVudC1MZW5ndGggY2FuJ3QgYmUgcHJlc2VudCB3aXRoIFRyYW5zZmVyLUVuY29kaW5nAEludmFsaWQgY2hhcmFjdGVyIGluIGNodW5rIHNpemUAU3BhbiBjYWxsYmFjayBlcnJvciBpbiBvbl9oZWFkZXJfdmFsdWUAU3BhbiBjYWxsYmFjayBlcnJvciBpbiBvbl9jaHVua19leHRlbnNpb25fdmFsdWUASW52YWxpZCBjaGFyYWN0ZXIgaW4gY2h1bmsgZXh0ZW5zaW9ucyB2YWx1ZQBNaXNzaW5nIGV4cGVjdGVkIExGIGFmdGVyIGhlYWRlciB2YWx1ZQBJbnZhbGlkIGBUcmFuc2Zlci1FbmNvZGluZ2AgaGVhZGVyIHZhbHVlAEludmFsaWQgY2hhcmFjdGVyIGluIGNodW5rIGV4dGVuc2lvbnMgcXVvdGUgdmFsdWUASW52YWxpZCBjaGFyYWN0ZXIgaW4gY2h1bmsgZXh0ZW5zaW9ucyBxdW90ZWQgdmFsdWUAUGF1c2VkIGJ5IG9uX2hlYWRlcnNfY29tcGxldGUASW52YWxpZCBFT0Ygc3RhdGUAb25fcmVzZXQgcGF1c2UAb25fY2h1bmtfaGVhZGVyIHBhdXNlAG9uX21lc3NhZ2VfYmVnaW4gcGF1c2UAb25fY2h1bmtfZXh0ZW5zaW9uX3ZhbHVlIHBhdXNlAG9uX3N0YXR1c19jb21wbGV0ZSBwYXVzZQBvbl92ZXJzaW9uX2NvbXBsZXRlIHBhdXNlAG9uX3VybF9jb21wbGV0ZSBwYXVzZQBvbl9jaHVua19jb21wbGV0ZSBwYXVzZQBvbl9oZWFkZXJfdmFsdWVfY29tcGxldGUgcGF1c2UAb25fbWVzc2FnZV9jb21wbGV0ZSBwYXVzZQBvbl9tZXRob2RfY29tcGxldGUgcGF1c2UAb25faGVhZGVyX2ZpZWxkX2NvbXBsZXRlIHBhdXNlAG9uX2NodW5rX2V4dGVuc2lvbl9uYW1lIHBhdXNlAFVuZXhwZWN0ZWQgc3BhY2UgYWZ0ZXIgc3RhcnQgbGluZQBTcGFuIGNhbGxiYWNrIGVycm9yIGluIG9uX2NodW5rX2V4dGVuc2lvbl9uYW1lAEludmFsaWQgY2hhcmFjdGVyIGluIGNodW5rIGV4dGVuc2lvbnMgbmFtZQBQYXVzZSBvbiBDT05ORUNUL1VwZ3JhZGUAUGF1c2Ugb24gUFJJL1VwZ3JhZGUARXhwZWN0ZWQgSFRUUC8yIENvbm5lY3Rpb24gUHJlZmFjZQBTcGFuIGNhbGxiYWNrIGVycm9yIGluIG9uX21ldGhvZABFeHBlY3RlZCBzcGFjZSBhZnRlciBtZXRob2QAU3BhbiBjYWxsYmFjayBlcnJvciBpbiBvbl9oZWFkZXJfZmllbGQAUGF1c2VkAEludmFsaWQgd29yZCBlbmNvdW50ZXJlZABJbnZhbGlkIG1ldGhvZCBlbmNvdW50ZXJlZABVbmV4cGVjdGVkIGNoYXIgaW4gdXJsIHNjaGVtYQBSZXF1ZXN0IGhhcyBpbnZhbGlkIGBUcmFuc2Zlci1FbmNvZGluZ2AAU1dJVENIX1BST1hZAFVTRV9QUk9YWQBNS0FDVElWSVRZAFVOUFJPQ0VTU0FCTEVfRU5USVRZAENPUFkATU9WRURfUEVSTUFORU5UTFkAVE9PX0VBUkxZAE5PVElGWQBGQUlMRURfREVQRU5ERU5DWQBCQURfR0FURVdBWQBQTEFZAFBVVABDSEVDS09VVABHQVRFV0FZX1RJTUVPVVQAUkVRVUVTVF9USU1FT1VUAE5FVFdPUktfQ09OTkVDVF9USU1FT1VUAENPTk5FQ1RJT05fVElNRU9VVABMT0dJTl9USU1FT1VUAE5FVFdPUktfUkVBRF9USU1FT1VUAFBPU1QATUlTRElSRUNURURfUkVRVUVTVABDTElFTlRfQ0xPU0VEX1JFUVVFU1QAQ0xJRU5UX0NMT1NFRF9MT0FEX0JBTEFOQ0VEX1JFUVVFU1QAQkFEX1JFUVVFU1QASFRUUF9SRVFVRVNUX1NFTlRfVE9fSFRUUFNfUE9SVABSRVBPUlQASU1fQV9URUFQT1QAUkVTRVRfQ09OVEVOVABOT19DT05URU5UAFBBUlRJQUxfQ09OVEVOVABIUEVfSU5WQUxJRF9DT05TVEFOVABIUEVfQ0JfUkVTRVQAR0VUAEhQRV9TVFJJQ1QAQ09ORkxJQ1QAVEVNUE9SQVJZX1JFRElSRUNUAFBFUk1BTkVOVF9SRURJUkVDVABDT05ORUNUAE1VTFRJX1NUQVRVUwBIUEVfSU5WQUxJRF9TVEFUVVMAVE9PX01BTllfUkVRVUVTVFMARUFSTFlfSElOVFMAVU5BVkFJTEFCTEVfRk9SX0xFR0FMX1JFQVNPTlMAT1BUSU9OUwBTV0lUQ0hJTkdfUFJPVE9DT0xTAFZBUklBTlRfQUxTT19ORUdPVElBVEVTAE1VTFRJUExFX0NIT0lDRVMASU5URVJOQUxfU0VSVkVSX0VSUk9SAFdFQl9TRVJWRVJfVU5LTk9XTl9FUlJPUgBSQUlMR1VOX0VSUk9SAElERU5USVRZX1BST1ZJREVSX0FVVEhFTlRJQ0FUSU9OX0VSUk9SAFNTTF9DRVJUSUZJQ0FURV9FUlJPUgBJTlZBTElEX1hfRk9SV0FSREVEX0ZPUgBTRVRfUEFSQU1FVEVSAEdFVF9QQVJBTUVURVIASFBFX1VTRVIAU0VFX09USEVSAEhQRV9DQl9DSFVOS19IRUFERVIATUtDQUxFTkRBUgBTRVRVUABXRUJfU0VSVkVSX0lTX0RPV04AVEVBUkRPV04ASFBFX0NMT1NFRF9DT05ORUNUSU9OAEhFVVJJU1RJQ19FWFBJUkFUSU9OAERJU0NPTk5FQ1RFRF9PUEVSQVRJT04ATk9OX0FVVEhPUklUQVRJVkVfSU5GT1JNQVRJT04ASFBFX0lOVkFMSURfVkVSU0lPTgBIUEVfQ0JfTUVTU0FHRV9CRUdJTgBTSVRFX0lTX0ZST1pFTgBIUEVfSU5WQUxJRF9IRUFERVJfVE9LRU4ASU5WQUxJRF9UT0tFTgBGT1JCSURERU4ARU5IQU5DRV9ZT1VSX0NBTE0ASFBFX0lOVkFMSURfVVJMAEJMT0NLRURfQllfUEFSRU5UQUxfQ09OVFJPTABNS0NPTABBQ0wASFBFX0lOVEVSTkFMAFJFUVVFU1RfSEVBREVSX0ZJRUxEU19UT09fTEFSR0VfVU5PRkZJQ0lBTABIUEVfT0sAVU5MSU5LAFVOTE9DSwBQUkkAUkVUUllfV0lUSABIUEVfSU5WQUxJRF9DT05URU5UX0xFTkdUSABIUEVfVU5FWFBFQ1RFRF9DT05URU5UX0xFTkdUSABGTFVTSABQUk9QUEFUQ0gATS1TRUFSQ0gAVVJJX1RPT19MT05HAFBST0NFU1NJTkcATUlTQ0VMTEFORU9VU19QRVJTSVNURU5UX1dBUk5JTkcATUlTQ0VMTEFORU9VU19XQVJOSU5HAEhQRV9JTlZBTElEX1RSQU5TRkVSX0VOQ09ESU5HAEV4cGVjdGVkIENSTEYASFBFX0lOVkFMSURfQ0hVTktfU0laRQBNT1ZFAENPTlRJTlVFAEhQRV9DQl9TVEFUVVNfQ09NUExFVEUASFBFX0NCX0hFQURFUlNfQ09NUExFVEUASFBFX0NCX1ZFUlNJT05fQ09NUExFVEUASFBFX0NCX1VSTF9DT01QTEVURQBIUEVfQ0JfQ0hVTktfQ09NUExFVEUASFBFX0NCX0hFQURFUl9WQUxVRV9DT01QTEVURQBIUEVfQ0JfQ0hVTktfRVhURU5TSU9OX1ZBTFVFX0NPTVBMRVRFAEhQRV9DQl9DSFVOS19FWFRFTlNJT05fTkFNRV9DT01QTEVURQBIUEVfQ0JfTUVTU0FHRV9DT01QTEVURQBIUEVfQ0JfTUVUSE9EX0NPTVBMRVRFAEhQRV9DQl9IRUFERVJfRklFTERfQ09NUExFVEUAREVMRVRFAEhQRV9JTlZBTElEX0VPRl9TVEFURQBJTlZBTElEX1NTTF9DRVJUSUZJQ0FURQBQQVVTRQBOT19SRVNQT05TRQBVTlNVUFBPUlRFRF9NRURJQV9UWVBFAEdPTkUATk9UX0FDQ0VQVEFCTEUAU0VSVklDRV9VTkFWQUlMQUJMRQBSQU5HRV9OT1RfU0FUSVNGSUFCTEUAT1JJR0lOX0lTX1VOUkVBQ0hBQkxFAFJFU1BPTlNFX0lTX1NUQUxFAFBVUkdFAE1FUkdFAFJFUVVFU1RfSEVBREVSX0ZJRUxEU19UT09fTEFSR0UAUkVRVUVTVF9IRUFERVJfVE9PX0xBUkdFAFBBWUxPQURfVE9PX0xBUkdFAElOU1VGRklDSUVOVF9TVE9SQUdFAEhQRV9QQVVTRURfVVBHUkFERQBIUEVfUEFVU0VEX0gyX1VQR1JBREUAU09VUkNFAEFOTk9VTkNFAFRSQUNFAEhQRV9VTkVYUEVDVEVEX1NQQUNFAERFU0NSSUJFAFVOU1VCU0NSSUJFAFJFQ09SRABIUEVfSU5WQUxJRF9NRVRIT0QATk9UX0ZPVU5EAFBST1BGSU5EAFVOQklORABSRUJJTkQAVU5BVVRIT1JJWkVEAE1FVEhPRF9OT1RfQUxMT1dFRABIVFRQX1ZFUlNJT05fTk9UX1NVUFBPUlRFRABBTFJFQURZX1JFUE9SVEVEAEFDQ0VQVEVEAE5PVF9JTVBMRU1FTlRFRABMT09QX0RFVEVDVEVEAEhQRV9DUl9FWFBFQ1RFRABIUEVfTEZfRVhQRUNURUQAQ1JFQVRFRABJTV9VU0VEAEhQRV9QQVVTRUQAVElNRU9VVF9PQ0NVUkVEAFBBWU1FTlRfUkVRVUlSRUQAUFJFQ09ORElUSU9OX1JFUVVJUkVEAFBST1hZX0FVVEhFTlRJQ0FUSU9OX1JFUVVJUkVEAE5FVFdPUktfQVVUSEVOVElDQVRJT05fUkVRVUlSRUQATEVOR1RIX1JFUVVJUkVEAFNTTF9DRVJUSUZJQ0FURV9SRVFVSVJFRABVUEdSQURFX1JFUVVJUkVEAFBBR0VfRVhQSVJFRABQUkVDT05ESVRJT05fRkFJTEVEAEVYUEVDVEFUSU9OX0ZBSUxFRABSRVZBTElEQVRJT05fRkFJTEVEAFNTTF9IQU5EU0hBS0VfRkFJTEVEAExPQ0tFRABUUkFOU0ZPUk1BVElPTl9BUFBMSUVEAE5PVF9NT0RJRklFRABOT1RfRVhURU5ERUQAQkFORFdJRFRIX0xJTUlUX0VYQ0VFREVEAFNJVEVfSVNfT1ZFUkxPQURFRABIRUFEAEV4cGVjdGVkIEhUVFAvAABeEwAAJhMAADAQAADwFwAAnRMAABUSAAA5FwAA8BIAAAoQAAB1EgAArRIAAIITAABPFAAAfxAAAKAVAAAjFAAAiRIAAIsUAABNFQAA1BEAAM8UAAAQGAAAyRYAANwWAADBEQAA4BcAALsUAAB0FAAAfBUAAOUUAAAIFwAAHxAAAGUVAACjFAAAKBUAAAIVAACZFQAALBAAAIsZAABPDwAA1A4AAGoQAADOEAAAAhcAAIkOAABuEwAAHBMAAGYUAABWFwAAwRMAAM0TAABsEwAAaBcAAGYXAABfFwAAIhMAAM4PAABpDgAA2A4AAGMWAADLEwAAqg4AACgXAAAmFwAAxRMAAF0WAADoEQAAZxMAAGUTAADyFgAAcxMAAB0XAAD5FgAA8xEAAM8OAADOFQAADBIAALMRAAClEQAAYRAAADIXAAC7EwAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEBAgEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQABAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAgMCAgICAgAAAgIAAgIAAgICAgICAgICAgAEAAAAAAACAgICAgICAgICAgICAgICAgICAgICAgICAgAAAAICAgICAgICAgICAgICAgICAgICAgICAgICAgICAAIAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAIAAgICAgIAAAICAAICAAICAgICAgICAgIAAwAEAAAAAgICAgICAgICAgICAgICAgICAgICAgICAgIAAAACAgICAgICAgICAgICAgICAgICAgICAgICAgICAgACAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABsb3NlZWVwLWFsaXZlAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQABAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQEBAQEBAQEBAQEBAgEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEAAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQFjaHVua2VkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAQABAQEBAQAAAQEAAQEAAQEBAQEBAQEBAQAAAAAAAAABAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQAAAAEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAAEAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGVjdGlvbmVudC1sZW5ndGhvbnJveHktY29ubmVjdGlvbgAAAAAAAAAAAAAAAAAAAHJhbnNmZXItZW5jb2RpbmdwZ3JhZGUNCg0KDQpTTQ0KDQpUVFAvQ0UvVFNQLwAAAAAAAAAAAAAAAAECAAEDAAAAAAAAAAAAAAAAAAAAAAAABAEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEAAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEAAAAAAAAAAAABAgABAwAAAAAAAAAAAAAAAAAAAAAAAAQBAQUBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAAEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAAAAAAAAAAAAAQAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAQEAAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAAEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQABAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQAAAAAAAAAAAAABAAACAAAAAAAAAAAAAAAAAAAAAAAAAwQAAAQEBAQEBAQEBAQEBQQEBAQEBAQEBAQEBAAEAAYHBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEAAQABAAEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAQAAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAAAAAAAAAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAEAAAAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAgAAAAACAAAAAAAAAAAAAAAAAAAAAAADAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwAAAAAAAAMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE5PVU5DRUVDS09VVE5FQ1RFVEVDUklCRUxVU0hFVEVBRFNFQVJDSFJHRUNUSVZJVFlMRU5EQVJWRU9USUZZUFRJT05TQ0hTRUFZU1RBVENIR0VPUkRJUkVDVE9SVFJDSFBBUkFNRVRFUlVSQ0VCU0NSSUJFQVJET1dOQUNFSU5ETktDS1VCU0NSSUJFSFRUUC9BRFRQLw=='; - return llhttp_simdWasm; -} + if (err) { + assert(client[kRunning] <= 1, 'pipeline should only contain this request'); + abort(err); + } + } + } -var client; -var hasRequiredClient; + clientH1 = connectH1; + return clientH1; +} -function requireClient () { - if (hasRequiredClient) return client; - hasRequiredClient = 1; +var clientH2; +var hasRequiredClientH2; - /* global WebAssembly */ +function requireClientH2 () { + if (hasRequiredClientH2) return clientH2; + hasRequiredClientH2 = 1; const assert = require$$0$3; - const net = require$$0$4; - const http = require$$2$1; - const { pipeline } = require$$0$5; - const util = requireUtil$7(); - const timers = requireTimers(); - const Request = requireRequest$1(); - const DispatcherBase = requireDispatcherBase(); + const { pipeline } = require$$0$4; + const util = requireUtil$8(); const { RequestContentLengthMismatchError, - ResponseContentLengthMismatchError, - InvalidArgumentError, RequestAbortedError, - HeadersTimeoutError, - HeadersOverflowError, SocketError, - InformationalError, - BodyTimeoutError, - HTTPParserError, - ResponseExceededMaxSizeError, - ClientDestroyedError + InformationalError } = requireErrors(); - const buildConnector = requireConnect(); const { kUrl, kReset, - kServerName, kClient, - kBusy, - kParser, - kConnect, - kBlocking, - kResuming, kRunning, kPending, - kSize, - kWriting, kQueue, - kConnected, - kConnecting, - kNeedDrain, - kNoRef, - kKeepAliveDefaultTimeout, - kHostHeader, kPendingIdx, kRunningIdx, kError, - kPipelining, kSocket, - kKeepAliveTimeoutValue, - kMaxHeadersSize, - kKeepAliveMaxTimeout, - kKeepAliveTimeoutThreshold, - kHeadersTimeout, - kBodyTimeout, kStrictContentLength, - kConnector, - kMaxRedirections, - kMaxRequests, - kCounter, - kClose, - kDestroy, - kDispatch, - kInterceptors, - kLocalAddress, - kMaxResponseSize, - kHTTPConnVersion, - // HTTP2 - kHost, + kOnError, + kMaxConcurrentStreams, kHTTP2Session, - kHTTP2SessionState, - kHTTP2BuildRequest, - kHTTP2CopyHeaders, - kHTTP1BuildRequest + kResume, + kSize, + kHTTPContext } = requireSymbols$4(); + const kOpenStreams = Symbol('open streams'); + + let extractBody; + + // Experimental + let h2ExperimentalWarned = false; + /** @type {import('http2')} */ let http2; try { - http2 = require('http2'); + http2 = require('node:http2'); } catch { // @ts-ignore http2 = { constants: {} }; @@ -8729,1102 +10265,1378 @@ function requireClient () { } } = http2; - // Experimental - let h2ExperimentalWarned = false; + function parseH2Headers (headers) { + const result = []; - const FastBuffer = Buffer[Symbol.species]; + for (const [name, value] of Object.entries(headers)) { + // h2 may concat the header value by array + // e.g. Set-Cookie + if (Array.isArray(value)) { + for (const subvalue of value) { + // we need to provide each header value of header name + // because the headers handler expect name-value pair + result.push(Buffer.from(name), Buffer.from(subvalue)); + } + } else { + result.push(Buffer.from(name), Buffer.from(value)); + } + } - const kClosedResolve = Symbol('kClosedResolve'); + return result + } - const channels = {}; + async function connectH2 (client, socket) { + client[kSocket] = socket; - try { - const diagnosticsChannel = require('diagnostics_channel'); - channels.sendHeaders = diagnosticsChannel.channel('undici:client:sendHeaders'); - channels.beforeConnect = diagnosticsChannel.channel('undici:client:beforeConnect'); - channels.connectError = diagnosticsChannel.channel('undici:client:connectError'); - channels.connected = diagnosticsChannel.channel('undici:client:connected'); - } catch { - channels.sendHeaders = { hasSubscribers: false }; - channels.beforeConnect = { hasSubscribers: false }; - channels.connectError = { hasSubscribers: false }; - channels.connected = { hasSubscribers: false }; - } + if (!h2ExperimentalWarned) { + h2ExperimentalWarned = true; + process.emitWarning('H2 support is experimental, expect them to change at any time.', { + code: 'UNDICI-H2' + }); + } - /** - * @type {import('../types/client').default} - */ - class Client extends DispatcherBase { - /** - * - * @param {string|URL} url - * @param {import('../types/client').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, - maxRequestsPerClient, - localAddress, - maxResponseSize, - autoSelectFamily, - autoSelectFamilyAttemptTimeout, - // h2 - allowH2, - maxConcurrentStreams - } = {}) { - super(); + const session = http2.connect(client[kUrl], { + createConnection: () => socket, + peerMaxConcurrentStreams: client[kMaxConcurrentStreams] + }); - if (keepAlive !== undefined) { - throw new InvalidArgumentError('unsupported keepAlive, use pipelining=0 instead') - } + session[kOpenStreams] = 0; + session[kClient] = client; + session[kSocket] = socket; - if (socketTimeout !== undefined) { - throw new InvalidArgumentError('unsupported socketTimeout, use headersTimeout & bodyTimeout instead') - } + 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]: client } = this; + const { [kSocket]: socket } = client; - if (requestTimeout !== undefined) { - throw new InvalidArgumentError('unsupported requestTimeout, use headersTimeout & bodyTimeout instead') - } + const err = this[kSocket][kError] || this[kError] || new SocketError('closed', util.getSocketInfo(socket)); - if (idleTimeout !== undefined) { - throw new InvalidArgumentError('unsupported idleTimeout, use keepAliveTimeout instead') - } + client[kHTTP2Session] = null; - if (maxKeepAliveTimeout !== undefined) { - throw new InvalidArgumentError('unsupported maxKeepAliveTimeout, use keepAliveMaxTimeout instead') - } + if (client.destroyed) { + assert(client[kPending] === 0); - if (maxHeaderSize != null && !Number.isFinite(maxHeaderSize)) { - throw new InvalidArgumentError('invalid maxHeaderSize') + // Fail entire queue. + const requests = client[kQueue].splice(client[kRunningIdx]); + for (let i = 0; i < requests.length; i++) { + const request = requests[i]; + util.errorRequest(client, request, err); + } } + }); - if (socketPath != null && typeof socketPath !== 'string') { - throw new InvalidArgumentError('invalid socketPath') - } + session.unref(); - if (connectTimeout != null && (!Number.isFinite(connectTimeout) || connectTimeout < 0)) { - throw new InvalidArgumentError('invalid connectTimeout') - } + client[kHTTP2Session] = session; + socket[kHTTP2Session] = session; - if (keepAliveTimeout != null && (!Number.isFinite(keepAliveTimeout) || keepAliveTimeout <= 0)) { - throw new InvalidArgumentError('invalid keepAliveTimeout') - } + util.addListener(socket, 'error', function (err) { + assert(err.code !== 'ERR_TLS_CERT_ALTNAME_INVALID'); - if (keepAliveMaxTimeout != null && (!Number.isFinite(keepAliveMaxTimeout) || keepAliveMaxTimeout <= 0)) { - throw new InvalidArgumentError('invalid keepAliveMaxTimeout') - } + this[kError] = err; - if (keepAliveTimeoutThreshold != null && !Number.isFinite(keepAliveTimeoutThreshold)) { - throw new InvalidArgumentError('invalid keepAliveTimeoutThreshold') - } + this[kClient][kOnError](err); + }); - if (headersTimeout != null && (!Number.isInteger(headersTimeout) || headersTimeout < 0)) { - throw new InvalidArgumentError('headersTimeout must be a positive integer or zero') - } + util.addListener(socket, 'end', function () { + util.destroy(this, new SocketError('other side closed', util.getSocketInfo(this))); + }); - if (bodyTimeout != null && (!Number.isInteger(bodyTimeout) || bodyTimeout < 0)) { - throw new InvalidArgumentError('bodyTimeout must be a positive integer or zero') - } + util.addListener(socket, 'close', function () { + const err = this[kError] || new SocketError('closed', util.getSocketInfo(this)); - if (connect != null && typeof connect !== 'function' && typeof connect !== 'object') { - throw new InvalidArgumentError('connect must be a function or an object') - } + client[kSocket] = null; - if (maxRedirections != null && (!Number.isInteger(maxRedirections) || maxRedirections < 0)) { - throw new InvalidArgumentError('maxRedirections must be a positive number') + if (this[kHTTP2Session] != null) { + this[kHTTP2Session].destroy(err); } - if (maxRequestsPerClient != null && (!Number.isInteger(maxRequestsPerClient) || maxRequestsPerClient < 0)) { - throw new InvalidArgumentError('maxRequestsPerClient must be a positive number') - } + client[kPendingIdx] = client[kRunningIdx]; - if (localAddress != null && (typeof localAddress !== 'string' || net.isIP(localAddress) === 0)) { - throw new InvalidArgumentError('localAddress must be valid string IP address') - } + assert(client[kRunning] === 0); - if (maxResponseSize != null && (!Number.isInteger(maxResponseSize) || maxResponseSize < -1)) { - throw new InvalidArgumentError('maxResponseSize must be a positive number') - } + client.emit('disconnect', client[kUrl], [client], err); - if ( - autoSelectFamilyAttemptTimeout != null && - (!Number.isInteger(autoSelectFamilyAttemptTimeout) || autoSelectFamilyAttemptTimeout < -1) - ) { - throw new InvalidArgumentError('autoSelectFamilyAttemptTimeout must be a positive number') - } + client[kResume](); + }); - // h2 - if (allowH2 != null && typeof allowH2 !== 'boolean') { - throw new InvalidArgumentError('allowH2 must be a valid boolean value') - } + let closed = false; + socket.on('close', () => { + closed = true; + }); - if (maxConcurrentStreams != null && (typeof maxConcurrentStreams !== 'number' || maxConcurrentStreams < 1)) { - throw new InvalidArgumentError('maxConcurrentStreams must be a possitive integer, greater than 0') + return { + version: 'h2', + defaultPipelining: Infinity, + write (...args) { + return writeH2(client, ...args) + }, + resume () { + resumeH2(client); + }, + destroy (err, callback) { + if (closed) { + queueMicrotask(callback); + } else { + // Destroying the socket will trigger the session close + socket.destroy(err).on('close', callback); + } + }, + get destroyed () { + return socket.destroyed + }, + busy () { + return false } + } + } - if (typeof connect !== 'function') { - connect = buildConnector({ - ...tls, - maxCachedSessions, - allowH2, - socketPath, - timeout: connectTimeout, - ...(util.nodeHasAutoSelectFamily && autoSelectFamily ? { autoSelectFamily, autoSelectFamilyAttemptTimeout } : undefined), - ...connect - }); + 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(); } + } + } - this[kInterceptors] = interceptors && interceptors.Client && Array.isArray(interceptors.Client) - ? interceptors.Client - : [createRedirectInterceptor({ maxRedirections })]; - this[kUrl] = util.parseOrigin(url); - this[kConnector] = connect; - this[kSocket] = null; - this[kPipelining] = pipelining != null ? pipelining : 1; - this[kMaxHeadersSize] = maxHeaderSize || http.maxHeaderSize; - this[kKeepAliveDefaultTimeout] = keepAliveTimeout == null ? 4e3 : keepAliveTimeout; - this[kKeepAliveMaxTimeout] = keepAliveMaxTimeout == null ? 600e3 : keepAliveMaxTimeout; - this[kKeepAliveTimeoutThreshold] = keepAliveTimeoutThreshold == null ? 1e3 : keepAliveTimeoutThreshold; - this[kKeepAliveTimeoutValue] = this[kKeepAliveDefaultTimeout]; - this[kServerName] = null; - this[kLocalAddress] = localAddress != null ? localAddress : null; - this[kResuming] = 0; // 0, idle, 1, scheduled, 2 resuming - this[kNeedDrain] = 0; // 0, idle, 1, scheduled, 2 resuming - this[kHostHeader] = `host: ${this[kUrl].hostname}${this[kUrl].port ? `:${this[kUrl].port}` : ''}\r\n`; - this[kBodyTimeout] = bodyTimeout != null ? bodyTimeout : 300e3; - this[kHeadersTimeout] = headersTimeout != null ? headersTimeout : 300e3; - this[kStrictContentLength] = strictContentLength == null ? true : strictContentLength; - this[kMaxRedirections] = maxRedirections; - this[kMaxRequests] = maxRequestsPerClient; - this[kClosedResolve] = null; - this[kMaxResponseSize] = maxResponseSize > -1 ? maxResponseSize : -1; - this[kHTTPConnVersion] = 'h1'; + function onHttp2SessionError (err) { + assert(err.code !== 'ERR_TLS_CERT_ALTNAME_INVALID'); - // HTTP/2 - this[kHTTP2Session] = null; - this[kHTTP2SessionState] = !allowH2 - ? null - : { - // streams: null, // Fixed queue of streams - For future support of `push` - openStreams: 0, // Keep track of them to decide wether or not unref the session - maxConcurrentStreams: maxConcurrentStreams != null ? maxConcurrentStreams : 100 // Max peerConcurrentStreams for a Node h2 server - }; - this[kHost] = `${this[kUrl].hostname}${this[kUrl].port ? `:${this[kUrl].port}` : ''}`; + this[kSocket][kError] = err; + this[kClient][kOnError](err); + } - // kQueue is built up of 3 sections separated by - // the kRunningIdx and kPendingIdx indices. - // | complete | running | pending | - // ^ kRunningIdx ^ kPendingIdx ^ kQueue.length - // kRunningIdx points to the first running element. - // kPendingIdx points to the first pending element. - // This implements a fast queue with an amortized - // time of O(1). - - this[kQueue] = []; - this[kRunningIdx] = 0; - this[kPendingIdx] = 0; - } - - get pipelining () { - return this[kPipelining] + 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); } + } - set pipelining (value) { - this[kPipelining] = value; - resume(this, true); - } + function onHttp2SessionEnd () { + const err = new SocketError('other side closed', util.getSocketInfo(this[kSocket])); + this.destroy(err); + util.destroy(this[kSocket], err); + } - get [kPending] () { - return this[kQueue].length - this[kPendingIdx] - } + /** + * This is the root cause of #3011 + * We need to handle GOAWAY frames properly, and trigger the session close + * along with the socket right away + */ + function onHTTP2GoAway (code) { + // We cannot recover, so best to close the session and the socket + const err = this[kError] || new SocketError(`HTTP/2: "GOAWAY" frame received with code ${code}`, util.getSocketInfo(this)); + const client = this[kClient]; - get [kRunning] () { - return this[kPendingIdx] - this[kRunningIdx] - } + client[kSocket] = null; + client[kHTTPContext] = null; - get [kSize] () { - return this[kQueue].length - this[kRunningIdx] + if (this[kHTTP2Session] != null) { + this[kHTTP2Session].destroy(err); + this[kHTTP2Session] = null; } - get [kConnected] () { - return !!this[kSocket] && !this[kConnecting] && !this[kSocket].destroyed - } + util.destroy(this[kSocket], err); - get [kBusy] () { - const socket = this[kSocket]; - return ( - (socket && (socket[kReset] || socket[kWriting] || socket[kBlocking])) || - (this[kSize] >= (this[kPipelining] || 1)) || - this[kPending] > 0 - ) + // Fail head of pipeline. + 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]; } - /* istanbul ignore: only used for test */ - [kConnect] (cb) { - connect(this); - this.once('connect', cb); - } + assert(client[kRunning] === 0); - [kDispatch] (opts, handler) { - const origin = opts.origin || this[kUrl].origin; + client.emit('disconnect', client[kUrl], [client], err); - const request = this[kHTTPConnVersion] === 'h2' - ? Request[kHTTP2BuildRequest](origin, opts, handler) - : Request[kHTTP1BuildRequest](origin, opts, handler); + client[kResume](); + } - this[kQueue].push(request); - if (this[kResuming]) ; else if (util.bodyLength(request.body) == null && util.isIterable(request.body)) { - // Wait a tick in case stream/iterator is ended in the same tick. - this[kResuming] = 1; - process.nextTick(resume, this); - } else { - resume(this, true); - } + // https://www.rfc-editor.org/rfc/rfc7230#section-3.3.2 + function shouldSendContentLength (method) { + return method !== 'GET' && method !== 'HEAD' && method !== 'OPTIONS' && method !== 'TRACE' && method !== 'CONNECT' + } - if (this[kResuming] && this[kNeedDrain] !== 2 && this[kBusy]) { - this[kNeedDrain] = 2; - } + function writeH2 (client, request) { + const session = client[kHTTP2Session]; + const { method, path, host, upgrade, expectContinue, signal, headers: reqHeaders } = request; + let { body } = request; - return this[kNeedDrain] < 2 + if (upgrade) { + util.errorRequest(client, request, new Error('Upgrade not supported for H2')); + return false } - async [kClose] () { - // TODO: for H2 we need to gracefully flush the remaining enqueued - // request and close each stream. - return new Promise((resolve) => { - if (!this[kSize]) { - resolve(null); - } else { - this[kClosedResolve] = resolve; - } - }) - } + const headers = {}; + for (let n = 0; n < reqHeaders.length; n += 2) { + const key = reqHeaders[n + 0]; + const val = reqHeaders[n + 1]; - 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]; - errorRequest(this, request, err); + 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; + } + } - const callback = () => { - if (this[kClosedResolve]) { - // TODO (fix): Should we error here with ClientDestroyedError? - this[kClosedResolve](); - this[kClosedResolve] = null; - } - resolve(); - }; + /** @type {import('node:http2').ClientHttp2Stream} */ + let stream; - if (this[kHTTP2Session] != null) { - util.destroy(this[kHTTP2Session], err); - this[kHTTP2Session] = null; - this[kHTTP2SessionState] = null; - } + const { hostname, port } = client[kUrl]; - if (!this[kSocket]) { - queueMicrotask(callback); - } else { - util.destroy(this[kSocket].on('close', callback), err); - } + headers[HTTP2_HEADER_AUTHORITY] = host || `${hostname}${port ? `:${port}` : ''}`; + headers[HTTP2_HEADER_METHOD] = method; - resume(this); - }) - } - } + const abort = (err) => { + if (request.aborted || request.completed) { + return + } - function onHttp2SessionError (err) { - assert(err.code !== 'ERR_TLS_CERT_ALTNAME_INVALID'); + err = err || new RequestAbortedError(); - this[kSocket][kError] = err; + util.errorRequest(client, request, err); - onError(this[kClient], err); - } + if (stream != null) { + util.destroy(stream, err); + } - function onHttp2FrameError (type, code, id) { - const err = new InformationalError(`HTTP/2: "frameError" received - type ${type}, code ${code}`); + // We do not destroy the socket as we can continue using the session + // the stream get's destroyed and the session remains to create new streams + util.destroy(body, err); + client[kQueue][client[kRunningIdx]++] = null; + client[kResume](); + }; - if (id === 0) { - this[kSocket][kError] = err; - onError(this[kClient], err); + try { + // We are already connected, streams are pending. + // We can call on connect, and wait for abort + request.onConnect(abort); + } catch (err) { + util.errorRequest(client, request, err); } - } - - function onHttp2SessionEnd () { - util.destroy(this, new SocketError('other side closed')); - util.destroy(this[kSocket], new SocketError('other side closed')); - } - function onHTTP2GoAway (code) { - const client = this[kClient]; - const err = new InformationalError(`HTTP/2: "GOAWAY" frame received with code ${code}`); - client[kSocket] = null; - client[kHTTP2Session] = null; + if (request.aborted) { + return false + } - if (client.destroyed) { - assert(this[kPending] === 0); + if (method === 'CONNECT') { + session.ref(); + // We are already connected, streams are pending, first request + // will create a new stream. We trigger a request to create the stream and wait until + // `ready` event is triggered + // We disabled endStream to allow the user to write to the stream + stream = session.request(headers, { endStream: false, signal }); - // Fail entire queue. - const requests = client[kQueue].splice(client[kRunningIdx]); - for (let i = 0; i < requests.length; i++) { - const request = requests[i]; - errorRequest(this, request, err); + 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; + }); } - } else if (client[kRunning] > 0) { - // Fail head of pipeline. - const request = client[kQueue][client[kRunningIdx]]; - client[kQueue][client[kRunningIdx]++] = null; - errorRequest(client, request, err); + stream.once('close', () => { + session[kOpenStreams] -= 1; + if (session[kOpenStreams] === 0) session.unref(); + }); + + return true } - client[kPendingIdx] = client[kRunningIdx]; + // https://tools.ietf.org/html/rfc7540#section-8.3 + // :path and :scheme headers must be omitted when sending CONNECT - assert(client[kRunning] === 0); + headers[HTTP2_HEADER_PATH] = path; + headers[HTTP2_HEADER_SCHEME] = 'https'; + + // https://tools.ietf.org/html/rfc7231#section-4.3.1 + // https://tools.ietf.org/html/rfc7231#section-4.3.2 + // https://tools.ietf.org/html/rfc7231#section-4.3.5 + + // Sending a payload body on a request that does not + // expect it can cause undefined behavior on some + // servers and corrupt connection state. Do not + // re-use the connection for further requests. - client.emit('disconnect', - client[kUrl], - [client], - err + const expectsPayload = ( + method === 'PUT' || + method === 'POST' || + method === 'PATCH' ); - resume(client); - } + if (body && typeof body.read === 'function') { + // Try to read EOF in order to get length. + body.read(0); + } - const constants = requireConstants$2(); - const createRedirectInterceptor = requireRedirectInterceptor(); - const EMPTY_BUF = Buffer.alloc(0); + let contentLength = util.bodyLength(body); - async function lazyllhttp () { - const llhttpWasmData = process.env.JEST_WORKER_ID ? requireLlhttpWasm() : undefined; + if (util.isFormDataLike(body)) { + extractBody ??= requireBody().extractBody; - let mod; - try { - mod = await WebAssembly.compile(Buffer.from(requireLlhttp_simdWasm(), 'base64')); - } catch (e) { - /* istanbul ignore next */ + const [bodyStream, contentType] = extractBody(body); + headers['content-type'] = contentType; - // We could check if the error was caused by the simd option not - // being enabled, but the occurring of this other error - // * https://github.com/emscripten-core/emscripten/issues/11495 - // got me to remove that check to avoid breaking Node 12. - mod = await WebAssembly.compile(Buffer.from(llhttpWasmData || requireLlhttpWasm(), 'base64')); + body = bodyStream.stream; + contentLength = bodyStream.length; } - return await WebAssembly.instantiate(mod, { - env: { - /* eslint-disable camelcase */ + if (contentLength == null) { + contentLength = request.contentLength; + } - wasm_on_url: (p, at, len) => { - /* istanbul ignore next */ - return 0 - }, - wasm_on_status: (p, at, len) => { - assert.strictEqual(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.strictEqual(currentParser.ptr, p); - return currentParser.onMessageBegin() || 0 - }, - wasm_on_header_field: (p, at, len) => { - assert.strictEqual(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.strictEqual(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.strictEqual(currentParser.ptr, p); - return currentParser.onHeadersComplete(statusCode, Boolean(upgrade), Boolean(shouldKeepAlive)) || 0 - }, - wasm_on_body: (p, at, len) => { - assert.strictEqual(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.strictEqual(currentParser.ptr, p); - return currentParser.onMessageComplete() || 0 - } + if (contentLength === 0 || !expectsPayload) { + // https://tools.ietf.org/html/rfc7230#section-3.3.2 + // A user agent SHOULD NOT send a Content-Length header field when + // the request message does not contain a payload body and the method + // semantics do not anticipate such a body. - /* eslint-enable camelcase */ + contentLength = null; + } + + // https://github.com/nodejs/undici/issues/2046 + // A user agent may send a Content-Length header with 0 value, this should be allowed. + if (shouldSendContentLength(method) && contentLength > 0 && request.contentLength != null && request.contentLength !== contentLength) { + if (client[kStrictContentLength]) { + util.errorRequest(client, request, new RequestContentLengthMismatchError()); + return false } - }) - } - let llhttpInstance = null; - let llhttpPromise = lazyllhttp(); - llhttpPromise.catch(); + process.emitWarning(new RequestContentLengthMismatchError()); + } - let currentParser = null; - let currentBufferRef = null; - let currentBufferSize = 0; - let currentBufferPtr = null; + if (contentLength != null) { + assert(body, 'no body must not have content length'); + headers[HTTP2_HEADER_CONTENT_LENGTH] = `${contentLength}`; + } - const TIMEOUT_HEADERS = 1; - const TIMEOUT_BODY = 2; - const TIMEOUT_IDLE = 3; + session.ref(); - class Parser { - constructor (client, socket, { exports: exports$1 }) { - assert(Number.isFinite(client[kMaxHeadersSize]) && client[kMaxHeadersSize] > 0); + const shouldEndStream = method === 'GET' || method === 'HEAD' || body === null; + if (expectContinue) { + headers[HTTP2_HEADER_EXPECT] = '100-continue'; + stream = session.request(headers, { endStream: shouldEndStream, signal }); - this.llhttp = exports$1; - 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); + stream.once('continue', writeBodyH2); + } else { + stream = session.request(headers, { + endStream: shouldEndStream, + signal + }); + writeBodyH2(); + } - this.bytesRead = 0; + // Increment counter as we have new streams open + ++session[kOpenStreams]; - this.keepAlive = ''; - this.contentLength = ''; - this.connection = ''; - this.maxResponseSize = client[kMaxResponseSize]; - } + stream.once('response', headers => { + const { [HTTP2_HEADER_STATUS]: statusCode, ...realHeaders } = headers; + request.onResponseStarted(); - setTimeout (value, type) { - this.timeoutType = type; - if (value !== this.timeoutValue) { - timers.clearTimeout(this.timeout); - if (value) { - this.timeout = timers.setTimeout(onParserTimeout, value, this); - // istanbul ignore else: only for jest - if (this.timeout.unref) { - this.timeout.unref(); - } - } else { - this.timeout = null; - } - this.timeoutValue = value; - } else if (this.timeout) { - // istanbul ignore else: only for jest - if (this.timeout.refresh) { - this.timeout.refresh(); - } + // Due to the stream nature, it is possible we face a race condition + // where the stream has been assigned, but the request has been aborted + // the request remains in-flight and headers hasn't been received yet + // for those scenarios, best effort is to destroy the stream immediately + // as there's no value to keep it open. + if (request.aborted) { + const err = new RequestAbortedError(); + util.errorRequest(client, request, err); + util.destroy(stream, err); + return } - } - resume () { - if (this.socket.destroyed || !this.paused) { - return + if (request.onHeaders(Number(statusCode), parseH2Headers(realHeaders), stream.resume.bind(stream), '') === false) { + stream.pause(); } - assert(this.ptr != null); - assert(currentParser == null); + stream.on('data', (chunk) => { + if (request.onData(chunk) === false) { + stream.pause(); + } + }); + }); - this.llhttp.llhttp_resume(this.ptr); + stream.once('end', () => { + // When state is null, it means we haven't consumed body and the stream still do not have + // a state. + // Present specially when using pipeline or stream + if (stream.state?.state == null || stream.state.state < 6) { + request.onComplete([]); + } - assert(this.timeoutType === TIMEOUT_BODY); - if (this.timeout) { - // istanbul ignore else: only for jest - if (this.timeout.refresh) { - this.timeout.refresh(); - } + if (session[kOpenStreams] === 0) { + // Stream is closed or half-closed-remote (6), decrement counter and cleanup + // It does not have sense to continue working with the stream as we do not + // have yet RST_STREAM support on client-side + + session.unref(); } - this.paused = false; - this.execute(this.socket.read() || EMPTY_BUF); // Flush parser. - this.readMore(); - } + abort(new InformationalError('HTTP/2: stream half-closed (remote)')); + client[kQueue][client[kRunningIdx]++] = null; + client[kPendingIdx] = client[kRunningIdx]; + client[kResume](); + }); - readMore () { - while (!this.paused && this.ptr) { - const chunk = this.socket.read(); - if (chunk === null) { - break - } - this.execute(chunk); + stream.once('close', () => { + session[kOpenStreams] -= 1; + if (session[kOpenStreams] === 0) { + session.unref(); } - } + }); - execute (data) { - assert(this.ptr != null); - assert(currentParser == null); - assert(!this.paused); + stream.once('error', function (err) { + abort(err); + }); - const { socket, llhttp } = this; + stream.once('frameError', (type, code) => { + abort(new InformationalError(`HTTP/2: "frameError" received - type ${type}, code ${code}`)); + }); - if (data.length > currentBufferSize) { - if (currentBufferPtr) { - llhttp.free(currentBufferPtr); - } - currentBufferSize = Math.ceil(data.length / 4096) * 4096; - currentBufferPtr = llhttp.malloc(currentBufferSize); - } + // stream.on('aborted', () => { + // // TODO(HTTP/2): Support aborted + // }) - new Uint8Array(llhttp.memory.buffer, currentBufferPtr, currentBufferSize).set(data); + // stream.on('timeout', () => { + // // TODO(HTTP/2): Support timeout + // }) - // Call `execute` on the wasm parser. - // We pass the `llhttp_parser` pointer address, the pointer address of buffer view data, - // and finally the length of bytes to parse. - // The return value is an error code or `constants.ERROR.OK`. - try { - let ret; + // stream.on('push', headers => { + // // TODO(HTTP/2): Support push + // }) - try { - currentBufferRef = data; - currentParser = this; - ret = llhttp.llhttp_execute(this.ptr, currentBufferPtr, data.length); - /* eslint-disable-next-line no-useless-catch */ - } catch (err) { - /* istanbul ignore next: difficult to make a test case for */ - throw err - } finally { - currentParser = null; - currentBufferRef = null; - } + // stream.on('trailers', headers => { + // // TODO(HTTP/2): Support trailers + // }) - const offset = llhttp.llhttp_get_error_pos(this.ptr) - currentBufferPtr; + return true - if (ret === constants.ERROR.PAUSED_UPGRADE) { - this.onUpgrade(data.slice(offset)); - } else if (ret === constants.ERROR.PAUSED) { - this.paused = true; - socket.unshift(data.slice(offset)); - } else if (ret !== constants.ERROR.OK) { - const ptr = llhttp.llhttp_get_error_reason(this.ptr); - let message = ''; - /* istanbul ignore else: difficult to make a test case for */ - 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() + - ')'; - } - throw new HTTPParserError(message, constants.ERROR[ret], data.slice(offset)) + function writeBodyH2 () { + /* istanbul ignore else: assertion */ + 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 + ); } - } catch (err) { - util.destroy(socket, err); + } 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); } } + } - destroy () { - assert(this.ptr != null); - assert(currentParser == null); + 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(); - this.llhttp.llhttp_free(this.ptr); - this.ptr = null; + request.onBodySent(body); + } - timers.clearTimeout(this.timeout); - this.timeout = null; - this.timeoutValue = null; - this.timeoutType = null; + if (!expectsPayload) { + socket[kReset] = true; + } - this.paused = false; + request.onRequestSent(); + client[kResume](); + } catch (error) { + abort(error); } + } - onStatus (buf) { - this.statusText = buf.toString(); - } + function writeStream (abort, socket, expectsPayload, h2stream, body, client, request, contentLength) { + assert(contentLength !== 0 || client[kRunning] === 0, 'stream body cannot be pipelined'); - onMessageBegin () { - const { socket, client } = this; + // For HTTP/2, is enough to pipe the stream + const pipe = pipeline( + body, + h2stream, + (err) => { + if (err) { + util.destroy(pipe, err); + abort(err); + } else { + util.removeAllListeners(pipe); + request.onRequestSent(); - /* istanbul ignore next: difficult to make a test case for */ - if (socket.destroyed) { - return -1 - } + if (!expectsPayload) { + socket[kReset] = true; + } - const request = client[kQueue][client[kRunningIdx]]; - if (!request) { - return -1 + client[kResume](); + } } + ); + + util.addListener(pipe, 'data', onPipeData); + + function onPipeData (chunk) { + request.onBodySent(chunk); } + } - onHeaderField (buf) { - const len = this.headers.length; + async function writeBlob (abort, h2stream, body, client, request, socket, contentLength, expectsPayload) { + assert(contentLength === body.size, 'blob body must have content length'); - if ((len & 1) === 0) { - this.headers.push(buf); - } else { - this.headers[len - 1] = Buffer.concat([this.headers[len - 1], buf]); + try { + if (contentLength != null && contentLength !== body.size) { + throw new RequestContentLengthMismatchError() } - this.trackHeader(buf.length); - } + const buffer = Buffer.from(await body.arrayBuffer()); - onHeaderValue (buf) { - let len = this.headers.length; + h2stream.cork(); + h2stream.write(buffer); + h2stream.uncork(); + h2stream.end(); - if ((len & 1) === 1) { - this.headers.push(buf); - len += 1; - } else { - this.headers[len - 1] = Buffer.concat([this.headers[len - 1], buf]); - } + request.onBodySent(buffer); + request.onRequestSent(); - const key = this.headers[len - 2]; - if (key.length === 10 && key.toString().toLowerCase() === 'keep-alive') { - this.keepAlive += buf.toString(); - } else if (key.length === 10 && key.toString().toLowerCase() === 'connection') { - this.connection += buf.toString(); - } else if (key.length === 14 && key.toString().toLowerCase() === 'content-length') { - this.contentLength += buf.toString(); + if (!expectsPayload) { + socket[kReset] = true; } - this.trackHeader(buf.length); - } - - trackHeader (len) { - this.headersSize += len; - if (this.headersSize >= this.headersMaxSize) { - util.destroy(this.socket, new HeadersOverflowError()); - } + client[kResume](); + } catch (err) { + abort(err); } + } - onUpgrade (head) { - const { upgrade, client, socket, headers, statusCode } = this; - - assert(upgrade); - - const request = client[kQueue][client[kRunningIdx]]; - assert(request); - - assert(!socket.destroyed); - assert(socket === client[kSocket]); - assert(!this.paused); - assert(request.upgrade || request.method === 'CONNECT'); - - this.statusCode = null; - this.statusText = ''; - this.shouldKeepAlive = null; - - assert(this.headers.length % 2 === 0); - this.headers = []; - this.headersSize = 0; - - socket.unshift(head); - - socket[kParser].destroy(); - socket[kParser] = null; - - socket[kClient] = null; - socket[kError] = null; - socket - .removeListener('error', onSocketError) - .removeListener('readable', onSocketReadable) - .removeListener('end', onSocketEnd) - .removeListener('close', onSocketClose); - - client[kSocket] = null; - client[kQueue][client[kRunningIdx]++] = null; - client.emit('disconnect', client[kUrl], [client], new InformationalError('upgrade')); + async function writeIterable (abort, h2stream, body, client, request, socket, contentLength, expectsPayload) { + assert(contentLength !== 0 || client[kRunning] === 0, 'iterator body cannot be pipelined'); - try { - request.onUpgrade(statusCode, headers, socket); - } catch (err) { - util.destroy(socket, err); + let callback = null; + function onDrain () { + if (callback) { + const cb = callback; + callback = null; + cb(); } - - resume(client); } - onHeadersComplete (statusCode, upgrade, shouldKeepAlive) { - const { client, socket, headers, statusText } = this; - - /* istanbul ignore next: difficult to make a test case for */ - if (socket.destroyed) { - return -1 - } - - const request = client[kQueue][client[kRunningIdx]]; + const waitForDrain = () => new Promise((resolve, reject) => { + assert(callback === null); - /* istanbul ignore next: difficult to make a test case for */ - if (!request) { - return -1 + if (socket[kError]) { + reject(socket[kError]); + } else { + callback = resolve; } + }); - assert(!this.upgrade); - assert(this.statusCode < 200); + h2stream + .on('close', onDrain) + .on('drain', onDrain); - if (statusCode === 100) { - util.destroy(socket, new SocketError('bad response', util.getSocketInfo(socket))); - return -1 - } + try { + // It's up to the user to somehow abort the async iterable. + for await (const chunk of body) { + if (socket[kError]) { + throw socket[kError] + } - /* this can only happen if server is misbehaving */ - if (upgrade && !request.upgrade) { - util.destroy(socket, new SocketError('bad upgrade', util.getSocketInfo(socket))); - return -1 + const res = h2stream.write(chunk); + request.onBodySent(chunk); + if (!res) { + await waitForDrain(); + } } - assert.strictEqual(this.timeoutType, TIMEOUT_HEADERS); + h2stream.end(); - 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') - ); + request.onRequestSent(); - if (this.statusCode >= 200) { - const bodyTimeout = request.bodyTimeout != null - ? request.bodyTimeout - : client[kBodyTimeout]; - this.setTimeout(bodyTimeout, TIMEOUT_BODY); - } else if (this.timeout) { - // istanbul ignore else: only for jest - if (this.timeout.refresh) { - this.timeout.refresh(); - } + if (!expectsPayload) { + socket[kReset] = true; } - if (request.method === 'CONNECT') { - assert(client[kRunning] === 1); - this.upgrade = true; - return 2 - } + client[kResume](); + } catch (err) { + abort(err); + } finally { + h2stream + .off('close', onDrain) + .off('drain', onDrain); + } + } - if (upgrade) { - assert(client[kRunning] === 1); - this.upgrade = true; - return 2 - } + clientH2 = connectH2; + return clientH2; +} - assert(this.headers.length % 2 === 0); - this.headers = []; - this.headersSize = 0; +var redirectHandler; +var hasRequiredRedirectHandler; - if (this.shouldKeepAlive && client[kPipelining]) { - const keepAliveTimeout = this.keepAlive ? util.parseKeepAliveTimeout(this.keepAlive) : null; +function requireRedirectHandler () { + if (hasRequiredRedirectHandler) return redirectHandler; + hasRequiredRedirectHandler = 1; - 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 { - // Stop more requests from being dispatched. - socket[kReset] = true; - } + const util = requireUtil$8(); + const { kBodyUsed } = requireSymbols$4(); + const assert = require$$0$3; + const { InvalidArgumentError } = requireErrors(); + const EE = require$$8; - const pause = request.onHeaders(statusCode, headers, this.resume, statusText) === false; + const redirectableStatusCodes = [300, 301, 302, 303, 307, 308]; - if (request.aborted) { - return -1 - } + const kBody = Symbol('body'); - if (request.method === 'HEAD') { - return 1 - } + class BodyAsyncIterable { + constructor (body) { + this[kBody] = body; + this[kBodyUsed] = false; + } - if (statusCode < 200) { - return 1 - } + async * [Symbol.asyncIterator] () { + assert(!this[kBodyUsed], 'disturbed'); + this[kBodyUsed] = true; + yield * this[kBody]; + } + } - if (socket[kBlocking]) { - socket[kBlocking] = false; - resume(client); + class RedirectHandler { + constructor (dispatch, maxRedirections, opts, handler) { + if (maxRedirections != null && (!Number.isInteger(maxRedirections) || maxRedirections < 0)) { + throw new InvalidArgumentError('maxRedirections must be a positive number') } - return pause ? constants.ERROR.PAUSED : 0 - } - - onBody (buf) { - const { client, socket, statusCode, maxResponseSize } = this; + util.validateHandler(handler, opts.method, opts.upgrade); - if (socket.destroyed) { - return -1 - } + this.dispatch = dispatch; + this.location = null; + this.abort = null; + this.opts = { ...opts, maxRedirections: 0 }; // opts must be a copy + this.maxRedirections = maxRedirections; + this.handler = handler; + this.history = []; + this.redirectionLimitReached = false; - const request = client[kQueue][client[kRunningIdx]]; - assert(request); + if (util.isStream(this.opts.body)) { + // TODO (fix): Provide some way for the user to cache the file to e.g. /tmp + // so that it can be dispatched again? + // TODO (fix): Do we need 100-expect support to provide a way to do this properly? + if (util.bodyLength(this.opts.body) === 0) { + this.opts.body + .on('data', function () { + assert(false); + }); + } - assert.strictEqual(this.timeoutType, TIMEOUT_BODY); - if (this.timeout) { - // istanbul ignore else: only for jest - if (this.timeout.refresh) { - this.timeout.refresh(); + 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') { + // TODO (fix): We can't access ReadableStream internal state + // to determine whether or not it has been disturbed. This is just + // a workaround. + 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) + ) { + // TODO: Should we allow re-using iterable if !this.opts.idempotent + // or through some other flag? + this.opts.body = new BodyAsyncIterable(this.opts.body); } + } - assert(statusCode >= 200); - - if (maxResponseSize > -1 && this.bytesRead + buf.length > maxResponseSize) { - util.destroy(socket, new ResponseExceededMaxSizeError()); - return -1 - } + onConnect (abort) { + this.abort = abort; + this.handler.onConnect(abort, { history: this.history }); + } - this.bytesRead += buf.length; + onUpgrade (statusCode, headers, socket) { + this.handler.onUpgrade(statusCode, headers, socket); + } - if (request.onData(buf) === false) { - return constants.ERROR.PAUSED - } + onError (error) { + this.handler.onError(error); } - onMessageComplete () { - const { client, socket, statusCode, upgrade, headers, contentLength, bytesRead, shouldKeepAlive } = this; + onHeaders (statusCode, headers, resume, statusText) { + this.location = this.history.length >= this.maxRedirections || util.isDisturbed(this.opts.body) + ? null + : parseLocation(statusCode, headers); - if (socket.destroyed && (!statusCode || shouldKeepAlive)) { - return -1 - } + if (this.opts.throwOnMaxRedirect && this.history.length >= this.maxRedirections) { + if (this.request) { + this.request.abort(new Error('max redirects')); + } - if (upgrade) { + this.redirectionLimitReached = true; + this.abort(new Error('max redirects')); return } - const request = client[kQueue][client[kRunningIdx]]; - assert(request); + if (this.opts.origin) { + this.history.push(new URL(this.opts.path, this.opts.origin)); + } - assert(statusCode >= 100); + if (!this.location) { + return this.handler.onHeaders(statusCode, headers, resume, statusText) + } - this.statusCode = null; - this.statusText = ''; - this.bytesRead = 0; - this.contentLength = ''; - this.keepAlive = ''; - this.connection = ''; + const { origin, pathname, search } = util.parseURL(new URL(this.location, this.opts.origin && new URL(this.opts.path, this.opts.origin))); + const path = search ? `${pathname}${search}` : pathname; - assert(this.headers.length % 2 === 0); - this.headers = []; - this.headersSize = 0; + // Remove headers referring to the original URL. + // By default it is Host only, unless it's a 303 (see below), which removes also all Content-* headers. + // https://tools.ietf.org/html/rfc7231#section-6.4 + this.opts.headers = cleanRequestHeaders(this.opts.headers, statusCode === 303, this.opts.origin !== origin); + this.opts.path = path; + this.opts.origin = origin; + this.opts.maxRedirections = 0; + this.opts.query = null; - if (statusCode < 200) { - return + // https://tools.ietf.org/html/rfc7231#section-6.4.4 + // In case of HTTP 303, always replace method to be either HEAD or GET + if (statusCode === 303 && this.opts.method !== 'HEAD') { + this.opts.method = 'GET'; + this.opts.body = null; } + } - /* istanbul ignore next: should be handled by llhttp? */ - if (request.method !== 'HEAD' && contentLength && bytesRead !== parseInt(contentLength, 10)) { - util.destroy(socket, new ResponseContentLengthMismatchError()); - return -1 + onData (chunk) { + if (this.location) ; else { + return this.handler.onData(chunk) } + } - request.onComplete(headers); + onComplete (trailers) { + if (this.location) { + /* + https://tools.ietf.org/html/rfc7231#section-6.4 - client[kQueue][client[kRunningIdx]++] = null; + TLDR: undici always ignores 3xx response trailers as they are not expected in case of redirections + and neither are useful if present. - if (socket[kWriting]) { - assert.strictEqual(client[kRunning], 0); - // Response completed before request. - 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) { - // Destroy socket once all requests have completed. - // The request at the tail of the pipeline is the one - // that requested reset and no further requests should - // have been queued since then. - util.destroy(socket, new InformationalError('reset')); - return constants.ERROR.PAUSED - } else if (client[kPipelining] === 1) { - // We must wait a full event loop cycle to reuse this socket to make sure - // that non-spec compliant servers are not closing the connection even if they - // said they won't. - setImmediate(resume, client); + See comment on onData method above for more detailed information. + */ + + this.location = null; + this.abort = null; + + this.dispatch(this.opts, this); } else { - resume(client); + this.handler.onComplete(trailers); } } - } - - function onParserTimeout (parser) { - const { socket, timeoutType, client } = parser; - /* istanbul ignore else */ - if (timeoutType === TIMEOUT_HEADERS) { - if (!socket[kWriting] || socket.writableNeedDrain || client[kRunning] > 1) { - assert(!parser.paused, 'cannot be paused while waiting for headers'); - util.destroy(socket, new HeadersTimeoutError()); - } - } else if (timeoutType === TIMEOUT_BODY) { - if (!parser.paused) { - util.destroy(socket, new BodyTimeoutError()); + onBodySent (chunk) { + if (this.handler.onBodySent) { + this.handler.onBodySent(chunk); } - } else if (timeoutType === TIMEOUT_IDLE) { - assert(client[kRunning] === 0 && client[kKeepAliveTimeoutValue]); - util.destroy(socket, new InformationalError('socket idle timeout')); } } - function onSocketReadable () { - const { [kParser]: parser } = this; - if (parser) { - parser.readMore(); + function parseLocation (statusCode, headers) { + if (redirectableStatusCodes.indexOf(statusCode) === -1) { + return null } - } - - function onSocketError (err) { - const { [kClient]: client, [kParser]: parser } = this; - assert(err.code !== 'ERR_TLS_CERT_ALTNAME_INVALID'); - - if (client[kHTTPConnVersion] !== 'h2') { - // On Mac OS, we get an ECONNRESET even if there is a full body to be forwarded - // to the user. - if (err.code === 'ECONNRESET' && parser.statusCode && !parser.shouldKeepAlive) { - // We treat all incoming data so for as a valid response. - parser.onMessageComplete(); - return + for (let i = 0; i < headers.length; i += 2) { + if (headers[i].length === 8 && util.headerNameToString(headers[i]) === 'location') { + return headers[i + 1] } } - - this[kError] = err; - - onError(this[kClient], err); } - function onError (client, err) { - if ( - client[kRunning] === 0 && - err.code !== 'UND_ERR_INFO' && - err.code !== 'UND_ERR_SOCKET' - ) { - // Error is not caused by running request and not a recoverable - // socket error. - - assert(client[kPendingIdx] === client[kRunningIdx]); - - const requests = client[kQueue].splice(client[kRunningIdx]); - for (let i = 0; i < requests.length; i++) { - const request = requests[i]; - errorRequest(client, request, err); - } - assert(client[kSize] === 0); + // https://tools.ietf.org/html/rfc7231#section-6.4.4 + 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 onSocketEnd () { - const { [kParser]: parser, [kClient]: client } = this; - - if (client[kHTTPConnVersion] !== 'h2') { - if (parser.statusCode && !parser.shouldKeepAlive) { - // We treat all incoming data so far as a valid response. - parser.onMessageComplete(); - return + // https://tools.ietf.org/html/rfc7231#section-6.4 + 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'); } - - util.destroy(this, new SocketError('other side closed', util.getSocketInfo(this))); + return ret } - function onSocketClose () { - const { [kClient]: client, [kParser]: parser } = this; + redirectHandler = RedirectHandler; + return redirectHandler; +} - if (client[kHTTPConnVersion] === 'h1' && parser) { - if (!this[kError] && parser.statusCode && !parser.shouldKeepAlive) { - // We treat all incoming data so far as a valid response. - parser.onMessageComplete(); - } +var redirectInterceptor; +var hasRequiredRedirectInterceptor; - this[kParser].destroy(); - this[kParser] = null; - } +function requireRedirectInterceptor () { + if (hasRequiredRedirectInterceptor) return redirectInterceptor; + hasRequiredRedirectInterceptor = 1; - const err = this[kError] || new SocketError('closed', util.getSocketInfo(this)); + const RedirectHandler = requireRedirectHandler(); - client[kSocket] = null; + function createRedirectInterceptor ({ maxRedirections: defaultMaxRedirections }) { + return (dispatch) => { + return function Intercept (opts, handler) { + const { maxRedirections = defaultMaxRedirections } = opts; - if (client.destroyed) { - assert(client[kPending] === 0); + if (!maxRedirections) { + return dispatch(opts, handler) + } - // Fail entire queue. - const requests = client[kQueue].splice(client[kRunningIdx]); - for (let i = 0; i < requests.length; i++) { - const request = requests[i]; - errorRequest(client, request, err); + const redirectHandler = new RedirectHandler(dispatch, maxRedirections, opts, handler); + opts = { ...opts, maxRedirections: 0 }; // Stop sub dispatcher from also redirecting. + return dispatch(opts, redirectHandler) } - } else if (client[kRunning] > 0 && err.code !== 'UND_ERR_INFO') { - // Fail head of pipeline. - const request = client[kQueue][client[kRunningIdx]]; - client[kQueue][client[kRunningIdx]++] = null; - - errorRequest(client, request, err); } - - client[kPendingIdx] = client[kRunningIdx]; - - assert(client[kRunning] === 0); - - client.emit('disconnect', client[kUrl], [client], err); - - resume(client); } - async function connect (client) { - assert(!client[kConnecting]); - assert(!client[kSocket]); - - let { host, hostname, protocol, port } = client[kUrl]; - - // Resolve ipv6 - if (hostname[0] === '[') { - const idx = hostname.indexOf(']'); - - assert(idx !== -1); - const ip = hostname.substring(1, idx); - - assert(net.isIP(ip)); - hostname = ip; - } + redirectInterceptor = createRedirectInterceptor; + return redirectInterceptor; +} - client[kConnecting] = true; +var client; +var hasRequiredClient; - if (channels.beforeConnect.hasSubscribers) { - channels.beforeConnect.publish({ - connectParams: { - host, - hostname, - protocol, - port, - servername: client[kServerName], - localAddress: client[kLocalAddress] - }, - connector: client[kConnector] - }); - } +function requireClient () { + if (hasRequiredClient) return client; + hasRequiredClient = 1; - try { - const socket = await new Promise((resolve, reject) => { - client[kConnector]({ - host, - hostname, + const assert = require$$0$3; + const net = require$$0$5; + const http = require$$2$1; + const util = requireUtil$8(); + const { channels } = requireDiagnostics(); + const Request = requireRequest$1(); + const DispatcherBase = requireDispatcherBase(); + const { + InvalidArgumentError, + InformationalError, + ClientDestroyedError + } = requireErrors(); + const buildConnector = requireConnect(); + const { + 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 + } = requireSymbols$4(); + const connectH1 = requireClientH1(); + const connectH2 = requireClientH2(); + let deprecatedInterceptorWarned = false; + + const kClosedResolve = Symbol('kClosedResolve'); + + const noop = () => {}; + + function getPipelining (client) { + return client[kPipelining] ?? client[kHTTPContext]?.defaultPipelining ?? 1 + } + + /** + * @type {import('../../types/client.js').default} + */ + class Client 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, + maxRequestsPerClient, + localAddress, + maxResponseSize, + autoSelectFamily, + autoSelectFamilyAttemptTimeout, + // h2 + maxConcurrentStreams, + allowH2 + } = {}) { + super(); + + if (keepAlive !== undefined) { + throw new InvalidArgumentError('unsupported keepAlive, use pipelining=0 instead') + } + + if (socketTimeout !== undefined) { + throw new InvalidArgumentError('unsupported socketTimeout, use headersTimeout & bodyTimeout instead') + } + + if (requestTimeout !== undefined) { + throw new InvalidArgumentError('unsupported requestTimeout, use headersTimeout & bodyTimeout instead') + } + + if (idleTimeout !== undefined) { + throw new InvalidArgumentError('unsupported idleTimeout, use keepAliveTimeout instead') + } + + if (maxKeepAliveTimeout !== undefined) { + 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 (connect != null && typeof connect !== 'function' && typeof connect !== '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') + } + + // h2 + 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 connect !== 'function') { + connect = buildConnector({ + ...tls, + maxCachedSessions, + allowH2, + socketPath, + timeout: connectTimeout, + ...(autoSelectFamily ? { autoSelectFamily, autoSelectFamilyAttemptTimeout } : undefined), + ...connect + }); + } + + 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] = connect; + this[kPipelining] = pipelining != null ? pipelining : 1; + this[kMaxHeadersSize] = maxHeaderSize || http.maxHeaderSize; + this[kKeepAliveDefaultTimeout] = keepAliveTimeout == null ? 4e3 : keepAliveTimeout; + this[kKeepAliveMaxTimeout] = keepAliveMaxTimeout == null ? 600e3 : keepAliveMaxTimeout; + this[kKeepAliveTimeoutThreshold] = keepAliveTimeoutThreshold == null ? 2e3 : keepAliveTimeoutThreshold; + this[kKeepAliveTimeoutValue] = this[kKeepAliveDefaultTimeout]; + this[kServerName] = null; + this[kLocalAddress] = localAddress != null ? localAddress : null; + this[kResuming] = 0; // 0, idle, 1, scheduled, 2 resuming + this[kNeedDrain] = 0; // 0, idle, 1, scheduled, 2 resuming + this[kHostHeader] = `host: ${this[kUrl].hostname}${this[kUrl].port ? `:${this[kUrl].port}` : ''}\r\n`; + this[kBodyTimeout] = bodyTimeout != null ? bodyTimeout : 300e3; + this[kHeadersTimeout] = headersTimeout != null ? headersTimeout : 300e3; + 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; // Max peerConcurrentStreams for a Node h2 server + this[kHTTPContext] = null; + + // kQueue is built up of 3 sections separated by + // the kRunningIdx and kPendingIdx indices. + // | complete | running | pending | + // ^ kRunningIdx ^ kPendingIdx ^ kQueue.length + // kRunningIdx points to the first running element. + // kPendingIdx points to the first pending element. + // This implements a fast queue with an amortized + // time of O(1). + + 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 Request(origin, opts, handler); + + this[kQueue].push(request); + if (this[kResuming]) ; else if (util.bodyLength(request.body) == null && util.isIterable(request.body)) { + // Wait a tick in case stream/iterator is ended in the same tick. + 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] () { + // TODO: for H2 we need to gracefully flush the remaining enqueued + // request and close each stream. + 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]) { + // TODO (fix): Should we error here with ClientDestroyedError? + this[kClosedResolve](); + this[kClosedResolve] = null; + } + resolve(null); + }; + + if (this[kHTTPContext]) { + this[kHTTPContext].destroy(err, callback); + this[kHTTPContext] = null; + } else { + queueMicrotask(callback); + } + + this[kResume](); + }) + } + } + + const createRedirectInterceptor = requireRedirectInterceptor(); + + function onError (client, err) { + if ( + client[kRunning] === 0 && + err.code !== 'UND_ERR_INFO' && + err.code !== 'UND_ERR_SOCKET' + ) { + // Error is not caused by running request and not a recoverable + // socket error. + + 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); + } + } + + /** + * @param {Client} client + * @returns + */ + async function connect (client) { + assert(!client[kConnecting]); + assert(!client[kHTTPContext]); + + let { host, hostname, protocol, port } = client[kUrl]; + + // Resolve ipv6 + 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, + hostname, + protocol, + port, + version: client[kHTTPContext]?.version, + servername: client[kServerName], + localAddress: client[kLocalAddress] + }, + connector: client[kConnector] + }); + } + + try { + const socket = await new Promise((resolve, reject) => { + client[kConnector]({ + host, + hostname, protocol, port, servername: client[kServerName], @@ -9839,66 +11651,28 @@ function requireClient () { }); if (client.destroyed) { - util.destroy(socket.on('error', () => {}), new ClientDestroyedError()); + util.destroy(socket.on('error', noop), new ClientDestroyedError()); return } - client[kConnecting] = false; - assert(socket); - const isH2 = socket.alpnProtocol === 'h2'; - if (isH2) { - 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[kHTTP2SessionState].maxConcurrentStreams - }); - - client[kHTTPConnVersion] = 'h2'; - session[kClient] = client; - session[kSocket] = socket; - session.on('error', onHttp2SessionError); - session.on('frameError', onHttp2FrameError); - session.on('end', onHttp2SessionEnd); - session.on('goaway', onHTTP2GoAway); - session.on('close', onSocketClose); - session.unref(); - - client[kHTTP2Session] = session; - socket[kHTTP2Session] = session; - } else { - 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); + 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; - socket - .on('error', onSocketError) - .on('readable', onSocketReadable) - .on('end', onSocketEnd) - .on('close', onSocketClose); - - client[kSocket] = socket; - if (channels.connected.hasSubscribers) { channels.connected.publish({ connectParams: { @@ -9906,6 +11680,7 @@ function requireClient () { hostname, protocol, port, + version: client[kHTTPContext]?.version, servername: client[kServerName], localAddress: client[kLocalAddress] }, @@ -9928,6 +11703,7 @@ function requireClient () { hostname, protocol, port, + version: client[kHTTPContext]?.version, servername: client[kServerName], localAddress: client[kLocalAddress] }, @@ -9940,7 +11716,7 @@ function requireClient () { assert(client[kRunning] === 0); while (client[kPending] > 0 && client[kQueue][client[kPendingIdx]].servername === client[kServerName]) { const request = client[kQueue][client[kPendingIdx]++]; - errorRequest(client, request, err); + util.errorRequest(client, request, err); } } else { onError(client, err); @@ -9949,7 +11725,7 @@ function requireClient () { client.emit('connectionError', client[kUrl], [client], err); } - resume(client); + client[kResume](); } function emitDrain (client) { @@ -9987,32 +11763,8 @@ function requireClient () { return } - const socket = client[kSocket]; - - if (socket && !socket.destroyed && socket.alpnProtocol !== 'h2') { - 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_IDLE) { - socket[kParser].setTimeout(client[kKeepAliveTimeoutValue], TIMEOUT_IDLE); - } - } 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); - } - } + if (client[kHTTPContext]) { + client[kHTTPContext].resume(); } if (client[kBusy]) { @@ -10020,7 +11772,7 @@ function requireClient () { } else if (client[kNeedDrain] === 2) { if (sync) { client[kNeedDrain] = 1; - process.nextTick(emitDrain, client); + queueMicrotask(() => emitDrain(client)); } else { emitDrain(client); } @@ -10031,7 +11783,7 @@ function requireClient () { return } - if (client[kRunning] >= (client[kPipelining] || 1)) { + if (client[kRunning] >= (getPipelining(client) || 1)) { return } @@ -10043,54 +11795,30 @@ function requireClient () { } client[kServerName] = request.servername; - - if (socket && socket.servername !== request.servername) { - util.destroy(socket, new InformationalError('servername changed')); - return - } + client[kHTTPContext]?.destroy(new InformationalError('servername changed'), () => { + client[kHTTPContext] = null; + resume(client); + }); } if (client[kConnecting]) { return } - if (!socket && !client[kHTTP2Session]) { + if (!client[kHTTPContext]) { connect(client); return } - if (socket.destroyed || socket[kWriting] || socket[kReset] || socket[kBlocking]) { - return - } - - if (client[kRunning] > 0 && !request.idempotent) { - // Non-idempotent request cannot be retried. - // Ensure that no other requests are inflight and - // could cause failure. - return - } - - if (client[kRunning] > 0 && (request.upgrade || request.method === 'CONNECT')) { - // Don't dispatch an upgrade until all preceding requests have completed. - // A misbehaving server might upgrade the connection before all pipelined - // request has completed. + if (client[kHTTPContext].destroyed) { return } - if (client[kRunning] > 0 && util.bodyLength(request.body) !== 0 && - (util.isStream(request.body) || util.isAsyncIterable(request.body))) { - // Request with stream or iterator body can error while other requests - // are inflight and indirectly error those as well. - // Ensure this doesn't happen by waiting for inflight - // to complete before dispatching. - - // Request with stream or iterator body cannot be retried. - // Ensure that no other requests are inflight and - // could cause failure. + if (client[kHTTPContext].busy(request)) { return } - if (!request.aborted && write(client, request)) { + if (!request.aborted && client[kHTTPContext].write(request)) { client[kPendingIdx]++; } else { client[kQueue].splice(client[kPendingIdx], 1); @@ -10098,1746 +11826,1756 @@ function requireClient () { } } - // https://www.rfc-editor.org/rfc/rfc7230#section-3.3.2 - function shouldSendContentLength (method) { - return method !== 'GET' && method !== 'HEAD' && method !== 'OPTIONS' && method !== 'TRACE' && method !== 'CONNECT' - } - - function write (client, request) { - if (client[kHTTPConnVersion] === 'h2') { - writeH2(client, client[kHTTP2Session], request); - return - } - - const { body, method, path, host, upgrade, headers, blocking, reset } = request; + client = Client; + return client; +} - // https://tools.ietf.org/html/rfc7231#section-4.3.1 - // https://tools.ietf.org/html/rfc7231#section-4.3.2 - // https://tools.ietf.org/html/rfc7231#section-4.3.5 +/* eslint-disable */ - // Sending a payload body on a request that does not - // expect it can cause undefined behavior on some - // servers and corrupt connection state. Do not - // re-use the connection for further requests. +var fixedQueue; +var hasRequiredFixedQueue; - const expectsPayload = ( - method === 'PUT' || - method === 'POST' || - method === 'PATCH' - ); +function requireFixedQueue () { + if (hasRequiredFixedQueue) return fixedQueue; + hasRequiredFixedQueue = 1; - if (body && typeof body.read === 'function') { - // Try to read EOF in order to get length. - body.read(0); - } + // Extracted from node/lib/internal/fixed_queue.js - const bodyLength = util.bodyLength(body); + // Currently optimal queue size, tested on V8 6.0 - 6.6. Must be power of two. + const kSize = 2048; + const kMask = kSize - 1; - let contentLength = bodyLength; + // The FixedQueue is implemented as a singly-linked list of fixed-size + // circular buffers. It looks something like this: + // + // head tail + // | | + // v v + // +-----------+ <-----\ +-----------+ <------\ +-----------+ + // | [null] | \----- | next | \------- | next | + // +-----------+ +-----------+ +-----------+ + // | item | <-- bottom | item | <-- bottom | [empty] | + // | item | | item | | [empty] | + // | item | | item | | [empty] | + // | item | | item | | [empty] | + // | item | | item | bottom --> | item | + // | item | | item | | item | + // | ... | | ... | | ... | + // | item | | item | | item | + // | item | | item | | item | + // | [empty] | <-- top | item | | item | + // | [empty] | | item | | item | + // | [empty] | | [empty] | <-- top top --> | [empty] | + // +-----------+ +-----------+ +-----------+ + // + // Or, if there is only one circular buffer, it looks something + // like either of these: + // + // head tail head tail + // | | | | + // v v v v + // +-----------+ +-----------+ + // | [null] | | [null] | + // +-----------+ +-----------+ + // | [empty] | | item | + // | [empty] | | item | + // | item | <-- bottom top --> | [empty] | + // | item | | [empty] | + // | [empty] | <-- top bottom --> | item | + // | [empty] | | item | + // +-----------+ +-----------+ + // + // Adding a value means moving `top` forward by one, removing means + // moving `bottom` forward by one. After reaching the end, the queue + // wraps around. + // + // When `top === bottom` the current queue is empty and when + // `top + 1 === bottom` it's full. This wastes a single space of storage + // but allows much quicker checks. - if (contentLength === null) { - contentLength = request.contentLength; + class FixedCircularBuffer { + constructor() { + this.bottom = 0; + this.top = 0; + this.list = new Array(kSize); + this.next = null; } - if (contentLength === 0 && !expectsPayload) { - // https://tools.ietf.org/html/rfc7230#section-3.3.2 - // A user agent SHOULD NOT send a Content-Length header field when - // the request message does not contain a payload body and the method - // semantics do not anticipate such a body. - - contentLength = null; + isEmpty() { + return this.top === this.bottom; } - // https://github.com/nodejs/undici/issues/2046 - // A user agent may send a Content-Length header with 0 value, this should be allowed. - if (shouldSendContentLength(method) && contentLength > 0 && request.contentLength !== null && request.contentLength !== contentLength) { - if (client[kStrictContentLength]) { - errorRequest(client, request, new RequestContentLengthMismatchError()); - return false - } - - process.emitWarning(new RequestContentLengthMismatchError()); + isFull() { + return ((this.top + 1) & kMask) === this.bottom; } - const socket = client[kSocket]; - - try { - request.onConnect((err) => { - if (request.aborted || request.completed) { - return - } - - errorRequest(client, request, err || new RequestAbortedError()); - - util.destroy(socket, new InformationalError('aborted')); - }); - } catch (err) { - errorRequest(client, request, err); + push(data) { + this.list[this.top] = data; + this.top = (this.top + 1) & kMask; } - if (request.aborted) { - return false + shift() { + const nextItem = this.list[this.bottom]; + if (nextItem === undefined) + return null; + this.list[this.bottom] = undefined; + this.bottom = (this.bottom + 1) & kMask; + return nextItem; } + } - if (method === 'HEAD') { - // https://github.com/mcollina/undici/issues/258 - // Close after a HEAD request to interop with misbehaving servers - // that may send a body in the response. - - socket[kReset] = true; + fixedQueue = class FixedQueue { + constructor() { + this.head = this.tail = new FixedCircularBuffer(); } - if (upgrade || method === 'CONNECT') { - // On CONNECT or upgrade, block pipeline from dispatching further - // requests on this connection. - - socket[kReset] = true; + isEmpty() { + return this.head.isEmpty(); } - if (reset != null) { - socket[kReset] = reset; + push(data) { + if (this.head.isFull()) { + // Head is full: Creates a new queue, sets the old queue's `.next` to it, + // and sets it as the new main queue. + this.head = this.head.next = new FixedCircularBuffer(); + } + this.head.push(data); } - if (client[kMaxRequests] && socket[kCounter]++ >= client[kMaxRequests]) { - socket[kReset] = true; + shift() { + const tail = this.tail; + const next = tail.shift(); + if (tail.isEmpty() && tail.next !== null) { + // If there is another queue, it forms the new tail. + this.tail = tail.next; + } + return next; } + }; + return fixedQueue; +} - if (blocking) { - socket[kBlocking] = true; - } +var poolStats; +var hasRequiredPoolStats; - let header = `${method} ${path} HTTP/1.1\r\n`; +function requirePoolStats () { + if (hasRequiredPoolStats) return poolStats; + hasRequiredPoolStats = 1; + const { kFree, kConnected, kPending, kQueued, kRunning, kSize } = requireSymbols$4(); + const kPool = Symbol('pool'); - if (typeof host === 'string') { - header += `host: ${host}\r\n`; - } else { - header += client[kHostHeader]; + class PoolStats { + constructor (pool) { + this[kPool] = pool; } - if (upgrade) { - header += `connection: upgrade\r\nupgrade: ${upgrade}\r\n`; - } else if (client[kPipelining] && !socket[kReset]) { - header += 'connection: keep-alive\r\n'; - } else { - header += 'connection: close\r\n'; + get connected () { + return this[kPool][kConnected] } - if (headers) { - header += headers; + get free () { + return this[kPool][kFree] } - if (channels.sendHeaders.hasSubscribers) { - channels.sendHeaders.publish({ request, headers: header, socket }); + get pending () { + return this[kPool][kPending] } - /* istanbul ignore else: assertion */ - if (!body || bodyLength === 0) { - if (contentLength === 0) { - socket.write(`${header}content-length: 0\r\n\r\n`, 'latin1'); - } else { - assert(contentLength === null, 'no body must not have content length'); - socket.write(`${header}\r\n`, 'latin1'); - } - request.onRequestSent(); - } else if (util.isBuffer(body)) { - assert(contentLength === body.byteLength, 'buffer body must have content length'); + get queued () { + return this[kPool][kQueued] + } - socket.cork(); - socket.write(`${header}content-length: ${contentLength}\r\n\r\n`, 'latin1'); - socket.write(body); - socket.uncork(); - request.onBodySent(body); - request.onRequestSent(); - if (!expectsPayload) { - socket[kReset] = true; - } - } else if (util.isBlobLike(body)) { - if (typeof body.stream === 'function') { - writeIterable({ body: body.stream(), client, request, socket, contentLength, header, expectsPayload }); - } else { - writeBlob({ body, client, request, socket, contentLength, header, expectsPayload }); - } - } else if (util.isStream(body)) { - writeStream({ body, client, request, socket, contentLength, header, expectsPayload }); - } else if (util.isIterable(body)) { - writeIterable({ body, client, request, socket, contentLength, header, expectsPayload }); - } else { - assert(false); + get running () { + return this[kPool][kRunning] } - return true + get size () { + return this[kPool][kSize] + } } - function writeH2 (client, session, request) { - const { body, method, path, host, upgrade, expectContinue, signal, headers: reqHeaders } = request; + poolStats = PoolStats; + return poolStats; +} - let headers; - if (typeof reqHeaders === 'string') headers = Request[kHTTP2CopyHeaders](reqHeaders.trim()); - else headers = reqHeaders; +var poolBase; +var hasRequiredPoolBase; - if (upgrade) { - errorRequest(client, request, new Error('Upgrade not supported for H2')); - return false - } +function requirePoolBase () { + if (hasRequiredPoolBase) return poolBase; + hasRequiredPoolBase = 1; - try { - // TODO(HTTP/2): Should we call onConnect immediately or on stream ready event? - request.onConnect((err) => { - if (request.aborted || request.completed) { - return - } + const DispatcherBase = requireDispatcherBase(); + const FixedQueue = requireFixedQueue(); + const { kConnected, kSize, kRunning, kPending, kQueued, kBusy, kFree, kUrl, kClose, kDestroy, kDispatch } = requireSymbols$4(); + const PoolStats = requirePoolStats(); - errorRequest(client, request, err || new RequestAbortedError()); - }); - } catch (err) { - errorRequest(client, request, err); - } + const kClients = Symbol('clients'); + const kNeedDrain = Symbol('needDrain'); + const kQueue = Symbol('queue'); + const kClosedResolve = Symbol('closed resolve'); + const kOnDrain = Symbol('onDrain'); + const kOnConnect = Symbol('onConnect'); + const kOnDisconnect = Symbol('onDisconnect'); + const kOnConnectionError = Symbol('onConnectionError'); + const kGetDispatcher = Symbol('get dispatcher'); + const kAddClient = Symbol('add client'); + const kRemoveClient = Symbol('remove client'); + const kStats = Symbol('stats'); - if (request.aborted) { - return false - } + class PoolBase extends DispatcherBase { + constructor () { + super(); - /** @type {import('node:http2').ClientHttp2Stream} */ - let stream; - const h2State = client[kHTTP2SessionState]; + this[kQueue] = new FixedQueue(); + this[kClients] = []; + this[kQueued] = 0; - headers[HTTP2_HEADER_AUTHORITY] = host || client[kHost]; - headers[HTTP2_HEADER_METHOD] = method; + const pool = this; - if (method === 'CONNECT') { - session.ref(); - // we are already connected, streams are pending, first request - // will create a new stream. We trigger a request to create the stream and wait until - // `ready` event is triggered - // We disabled endStream to allow the user to write to the stream - stream = session.request(headers, { endStream: false, signal }); + this[kOnDrain] = function onDrain (origin, targets) { + const queue = pool[kQueue]; - if (stream.id && !stream.pending) { - request.onUpgrade(null, null, stream); - ++h2State.openStreams; - } else { - stream.once('ready', () => { - request.onUpgrade(null, null, stream); - ++h2State.openStreams; - }); - } + let needDrain = false; - stream.once('close', () => { - h2State.openStreams -= 1; - // TODO(HTTP/2): unref only if current streams count is 0 - if (h2State.openStreams === 0) session.unref(); - }); + while (!needDrain) { + const item = queue.shift(); + if (!item) { + break + } + pool[kQueued]--; + needDrain = !this.dispatch(item.opts, item.handler); + } - return true - } + this[kNeedDrain] = needDrain; - // https://tools.ietf.org/html/rfc7540#section-8.3 - // :path and :scheme headers must be omited when sending CONNECT + if (!this[kNeedDrain] && pool[kNeedDrain]) { + pool[kNeedDrain] = false; + pool.emit('drain', origin, [pool, ...targets]); + } - headers[HTTP2_HEADER_PATH] = path; - headers[HTTP2_HEADER_SCHEME] = 'https'; + if (pool[kClosedResolve] && queue.isEmpty()) { + Promise + .all(pool[kClients].map(c => c.close())) + .then(pool[kClosedResolve]); + } + }; - // https://tools.ietf.org/html/rfc7231#section-4.3.1 - // https://tools.ietf.org/html/rfc7231#section-4.3.2 - // https://tools.ietf.org/html/rfc7231#section-4.3.5 + this[kOnConnect] = (origin, targets) => { + pool.emit('connect', origin, [pool, ...targets]); + }; - // Sending a payload body on a request that does not - // expect it can cause undefined behavior on some - // servers and corrupt connection state. Do not - // re-use the connection for further requests. + this[kOnDisconnect] = (origin, targets, err) => { + pool.emit('disconnect', origin, [pool, ...targets], err); + }; - const expectsPayload = ( - method === 'PUT' || - method === 'POST' || - method === 'PATCH' - ); + this[kOnConnectionError] = (origin, targets, err) => { + pool.emit('connectionError', origin, [pool, ...targets], err); + }; - if (body && typeof body.read === 'function') { - // Try to read EOF in order to get length. - body.read(0); + this[kStats] = new PoolStats(this); } - let contentLength = util.bodyLength(body); - - if (contentLength == null) { - contentLength = request.contentLength; + get [kBusy] () { + return this[kNeedDrain] } - if (contentLength === 0 || !expectsPayload) { - // https://tools.ietf.org/html/rfc7230#section-3.3.2 - // A user agent SHOULD NOT send a Content-Length header field when - // the request message does not contain a payload body and the method - // semantics do not anticipate such a body. - - contentLength = null; + get [kConnected] () { + return this[kClients].filter(client => client[kConnected]).length } - // https://github.com/nodejs/undici/issues/2046 - // A user agent may send a Content-Length header with 0 value, this should be allowed. - if (shouldSendContentLength(method) && contentLength > 0 && request.contentLength != null && request.contentLength !== contentLength) { - if (client[kStrictContentLength]) { - errorRequest(client, request, new RequestContentLengthMismatchError()); - return false - } - - process.emitWarning(new RequestContentLengthMismatchError()); + get [kFree] () { + return this[kClients].filter(client => client[kConnected] && !client[kNeedDrain]).length } - if (contentLength != null) { - assert(body, 'no body must not have content length'); - headers[HTTP2_HEADER_CONTENT_LENGTH] = `${contentLength}`; + get [kPending] () { + let ret = this[kQueued]; + for (const { [kPending]: pending } of this[kClients]) { + ret += pending; + } + return ret } - session.ref(); - - const shouldEndStream = method === 'GET' || method === 'HEAD'; - 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(); + get [kRunning] () { + let ret = 0; + for (const { [kRunning]: running } of this[kClients]) { + ret += running; + } + return ret } - // Increment counter as we have new several streams open - ++h2State.openStreams; - - stream.once('response', headers => { - const { [HTTP2_HEADER_STATUS]: statusCode, ...realHeaders } = headers; - - if (request.onHeaders(Number(statusCode), realHeaders, stream.resume.bind(stream), '') === false) { - stream.pause(); + get [kSize] () { + let ret = this[kQueued]; + for (const { [kSize]: size } of this[kClients]) { + ret += size; } - }); + return ret + } - stream.once('end', () => { - request.onComplete([]); - }); + get stats () { + return this[kStats] + } - stream.on('data', (chunk) => { - if (request.onData(chunk) === false) { - stream.pause(); + async [kClose] () { + if (this[kQueue].isEmpty()) { + await Promise.all(this[kClients].map(c => c.close())); + } else { + await new Promise((resolve) => { + this[kClosedResolve] = resolve; + }); } - }); + } - stream.once('close', () => { - h2State.openStreams -= 1; - // TODO(HTTP/2): unref only if current streams count is 0 - if (h2State.openStreams === 0) { - session.unref(); + async [kDestroy] (err) { + while (true) { + const item = this[kQueue].shift(); + if (!item) { + break + } + item.handler.onError(err); } - }); - stream.once('error', function (err) { - if (client[kHTTP2Session] && !client[kHTTP2Session].destroyed && !this.closed && !this.destroyed) { - h2State.streams -= 1; - util.destroy(stream, err); - } - }); + await Promise.all(this[kClients].map(c => c.destroy(err))); + } - stream.once('frameError', (type, code) => { - const err = new InformationalError(`HTTP/2: "frameError" received - type ${type}, code ${code}`); - errorRequest(client, request, err); + [kDispatch] (opts, handler) { + const dispatcher = this[kGetDispatcher](); - if (client[kHTTP2Session] && !client[kHTTP2Session].destroyed && !this.closed && !this.destroyed) { - h2State.streams -= 1; - util.destroy(stream, err); + 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](); } - }); - // stream.on('aborted', () => { - // // TODO(HTTP/2): Support aborted - // }) + return !this[kNeedDrain] + } - // stream.on('timeout', () => { - // // TODO(HTTP/2): Support timeout - // }) + [kAddClient] (client) { + client + .on('drain', this[kOnDrain]) + .on('connect', this[kOnConnect]) + .on('disconnect', this[kOnDisconnect]) + .on('connectionError', this[kOnConnectionError]); - // stream.on('push', headers => { - // // TODO(HTTP/2): Suppor push - // }) + this[kClients].push(client); - // stream.on('trailers', headers => { - // // TODO(HTTP/2): Support trailers - // }) + if (this[kNeedDrain]) { + queueMicrotask(() => { + if (this[kNeedDrain]) { + this[kOnDrain](client[kUrl], [this, client]); + } + }); + } - return true + return this + } - function writeBodyH2 () { - /* istanbul ignore else: assertion */ - if (!body) { - request.onRequestSent(); - } else if (util.isBuffer(body)) { - assert(contentLength === body.byteLength, 'buffer body must have content length'); - stream.cork(); - stream.write(body); - stream.uncork(); - stream.end(); - request.onBodySent(body); - request.onRequestSent(); - } else if (util.isBlobLike(body)) { - if (typeof body.stream === 'function') { - writeIterable({ - client, - request, - contentLength, - h2stream: stream, - expectsPayload, - body: body.stream(), - socket: client[kSocket], - header: '' - }); - } else { - writeBlob({ - body, - client, - request, - contentLength, - expectsPayload, - h2stream: stream, - header: '', - socket: client[kSocket] - }); + [kRemoveClient] (client) { + client.close(() => { + const idx = this[kClients].indexOf(client); + if (idx !== -1) { + this[kClients].splice(idx, 1); } - } else if (util.isStream(body)) { - writeStream({ - body, - client, - request, - contentLength, - expectsPayload, - socket: client[kSocket], - h2stream: stream, - header: '' - }); - } else if (util.isIterable(body)) { - writeIterable({ - body, - client, - request, - contentLength, - expectsPayload, - header: '', - h2stream: stream, - socket: client[kSocket] - }); - } else { - assert(false); - } + }); + + this[kNeedDrain] = this[kClients].some(dispatcher => ( + !dispatcher[kNeedDrain] && + dispatcher.closed !== true && + dispatcher.destroyed !== true + )); } } - function writeStream ({ h2stream, body, client, request, socket, contentLength, header, expectsPayload }) { - assert(contentLength !== 0 || client[kRunning] === 0, 'stream body cannot be pipelined'); + poolBase = { + PoolBase, + kClients, + kNeedDrain, + kAddClient, + kRemoveClient, + kGetDispatcher + }; + return poolBase; +} - if (client[kHTTPConnVersion] === 'h2') { - // For HTTP/2, is enough to pipe the stream - const pipe = pipeline( - body, - h2stream, - (err) => { - if (err) { - util.destroy(body, err); - util.destroy(h2stream, err); - } else { - request.onRequestSent(); - } - } - ); +var pool; +var hasRequiredPool; - pipe.on('data', onPipeData); - pipe.once('end', () => { - pipe.removeListener('data', onPipeData); - util.destroy(pipe); - }); +function requirePool () { + if (hasRequiredPool) return pool; + hasRequiredPool = 1; - function onPipeData (chunk) { - request.onBodySent(chunk); - } + const { + PoolBase, + kClients, + kNeedDrain, + kAddClient, + kGetDispatcher + } = requirePoolBase(); + const Client = requireClient(); + const { + InvalidArgumentError + } = requireErrors(); + const util = requireUtil$8(); + const { kUrl, kInterceptors } = requireSymbols$4(); + const buildConnector = requireConnect(); - return - } + const kOptions = Symbol('options'); + const kConnections = Symbol('connections'); + const kFactory = Symbol('factory'); - let finished = false; + function defaultFactory (origin, opts) { + return new Client(origin, opts) + } - const writer = new AsyncWriter({ socket, request, contentLength, client, expectsPayload, header }); + class Pool extends PoolBase { + constructor (origin, { + connections, + factory = defaultFactory, + connect, + connectTimeout, + tls, + maxCachedSessions, + socketPath, + autoSelectFamily, + autoSelectFamilyAttemptTimeout, + allowH2, + ...options + } = {}) { + super(); - const onData = function (chunk) { - if (finished) { - return + if (connections != null && (!Number.isFinite(connections) || connections < 0)) { + throw new InvalidArgumentError('invalid connections') } - try { - if (!writer.write(chunk) && this.pause) { - this.pause(); - } - } catch (err) { - util.destroy(this, err); - } - }; - const onDrain = function () { - if (finished) { - return + if (typeof factory !== 'function') { + throw new InvalidArgumentError('factory must be a function.') } - if (body.resume) { - body.resume(); - } - }; - const onAbort = function () { - if (finished) { - return - } - const err = new RequestAbortedError(); - queueMicrotask(() => onFinished(err)); - }; - const onFinished = function (err) { - if (finished) { - return + if (connect != null && typeof connect !== 'function' && typeof connect !== 'object') { + throw new InvalidArgumentError('connect must be a function or an object') } - finished = true; - - assert(socket.destroyed || (socket[kWriting] && client[kRunning] <= 1)); + if (typeof connect !== 'function') { + connect = buildConnector({ + ...tls, + maxCachedSessions, + allowH2, + socketPath, + timeout: connectTimeout, + ...(autoSelectFamily ? { autoSelectFamily, autoSelectFamilyAttemptTimeout } : undefined), + ...connect + }); + } - socket - .off('drain', onDrain) - .off('error', onFinished); + 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 } + : undefined; + this[kFactory] = factory; - body - .removeListener('data', onData) - .removeListener('end', onFinished) - .removeListener('error', onFinished) - .removeListener('close', onAbort); + this.on('connectionError', (origin, targets, error) => { + // If a connection error occurs, we remove the client from the pool, + // and emit a connectionError event. They will not be re-used. + // Fixes https://github.com/nodejs/undici/issues/3895 + for (const target of targets) { + // Do not use kRemoveClient here, as it will close the client, + // but the client cannot be closed in this state. + const idx = this[kClients].indexOf(target); + if (idx !== -1) { + this[kClients].splice(idx, 1); + } + } + }); + } - if (!err) { - try { - writer.end(); - } catch (er) { - err = er; + [kGetDispatcher] () { + for (const client of this[kClients]) { + if (!client[kNeedDrain]) { + return client } } - writer.destroy(err); - - if (err && (err.code !== 'UND_ERR_INFO' || err.message !== 'reset')) { - util.destroy(body, err); - } else { - util.destroy(body); + if (!this[kConnections] || this[kClients].length < this[kConnections]) { + const dispatcher = this[kFactory](this[kUrl], this[kOptions]); + this[kAddClient](dispatcher); + return dispatcher } - }; + } + } - body - .on('data', onData) - .on('end', onFinished) - .on('error', onFinished) - .on('close', onAbort); + pool = Pool; + return pool; +} - if (body.resume) { - body.resume(); +var balancedPool; +var hasRequiredBalancedPool; + +function requireBalancedPool () { + if (hasRequiredBalancedPool) return balancedPool; + hasRequiredBalancedPool = 1; + + const { + BalancedPoolMissingUpstreamError, + InvalidArgumentError + } = requireErrors(); + const { + PoolBase, + kClients, + kNeedDrain, + kAddClient, + kRemoveClient, + kGetDispatcher + } = requirePoolBase(); + const Pool = requirePool(); + const { kUrl, kInterceptors } = requireSymbols$4(); + const { parseOrigin } = requireUtil$8(); + const kFactory = Symbol('factory'); + + const kOptions = Symbol('options'); + const kGreatestCommonDivisor = Symbol('kGreatestCommonDivisor'); + const kCurrentWeight = Symbol('kCurrentWeight'); + const kIndex = Symbol('kIndex'); + const kWeight = Symbol('kWeight'); + const kMaxWeightPerServer = Symbol('kMaxWeightPerServer'); + const kErrorPenalty = Symbol('kErrorPenalty'); + + /** + * Calculate the greatest common divisor of two numbers by + * using the Euclidean algorithm. + * + * @param {number} a + * @param {number} b + * @returns {number} + */ + function getGreatestCommonDivisor (a, b) { + if (a === 0) return b + + while (b !== 0) { + const t = b; + b = a % b; + a = t; } + return a + } - socket - .on('drain', onDrain) - .on('error', onFinished); + function defaultFactory (origin, opts) { + return new Pool(origin, opts) } - async function writeBlob ({ h2stream, body, client, request, socket, contentLength, header, expectsPayload }) { - assert(contentLength === body.size, 'blob body must have content length'); + class BalancedPool extends PoolBase { + constructor (upstreams = [], { factory = defaultFactory, ...opts } = {}) { + super(); - const isH2 = client[kHTTPConnVersion] === 'h2'; - try { - if (contentLength != null && contentLength !== body.size) { - throw new RequestContentLengthMismatchError() - } + this[kOptions] = opts; + this[kIndex] = -1; + this[kCurrentWeight] = 0; - const buffer = Buffer.from(await body.arrayBuffer()); + this[kMaxWeightPerServer] = this[kOptions].maxWeightPerServer || 100; + this[kErrorPenalty] = this[kOptions].errorPenalty || 15; - if (isH2) { - h2stream.cork(); - h2stream.write(buffer); - h2stream.uncork(); - } else { - socket.cork(); - socket.write(`${header}content-length: ${contentLength}\r\n\r\n`, 'latin1'); - socket.write(buffer); - socket.uncork(); + if (!Array.isArray(upstreams)) { + upstreams = [upstreams]; } - request.onBodySent(buffer); - request.onRequestSent(); - - if (!expectsPayload) { - socket[kReset] = true; + if (typeof factory !== 'function') { + throw new InvalidArgumentError('factory must be a function.') } - resume(client); - } catch (err) { - util.destroy(isH2 ? h2stream : socket, err); - } - } - - async function writeIterable ({ h2stream, body, client, request, socket, contentLength, header, expectsPayload }) { - assert(contentLength !== 0 || client[kRunning] === 0, 'iterator body cannot be pipelined'); + this[kInterceptors] = opts.interceptors?.BalancedPool && Array.isArray(opts.interceptors.BalancedPool) + ? opts.interceptors.BalancedPool + : []; + this[kFactory] = factory; - let callback = null; - function onDrain () { - if (callback) { - const cb = callback; - callback = null; - cb(); + for (const upstream of upstreams) { + this.addUpstream(upstream); } + this._updateBalancedPoolStats(); } - const waitForDrain = () => new Promise((resolve, reject) => { - assert(callback === null); + addUpstream (upstream) { + const upstreamOrigin = parseOrigin(upstream).origin; - if (socket[kError]) { - reject(socket[kError]); - } else { - callback = resolve; + if (this[kClients].find((pool) => ( + pool[kUrl].origin === upstreamOrigin && + pool.closed !== true && + pool.destroyed !== true + ))) { + return this } - }); + const pool = this[kFactory](upstreamOrigin, Object.assign({}, this[kOptions])); - if (client[kHTTPConnVersion] === 'h2') { - h2stream - .on('close', onDrain) - .on('drain', onDrain); + this[kAddClient](pool); + pool.on('connect', () => { + pool[kWeight] = Math.min(this[kMaxWeightPerServer], pool[kWeight] + this[kErrorPenalty]); + }); - try { - // It's up to the user to somehow abort the async iterable. - for await (const chunk of body) { - if (socket[kError]) { - throw socket[kError] - } + pool.on('connectionError', () => { + pool[kWeight] = Math.max(1, pool[kWeight] - this[kErrorPenalty]); + this._updateBalancedPoolStats(); + }); - const res = h2stream.write(chunk); - request.onBodySent(chunk); - if (!res) { - await waitForDrain(); - } + pool.on('disconnect', (...args) => { + const err = args[2]; + if (err && err.code === 'UND_ERR_SOCKET') { + // decrease the weight of the pool. + pool[kWeight] = Math.max(1, pool[kWeight] - this[kErrorPenalty]); + this._updateBalancedPoolStats(); } - } catch (err) { - h2stream.destroy(err); - } finally { - request.onRequestSent(); - h2stream.end(); - h2stream - .off('close', onDrain) - .off('drain', onDrain); - } + }); - return - } + for (const client of this[kClients]) { + client[kWeight] = this[kMaxWeightPerServer]; + } - socket - .on('close', onDrain) - .on('drain', onDrain); + this._updateBalancedPoolStats(); - const writer = new AsyncWriter({ socket, request, contentLength, client, expectsPayload, header }); - try { - // It's up to the user to somehow abort the async iterable. - for await (const chunk of body) { - if (socket[kError]) { - throw socket[kError] - } + return this + } - if (!writer.write(chunk)) { - await waitForDrain(); - } + _updateBalancedPoolStats () { + let result = 0; + for (let i = 0; i < this[kClients].length; i++) { + result = getGreatestCommonDivisor(this[kClients][i][kWeight], result); } - writer.end(); - } catch (err) { - writer.destroy(err); - } finally { - socket - .off('close', onDrain) - .off('drain', onDrain); + this[kGreatestCommonDivisor] = result; } - } - class AsyncWriter { - constructor ({ 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; + removeUpstream (upstream) { + const upstreamOrigin = parseOrigin(upstream).origin; - socket[kWriting] = true; + const pool = this[kClients].find((pool) => ( + pool[kUrl].origin === upstreamOrigin && + pool.closed !== true && + pool.destroyed !== true + )); + + if (pool) { + this[kRemoveClient](pool); + } + + return this } - write (chunk) { - const { socket, request, contentLength, client, bytesWritten, expectsPayload, header } = this; + get upstreams () { + return this[kClients] + .filter(dispatcher => dispatcher.closed !== true && dispatcher.destroyed !== true) + .map((p) => p[kUrl].origin) + } - if (socket[kError]) { - throw socket[kError] + [kGetDispatcher] () { + // We validate that pools is greater than 0, + // otherwise we would have to wait until an upstream + // is added, which might never happen. + if (this[kClients].length === 0) { + throw new BalancedPoolMissingUpstreamError() } - if (socket.destroyed) { - return false - } + const dispatcher = this[kClients].find(dispatcher => ( + !dispatcher[kNeedDrain] && + dispatcher.closed !== true && + dispatcher.destroyed !== true + )); - const len = Buffer.byteLength(chunk); - if (!len) { - return true + if (!dispatcher) { + return } - // We should defer writing chunks. - if (contentLength !== null && bytesWritten + len > contentLength) { - if (client[kStrictContentLength]) { - throw new RequestContentLengthMismatchError() - } + const allClientsBusy = this[kClients].map(pool => pool[kNeedDrain]).reduce((a, b) => a && b, true); - process.emitWarning(new RequestContentLengthMismatchError()); + if (allClientsBusy) { + return } - socket.cork(); + let counter = 0; - if (bytesWritten === 0) { - if (!expectsPayload) { - socket[kReset] = true; + 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]]; + + // find pool index with the largest weight + if (pool[kWeight] > this[kClients][maxWeightIndex][kWeight] && !pool[kNeedDrain]) { + maxWeightIndex = this[kIndex]; } - if (contentLength === null) { - socket.write(`${header}transfer-encoding: chunked\r\n`, 'latin1'); - } else { - socket.write(`${header}content-length: ${contentLength}\r\n\r\n`, 'latin1'); + // decrease the current weight every `this[kClients].length`. + if (this[kIndex] === 0) { + // Set the current weight to the next lower weight. + this[kCurrentWeight] = this[kCurrentWeight] - this[kGreatestCommonDivisor]; + + if (this[kCurrentWeight] <= 0) { + this[kCurrentWeight] = this[kMaxWeightPerServer]; + } + } + if (pool[kWeight] >= this[kCurrentWeight] && (!pool[kNeedDrain])) { + return pool } } - if (contentLength === null) { - socket.write(`\r\n${len.toString(16)}\r\n`, 'latin1'); - } + this[kCurrentWeight] = this[kClients][maxWeightIndex][kWeight]; + this[kIndex] = maxWeightIndex; + return this[kClients][maxWeightIndex] + } + } - this.bytesWritten += len; + balancedPool = BalancedPool; + return balancedPool; +} - const ret = socket.write(chunk); +var agent; +var hasRequiredAgent; - socket.uncork(); +function requireAgent () { + if (hasRequiredAgent) return agent; + hasRequiredAgent = 1; - request.onBodySent(chunk); + const { InvalidArgumentError } = requireErrors(); + const { kClients, kRunning, kClose, kDestroy, kDispatch, kInterceptors } = requireSymbols$4(); + const DispatcherBase = requireDispatcherBase(); + const Pool = requirePool(); + const Client = requireClient(); + const util = requireUtil$8(); + const createRedirectInterceptor = requireRedirectInterceptor(); - if (!ret) { - if (socket[kParser].timeout && socket[kParser].timeoutType === TIMEOUT_HEADERS) { - // istanbul ignore else: only for jest - if (socket[kParser].timeout.refresh) { - socket[kParser].timeout.refresh(); - } - } - } + const kOnConnect = Symbol('onConnect'); + const kOnDisconnect = Symbol('onDisconnect'); + const kOnConnectionError = Symbol('onConnectionError'); + const kMaxRedirections = Symbol('maxRedirections'); + const kOnDrain = Symbol('onDrain'); + const kFactory = Symbol('factory'); + const kOptions = Symbol('options'); - return ret - } + function defaultFactory (origin, opts) { + return opts && opts.connections === 1 + ? new Client(origin, opts) + : new Pool(origin, opts) + } - end () { - const { socket, contentLength, client, bytesWritten, expectsPayload, header, request } = this; - request.onRequestSent(); + class Agent extends DispatcherBase { + constructor ({ factory = defaultFactory, maxRedirections = 0, connect, ...options } = {}) { + super(); - socket[kWriting] = false; + if (typeof factory !== 'function') { + throw new InvalidArgumentError('factory must be a function.') + } - if (socket[kError]) { - throw socket[kError] + if (connect != null && typeof connect !== 'function' && typeof connect !== 'object') { + throw new InvalidArgumentError('connect must be a function or an object') } - if (socket.destroyed) { - return + if (!Number.isInteger(maxRedirections) || maxRedirections < 0) { + throw new InvalidArgumentError('maxRedirections must be a positive number') } - if (bytesWritten === 0) { - if (expectsPayload) { - // https://tools.ietf.org/html/rfc7230#section-3.3.2 - // A user agent SHOULD send a Content-Length in a request message when - // no Transfer-Encoding is sent and the request method defines a meaning - // for an enclosed payload body. + if (connect && typeof connect !== 'function') { + connect = { ...connect }; + } - socket.write(`${header}content-length: 0\r\n\r\n`, 'latin1'); - } else { - socket.write(`${header}\r\n`, 'latin1'); - } - } else if (contentLength === null) { - socket.write('\r\n0\r\n\r\n', 'latin1'); + 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 } + : undefined; + this[kMaxRedirections] = maxRedirections; + this[kFactory] = factory; + this[kClients] = 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 + } - if (contentLength !== null && bytesWritten !== contentLength) { - if (client[kStrictContentLength]) { - throw new RequestContentLengthMismatchError() - } else { - process.emitWarning(new RequestContentLengthMismatchError()); - } + [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.') } - if (socket[kParser].timeout && socket[kParser].timeoutType === TIMEOUT_HEADERS) { - // istanbul ignore else: only for jest - if (socket[kParser].timeout.refresh) { - socket[kParser].timeout.refresh(); - } + 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 introduces a tiny memory leak, as dispatchers are never removed from the map. + // TODO(mcollina): remove te timer when the client/pool do not have any more + // active connections. + this[kClients].set(key, dispatcher); } - resume(client); + return dispatcher.dispatch(opts, handler) } - destroy (err) { - const { socket, client } = this; + async [kClose] () { + const closePromises = []; + for (const client of this[kClients].values()) { + closePromises.push(client.close()); + } + this[kClients].clear(); - socket[kWriting] = false; + await Promise.all(closePromises); + } - if (err) { - assert(client[kRunning] <= 1, 'pipeline should only contain this request'); - util.destroy(socket, err); + async [kDestroy] (err) { + const destroyPromises = []; + for (const client of this[kClients].values()) { + destroyPromises.push(client.destroy(err)); } - } - } + this[kClients].clear(); - function errorRequest (client, request, err) { - try { - request.onError(err); - assert(request.aborted); - } catch (err) { - client.emit('error', err); + await Promise.all(destroyPromises); } } - client = Client; - return client; + agent = Agent; + return agent; } -/* eslint-disable */ - -var fixedQueue; -var hasRequiredFixedQueue; +var proxyAgent; +var hasRequiredProxyAgent; -function requireFixedQueue () { - if (hasRequiredFixedQueue) return fixedQueue; - hasRequiredFixedQueue = 1; +function requireProxyAgent () { + if (hasRequiredProxyAgent) return proxyAgent; + hasRequiredProxyAgent = 1; - // Extracted from node/lib/internal/fixed_queue.js + const { kProxy, kClose, kDestroy, kDispatch, kInterceptors } = requireSymbols$4(); + const { URL } = require$$1$3; + const Agent = requireAgent(); + const Pool = requirePool(); + const DispatcherBase = requireDispatcherBase(); + const { InvalidArgumentError, RequestAbortedError, SecureProxyConnectionError } = requireErrors(); + const buildConnector = requireConnect(); + const Client = requireClient(); - // Currently optimal queue size, tested on V8 6.0 - 6.6. Must be power of two. - const kSize = 2048; - const kMask = kSize - 1; + const kAgent = Symbol('proxy agent'); + const kClient = Symbol('proxy client'); + const kProxyHeaders = Symbol('proxy headers'); + const kRequestTls = Symbol('request tls settings'); + const kProxyTls = Symbol('proxy tls settings'); + const kConnectEndpoint = Symbol('connect endpoint function'); + const kTunnelProxy = Symbol('tunnel proxy'); - // The FixedQueue is implemented as a singly-linked list of fixed-size - // circular buffers. It looks something like this: - // - // head tail - // | | - // v v - // +-----------+ <-----\ +-----------+ <------\ +-----------+ - // | [null] | \----- | next | \------- | next | - // +-----------+ +-----------+ +-----------+ - // | item | <-- bottom | item | <-- bottom | [empty] | - // | item | | item | | [empty] | - // | item | | item | | [empty] | - // | item | | item | | [empty] | - // | item | | item | bottom --> | item | - // | item | | item | | item | - // | ... | | ... | | ... | - // | item | | item | | item | - // | item | | item | | item | - // | [empty] | <-- top | item | | item | - // | [empty] | | item | | item | - // | [empty] | | [empty] | <-- top top --> | [empty] | - // +-----------+ +-----------+ +-----------+ - // - // Or, if there is only one circular buffer, it looks something - // like either of these: - // - // head tail head tail - // | | | | - // v v v v - // +-----------+ +-----------+ - // | [null] | | [null] | - // +-----------+ +-----------+ - // | [empty] | | item | - // | [empty] | | item | - // | item | <-- bottom top --> | [empty] | - // | item | | [empty] | - // | [empty] | <-- top bottom --> | item | - // | [empty] | | item | - // +-----------+ +-----------+ - // - // Adding a value means moving `top` forward by one, removing means - // moving `bottom` forward by one. After reaching the end, the queue - // wraps around. - // - // When `top === bottom` the current queue is empty and when - // `top + 1 === bottom` it's full. This wastes a single space of storage - // but allows much quicker checks. + function defaultProtocolPort (protocol) { + return protocol === 'https:' ? 443 : 80 + } - class FixedCircularBuffer { - constructor() { - this.bottom = 0; - this.top = 0; - this.list = new Array(kSize); - this.next = null; - } + function defaultFactory (origin, opts) { + return new Pool(origin, opts) + } - isEmpty() { - return this.top === this.bottom; - } + const noop = () => {}; - isFull() { - return ((this.top + 1) & kMask) === this.bottom; + function defaultAgentFactory (origin, opts) { + if (opts.connections === 1) { + return new Client(origin, opts) } + return new Pool(origin, opts) + } - push(data) { - this.list[this.top] = data; - this.top = (this.top + 1) & kMask; + class Http1ProxyWrapper 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 }); + } } - shift() { - const nextItem = this.list[this.bottom]; - if (nextItem === undefined) - return null; - this.list[this.bottom] = undefined; - this.bottom = (this.bottom + 1) & kMask; - return nextItem; + [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); + }; + + // Rewrite request as an HTTP1 Proxy request, without tunneling. + const { + origin, + path = '/', + headers = {} + } = opts; + + opts.path = origin + path; + + if (!('host' in headers) && !('Host' in headers)) { + const { host } = new URL(origin); + headers.host = host; + } + opts.headers = { ...this[kProxyHeaders], ...headers }; + + return this.#client[kDispatch](opts, handler) } - } - fixedQueue = class FixedQueue { - constructor() { - this.head = this.tail = new FixedCircularBuffer(); + async [kClose] () { + return this.#client.close() } - isEmpty() { - return this.head.isEmpty(); + async [kDestroy] (err) { + return this.#client.destroy(err) } + } - push(data) { - if (this.head.isFull()) { - // Head is full: Creates a new queue, sets the old queue's `.next` to it, - // and sets it as the new main queue. - this.head = this.head.next = new FixedCircularBuffer(); + class ProxyAgent extends DispatcherBase { + constructor (opts) { + super(); + + if (!opts || (typeof opts === 'object' && !(opts instanceof URL) && !opts.uri)) { + throw new InvalidArgumentError('Proxy uri is mandatory') } - this.head.push(data); - } - shift() { - const tail = this.tail; - const next = tail.shift(); - if (tail.isEmpty() && tail.next !== null) { - // If there is another queue, it forms the new tail. - this.tail = tail.next; + const { clientFactory = defaultFactory } = opts; + if (typeof clientFactory !== 'function') { + throw new InvalidArgumentError('Proxy opts.clientFactory must be a function.') } - return next; - } - }; - return fixedQueue; -} -var poolStats; -var hasRequiredPoolStats; + const { proxyTunnel = true } = opts; -function requirePoolStats () { - if (hasRequiredPoolStats) return poolStats; - hasRequiredPoolStats = 1; - const { kFree, kConnected, kPending, kQueued, kRunning, kSize } = requireSymbols$4(); - const kPool = Symbol('pool'); + const url = this.#getUrl(opts); + const { href, origin, port, protocol, username, password, hostname: proxyHostname } = url; - class PoolStats { - constructor (pool) { - this[kPool] = pool; - } + 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; - get connected () { - return this[kPool][kConnected] - } + if (opts.auth && opts.token) { + throw new InvalidArgumentError('opts.auth cannot be used in combination with opts.token') + } else if (opts.auth) { + /* @deprecated in favour of opts.token */ + 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')}`; + } - get free () { - return this[kPool][kFree] + const connect = buildConnector({ ...opts.proxyTls }); + this[kConnectEndpoint] = buildConnector({ ...opts.requestTls }); + + const agentFactory = opts.factory || defaultAgentFactory; + const factory = (origin, options) => { + const { protocol } = new URL(origin); + if (!this[kTunnelProxy] && protocol === 'http:' && this[kProxy].protocol === 'http:') { + return new Http1ProxyWrapper(this[kProxy].uri, { + headers: this[kProxyHeaders], + connect, + factory: agentFactory + }) + } + return agentFactory(origin, options) + }; + this[kClient] = clientFactory(url, { connect }); + this[kAgent] = new Agent({ + ...opts, + factory, + connect: async (opts, callback) => { + let requestedPath = opts.host; + if (!opts.port) { + requestedPath += `:${defaultProtocolPort(opts.protocol)}`; + } + try { + const { socket, statusCode } = await this[kClient].connect({ + origin, + port, + path: requestedPath, + signal: opts.signal, + headers: { + ...this[kProxyHeaders], + host: opts.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 (opts.protocol !== 'https:') { + callback(null, socket); + return + } + let servername; + if (this[kRequestTls]) { + servername = this[kRequestTls].servername; + } else { + servername = opts.servername; + } + this[kConnectEndpoint]({ ...opts, servername, httpSocket: socket }, callback); + } catch (err) { + if (err.code === 'ERR_TLS_CERT_ALTNAME_INVALID') { + // Throw a custom error to avoid loop in client.js#connect + callback(new SecureProxyConnectionError(err)); + } else { + callback(err); + } + } + } + }); } - get pending () { - return this[kPool][kPending] + dispatch (opts, handler) { + const headers = buildHeaders(opts.headers); + throwIfProxyAuthIsSent(headers); + + if (headers && !('host' in headers) && !('Host' in headers)) { + const { host } = new URL(opts.origin); + headers.host = host; + } + + return this[kAgent].dispatch( + { + ...opts, + headers + }, + handler + ) } - get queued () { - return this[kPool][kQueued] + /** + * @param {import('../types/proxy-agent').ProxyAgent.Options | string | URL} opts + * @returns {URL} + */ + #getUrl (opts) { + if (typeof opts === 'string') { + return new URL(opts) + } else if (opts instanceof URL) { + return opts + } else { + return new URL(opts.uri) + } } - get running () { - return this[kPool][kRunning] + async [kClose] () { + await this[kAgent].close(); + await this[kClient].close(); } - get size () { - return this[kPool][kSize] + async [kDestroy] () { + await this[kAgent].destroy(); + await this[kClient].destroy(); } } - poolStats = PoolStats; - return poolStats; -} - -var poolBase; -var hasRequiredPoolBase; + /** + * @param {string[] | Record} headers + * @returns {Record} + */ + function buildHeaders (headers) { + // When using undici.fetch, the headers list is stored + // as an array. + if (Array.isArray(headers)) { + /** @type {Record} */ + const headersPair = {}; -function requirePoolBase () { - if (hasRequiredPoolBase) return poolBase; - hasRequiredPoolBase = 1; + for (let i = 0; i < headers.length; i += 2) { + headersPair[headers[i]] = headers[i + 1]; + } - const DispatcherBase = requireDispatcherBase(); - const FixedQueue = requireFixedQueue(); - const { kConnected, kSize, kRunning, kPending, kQueued, kBusy, kFree, kUrl, kClose, kDestroy, kDispatch } = requireSymbols$4(); - const PoolStats = requirePoolStats(); + return headersPair + } - const kClients = Symbol('clients'); - const kNeedDrain = Symbol('needDrain'); - const kQueue = Symbol('queue'); - const kClosedResolve = Symbol('closed resolve'); - const kOnDrain = Symbol('onDrain'); - const kOnConnect = Symbol('onConnect'); - const kOnDisconnect = Symbol('onDisconnect'); - const kOnConnectionError = Symbol('onConnectionError'); - const kGetDispatcher = Symbol('get dispatcher'); - const kAddClient = Symbol('add client'); - const kRemoveClient = Symbol('remove client'); - const kStats = Symbol('stats'); + return headers + } - class PoolBase extends DispatcherBase { - constructor () { - super(); + /** + * @param {Record} headers + * + * Previous versions of ProxyAgent suggests the Proxy-Authorization in request headers + * Nevertheless, it was changed and to avoid a security vulnerability by end users + * this check was created. + * It should be removed in the next major version for performance reasons + */ + 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') + } + } - this[kQueue] = new FixedQueue(); - this[kClients] = []; - this[kQueued] = 0; + proxyAgent = ProxyAgent; + return proxyAgent; +} - const pool = this; +var envHttpProxyAgent; +var hasRequiredEnvHttpProxyAgent; - this[kOnDrain] = function onDrain (origin, targets) { - const queue = pool[kQueue]; +function requireEnvHttpProxyAgent () { + if (hasRequiredEnvHttpProxyAgent) return envHttpProxyAgent; + hasRequiredEnvHttpProxyAgent = 1; - let needDrain = false; + const DispatcherBase = requireDispatcherBase(); + const { kClose, kDestroy, kClosed, kDestroyed, kDispatch, kNoProxyAgent, kHttpProxyAgent, kHttpsProxyAgent } = requireSymbols$4(); + const ProxyAgent = requireProxyAgent(); + const Agent = requireAgent(); - while (!needDrain) { - const item = queue.shift(); - if (!item) { - break - } - pool[kQueued]--; - needDrain = !this.dispatch(item.opts, item.handler); - } + const DEFAULT_PORTS = { + 'http:': 80, + 'https:': 443 + }; - this[kNeedDrain] = needDrain; + let experimentalWarned = false; - if (!this[kNeedDrain] && pool[kNeedDrain]) { - pool[kNeedDrain] = false; - pool.emit('drain', origin, [pool, ...targets]); - } + class EnvHttpProxyAgent extends DispatcherBase { + #noProxyValue = null + #noProxyEntries = null + #opts = null - if (pool[kClosedResolve] && queue.isEmpty()) { - Promise - .all(pool[kClients].map(c => c.close())) - .then(pool[kClosedResolve]); - } - }; + constructor (opts = {}) { + super(); + this.#opts = opts; - this[kOnConnect] = (origin, targets) => { - pool.emit('connect', origin, [pool, ...targets]); - }; + if (!experimentalWarned) { + experimentalWarned = true; + process.emitWarning('EnvHttpProxyAgent is experimental, expect them to change at any time.', { + code: 'UNDICI-EHPA' + }); + } - this[kOnDisconnect] = (origin, targets, err) => { - pool.emit('disconnect', origin, [pool, ...targets], err); - }; + const { httpProxy, httpsProxy, noProxy, ...agentOpts } = opts; - this[kOnConnectionError] = (origin, targets, err) => { - pool.emit('connectionError', origin, [pool, ...targets], err); - }; + this[kNoProxyAgent] = new Agent(agentOpts); - this[kStats] = new PoolStats(this); - } + 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]; + } - get [kBusy] () { - return this[kNeedDrain] - } + 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]; + } - get [kConnected] () { - return this[kClients].filter(client => client[kConnected]).length + this.#parseNoProxy(); } - get [kFree] () { - return this[kClients].filter(client => client[kConnected] && !client[kNeedDrain]).length + [kDispatch] (opts, handler) { + const url = new URL(opts.origin); + const agent = this.#getProxyAgentForUrl(url); + return agent.dispatch(opts, handler) } - get [kPending] () { - let ret = this[kQueued]; - for (const { [kPending]: pending } of this[kClients]) { - ret += pending; + async [kClose] () { + await this[kNoProxyAgent].close(); + if (!this[kHttpProxyAgent][kClosed]) { + await this[kHttpProxyAgent].close(); } - return ret - } - - get [kRunning] () { - let ret = 0; - for (const { [kRunning]: running } of this[kClients]) { - ret += running; + if (!this[kHttpsProxyAgent][kClosed]) { + await this[kHttpsProxyAgent].close(); } - return ret } - get [kSize] () { - let ret = this[kQueued]; - for (const { [kSize]: size } of this[kClients]) { - ret += size; + 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); } - return ret } - get stats () { - return this[kStats] - } + #getProxyAgentForUrl (url) { + let { protocol, host: hostname, port } = url; - async [kClose] () { - if (this[kQueue].isEmpty()) { - return Promise.all(this[kClients].map(c => c.close())) - } else { - return new Promise((resolve) => { - this[kClosedResolve] = resolve; - }) + // Stripping ports in this way instead of using parsedUrl.hostname to make + // sure that the brackets around IPv6 addresses are kept. + hostname = hostname.replace(/:\d*$/, '').toLowerCase(); + port = Number.parseInt(port, 10) || DEFAULT_PORTS[protocol] || 0; + if (!this.#shouldProxy(hostname, port)) { + return this[kNoProxyAgent] } + if (protocol === 'https:') { + return this[kHttpsProxyAgent] + } + return this[kHttpProxyAgent] } - async [kDestroy] (err) { - while (true) { - const item = this[kQueue].shift(); - if (!item) { - break - } - item.handler.onError(err); + #shouldProxy (hostname, port) { + if (this.#noProxyChanged) { + this.#parseNoProxy(); } - return Promise.all(this[kClients].map(c => c.destroy(err))) - } - - [kDispatch] (opts, handler) { - const dispatcher = this[kGetDispatcher](); + if (this.#noProxyEntries.length === 0) { + return true // Always proxy if NO_PROXY is not set or empty. + } + if (this.#noProxyValue === '*') { + return false // Never proxy if wildcard is set. + } - 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](); + for (let i = 0; i < this.#noProxyEntries.length; i++) { + const entry = this.#noProxyEntries[i]; + if (entry.port && entry.port !== port) { + continue // Skip if ports don't match. + } + if (!/^[.*]/.test(entry.hostname)) { + // No wildcards, so don't proxy only if there is not an exact match. + if (hostname === entry.hostname) { + return false + } + } else { + // Don't proxy if the hostname ends with the no_proxy host. + if (hostname.endsWith(entry.hostname.replace(/^\*/, ''))) { + return false + } + } } - return !this[kNeedDrain] + return true } - [kAddClient] (client) { - client - .on('drain', this[kOnDrain]) - .on('connect', this[kOnConnect]) - .on('disconnect', this[kOnDisconnect]) - .on('connectionError', this[kOnConnectionError]); - - this[kClients].push(client); + #parseNoProxy () { + const noProxyValue = this.#opts.noProxy ?? this.#noProxyEnv; + const noProxySplit = noProxyValue.split(/[,\s]/); + const noProxyEntries = []; - if (this[kNeedDrain]) { - process.nextTick(() => { - if (this[kNeedDrain]) { - this[kOnDrain](client[kUrl], [this, client]); - } + 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 }); } - return this + this.#noProxyValue = noProxyValue; + this.#noProxyEntries = noProxyEntries; } - [kRemoveClient] (client) { - client.close(() => { - const idx = this[kClients].indexOf(client); - if (idx !== -1) { - this[kClients].splice(idx, 1); - } - }); + get #noProxyChanged () { + if (this.#opts.noProxy !== undefined) { + return false + } + return this.#noProxyValue !== this.#noProxyEnv + } - this[kNeedDrain] = this[kClients].some(dispatcher => ( - !dispatcher[kNeedDrain] && - dispatcher.closed !== true && - dispatcher.destroyed !== true - )); + get #noProxyEnv () { + return process.env.no_proxy ?? process.env.NO_PROXY ?? '' } } - poolBase = { - PoolBase, - kClients, - kNeedDrain, - kAddClient, - kRemoveClient, - kGetDispatcher - }; - return poolBase; + envHttpProxyAgent = EnvHttpProxyAgent; + return envHttpProxyAgent; } -var pool; -var hasRequiredPool; +var retryHandler; +var hasRequiredRetryHandler; -function requirePool () { - if (hasRequiredPool) return pool; - hasRequiredPool = 1; +function requireRetryHandler () { + if (hasRequiredRetryHandler) return retryHandler; + hasRequiredRetryHandler = 1; + const assert = require$$0$3; + const { kRetryHandlerDefaultRetry } = requireSymbols$4(); + const { RequestRetryError } = requireErrors(); const { - PoolBase, - kClients, - kNeedDrain, - kAddClient, - kGetDispatcher - } = requirePoolBase(); - const Client = requireClient(); - const { - InvalidArgumentError - } = requireErrors(); - const util = requireUtil$7(); - const { kUrl, kInterceptors } = requireSymbols$4(); - const buildConnector = requireConnect(); - - const kOptions = Symbol('options'); - const kConnections = Symbol('connections'); - const kFactory = Symbol('factory'); + isDisturbed, + parseHeaders, + parseRangeHeader, + wrapRequestBody + } = requireUtil$8(); - function defaultFactory (origin, opts) { - return new Client(origin, opts) + function calculateRetryAfterHeader (retryAfter) { + const current = Date.now(); + return new Date(retryAfter).getTime() - current } - class Pool extends PoolBase { - constructor (origin, { - connections, - factory = defaultFactory, - connect, - connectTimeout, - tls, - maxCachedSessions, - socketPath, - autoSelectFamily, - autoSelectFamilyAttemptTimeout, - allowH2, - ...options - } = {}) { - super(); - - 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') - } + 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 ?? {}; - if (typeof connect !== 'function') { - connect = buildConnector({ - ...tls, - maxCachedSessions, - allowH2, - socketPath, - timeout: connectTimeout, - ...(util.nodeHasAutoSelectFamily && autoSelectFamily ? { autoSelectFamily, autoSelectFamilyAttemptTimeout } : undefined), - ...connect - }); - } + 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 * 1000, // 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[kInterceptors] = options.interceptors && 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 } - : undefined; - this[kFactory] = factory; + this.retryCount = 0; + this.retryCountCheckpoint = 0; + this.start = 0; + this.end = null; + this.etag = null; + this.resume = null; - this.on('connectionError', (origin, targets, error) => { - // If a connection error occurs, we remove the client from the pool, - // and emit a connectionError event. They will not be re-used. - // Fixes https://github.com/nodejs/undici/issues/3895 - for (const target of targets) { - // Do not use kRemoveClient here, as it will close the client, - // but the client cannot be closed in this state. - const idx = this[kClients].indexOf(target); - if (idx !== -1) { - this[kClients].splice(idx, 1); - } + // Handle possible onConnect duplication + this.handler.onConnect(reason => { + this.aborted = true; + if (this.abort) { + this.abort(reason); + } else { + this.reason = reason; } }); } - [kGetDispatcher] () { - let dispatcher = this[kClients].find(dispatcher => !dispatcher[kNeedDrain]); + onRequestSent () { + if (this.handler.onRequestSent) { + this.handler.onRequestSent(); + } + } - if (dispatcher) { - return dispatcher + onUpgrade (statusCode, headers, socket) { + if (this.handler.onUpgrade) { + this.handler.onUpgrade(statusCode, headers, socket); } + } - if (!this[kConnections] || this[kClients].length < this[kConnections]) { - dispatcher = this[kFactory](this[kUrl], this[kOptions]); - this[kAddClient](dispatcher); + onConnect (abort) { + if (this.aborted) { + abort(this.reason); + } else { + this.abort = abort; } + } - return dispatcher + onBodySent (chunk) { + if (this.handler.onBodySent) return this.handler.onBodySent(chunk) } - } - pool = Pool; - return pool; -} + 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; -var balancedPool; -var hasRequiredBalancedPool; + // Any code that is not a Undici's originated and allowed to retry + if (code && code !== 'UND_ERR_REQ_RETRY' && !errorCodes.includes(code)) { + cb(err); + return + } -function requireBalancedPool () { - if (hasRequiredBalancedPool) return balancedPool; - hasRequiredBalancedPool = 1; + // If a set of method are provided and the current method is not in the list + if (Array.isArray(methods) && !methods.includes(method)) { + cb(err); + return + } - const { - BalancedPoolMissingUpstreamError, - InvalidArgumentError - } = requireErrors(); - const { - PoolBase, - kClients, - kNeedDrain, - kAddClient, - kRemoveClient, - kGetDispatcher - } = requirePoolBase(); - const Pool = requirePool(); - const { kUrl, kInterceptors } = requireSymbols$4(); - const { parseOrigin } = requireUtil$7(); - const kFactory = Symbol('factory'); + // If a set of status code are provided and the current status code is not in the list + if ( + statusCode != null && + Array.isArray(statusCodes) && + !statusCodes.includes(statusCode) + ) { + cb(err); + return + } - const kOptions = Symbol('options'); - const kGreatestCommonDivisor = Symbol('kGreatestCommonDivisor'); - const kCurrentWeight = Symbol('kCurrentWeight'); - const kIndex = Symbol('kIndex'); - const kWeight = Symbol('kWeight'); - const kMaxWeightPerServer = Symbol('kMaxWeightPerServer'); - const kErrorPenalty = Symbol('kErrorPenalty'); + // If we reached the max number of retries + if (counter > maxRetries) { + cb(err); + return + } - function getGreatestCommonDivisor (a, b) { - if (b === 0) return a - return getGreatestCommonDivisor(b, a % b) - } + let retryAfterHeader = headers?.['retry-after']; + if (retryAfterHeader) { + retryAfterHeader = Number(retryAfterHeader); + retryAfterHeader = Number.isNaN(retryAfterHeader) + ? calculateRetryAfterHeader(retryAfterHeader) + : retryAfterHeader * 1e3; // Retry-After is in seconds + } - function defaultFactory (origin, opts) { - return new Pool(origin, opts) - } + const retryTimeout = + retryAfterHeader > 0 + ? Math.min(retryAfterHeader, maxTimeout) + : Math.min(minTimeout * timeoutFactor ** (counter - 1), maxTimeout); - class BalancedPool extends PoolBase { - constructor (upstreams = [], { factory = defaultFactory, ...opts } = {}) { - super(); + setTimeout(() => cb(null), retryTimeout); + } - this[kOptions] = opts; - this[kIndex] = -1; - this[kCurrentWeight] = 0; + onHeaders (statusCode, rawHeaders, resume, statusMessage) { + const headers = parseHeaders(rawHeaders); - this[kMaxWeightPerServer] = this[kOptions].maxWeightPerServer || 100; - this[kErrorPenalty] = this[kOptions].errorPenalty || 15; + this.retryCount += 1; - if (!Array.isArray(upstreams)) { - upstreams = [upstreams]; + 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 (typeof factory !== 'function') { - throw new InvalidArgumentError('factory must be a function.') - } + // Checkpoint for resume from where we left it + if (this.resume != null) { + this.resume = null; - this[kInterceptors] = opts.interceptors && opts.interceptors.BalancedPool && Array.isArray(opts.interceptors.BalancedPool) - ? opts.interceptors.BalancedPool - : []; - this[kFactory] = factory; + // Only Partial Content 206 supposed to provide Content-Range, + // any other status code that partially consumed the payload + // should not be retry because it would result in downstream + // wrongly concatanete multiple responses. + 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 + } - for (const upstream of upstreams) { - this.addUpstream(upstream); - } - this._updateBalancedPoolStats(); - } + const contentRange = parseRangeHeader(headers['content-range']); + // If no content range + if (!contentRange) { + this.abort( + new RequestRetryError('Content-Range mismatch', statusCode, { + headers, + data: { count: this.retryCount } + }) + ); + return false + } - addUpstream (upstream) { - const upstreamOrigin = parseOrigin(upstream).origin; + // Let's start with a weak etag check + if (this.etag != null && this.etag !== headers.etag) { + this.abort( + new RequestRetryError('ETag mismatch', statusCode, { + headers, + data: { count: this.retryCount } + }) + ); + return false + } - if (this[kClients].find((pool) => ( - pool[kUrl].origin === upstreamOrigin && - pool.closed !== true && - pool.destroyed !== true - ))) { - return this + 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 } - 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]); - }); + if (this.end == null) { + if (statusCode === 206) { + // First time we receive 206 + const range = parseRangeHeader(headers['content-range']); - pool.on('connectionError', () => { - pool[kWeight] = Math.max(1, pool[kWeight] - this[kErrorPenalty]); - this._updateBalancedPoolStats(); - }); + if (range == null) { + return this.handler.onHeaders( + statusCode, + rawHeaders, + resume, + statusMessage + ) + } - pool.on('disconnect', (...args) => { - const err = args[2]; - if (err && err.code === 'UND_ERR_SOCKET') { - // decrease the weight of the pool. - pool[kWeight] = Math.max(1, pool[kWeight] - this[kErrorPenalty]); - this._updateBalancedPoolStats(); + 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; } - }); - for (const client of this[kClients]) { - client[kWeight] = this[kMaxWeightPerServer]; - } + // We make our best to checkpoint the body for further range headers + if (this.end == null) { + const contentLength = headers['content-length']; + this.end = contentLength != null ? Number(contentLength) - 1 : null; + } - this._updateBalancedPoolStats(); + assert(Number.isFinite(this.start)); + assert( + this.end == null || Number.isFinite(this.end), + 'invalid content-length' + ); - return this - } + this.resume = resume; + this.etag = headers.etag != null ? headers.etag : null; - _updateBalancedPoolStats () { - this[kGreatestCommonDivisor] = this[kClients].map(p => p[kWeight]).reduce(getGreatestCommonDivisor, 0); - } + // Weak etags are not useful for comparison nor cache + // for instance not safe to assume if the response is byte-per-byte + // equal + if (this.etag != null && this.etag.startsWith('W/')) { + this.etag = null; + } - removeUpstream (upstream) { - const upstreamOrigin = parseOrigin(upstream).origin; + return this.handler.onHeaders( + statusCode, + rawHeaders, + resume, + statusMessage + ) + } - const pool = this[kClients].find((pool) => ( - pool[kUrl].origin === upstreamOrigin && - pool.closed !== true && - pool.destroyed !== true - )); + const err = new RequestRetryError('Request failed', statusCode, { + headers, + data: { count: this.retryCount } + }); - if (pool) { - this[kRemoveClient](pool); - } + this.abort(err); - return this + return false } - get upstreams () { - return this[kClients] - .filter(dispatcher => dispatcher.closed !== true && dispatcher.destroyed !== true) - .map((p) => p[kUrl].origin) - } + onData (chunk) { + this.start += chunk.length; - [kGetDispatcher] () { - // We validate that pools is greater than 0, - // otherwise we would have to wait until an upstream - // is added, which might never happen. - if (this[kClients].length === 0) { - throw new BalancedPoolMissingUpstreamError() - } + return this.handler.onData(chunk) + } - const dispatcher = this[kClients].find(dispatcher => ( - !dispatcher[kNeedDrain] && - dispatcher.closed !== true && - dispatcher.destroyed !== true - )); + onComplete (rawTrailers) { + this.retryCount = 0; + return this.handler.onComplete(rawTrailers) + } - if (!dispatcher) { - return + onError (err) { + if (this.aborted || isDisturbed(this.opts.body)) { + return this.handler.onError(err) } - const allClientsBusy = this[kClients].map(pool => pool[kNeedDrain]).reduce((a, b) => a && b, true); - - if (allClientsBusy) { - return + // We reconcile in case of a mix between network errors + // and server error response + if (this.retryCount - this.retryCountCheckpoint > 0) { + // We count the difference between the last checkpoint and the current retry count + this.retryCount = + this.retryCountCheckpoint + + (this.retryCount - this.retryCountCheckpoint); + } else { + this.retryCount += 1; } - 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]]; + this.retryOpts.retry( + err, + { + state: { counter: this.retryCount }, + opts: { retryOptions: this.retryOpts, ...this.opts } + }, + onRetry.bind(this) + ); - // find pool index with the largest weight - if (pool[kWeight] > this[kClients][maxWeightIndex][kWeight] && !pool[kNeedDrain]) { - maxWeightIndex = this[kIndex]; + function onRetry (err) { + if (err != null || this.aborted || isDisturbed(this.opts.body)) { + return this.handler.onError(err) } - // decrease the current weight every `this[kClients].length`. - if (this[kIndex] === 0) { - // Set the current weight to the next lower weight. - this[kCurrentWeight] = this[kCurrentWeight] - this[kGreatestCommonDivisor]; + if (this.start !== 0) { + const headers = { range: `bytes=${this.start}-${this.end ?? ''}` }; - if (this[kCurrentWeight] <= 0) { - this[kCurrentWeight] = this[kMaxWeightPerServer]; + // Weak etag check - weak etags will make comparison algorithms never match + if (this.etag != null) { + headers['if-match'] = this.etag; } + + this.opts = { + ...this.opts, + headers: { + ...this.opts.headers, + ...headers + } + }; } - if (pool[kWeight] >= this[kCurrentWeight] && (!pool[kNeedDrain])) { - return pool + + try { + this.retryCountCheckpoint = this.retryCount; + this.dispatch(this.opts, this); + } catch (err) { + this.handler.onError(err); } } - - this[kCurrentWeight] = this[kClients][maxWeightIndex][kWeight]; - this[kIndex] = maxWeightIndex; - return this[kClients][maxWeightIndex] } } - balancedPool = BalancedPool; - return balancedPool; + retryHandler = RetryHandler; + return retryHandler; } -var dispatcherWeakref; -var hasRequiredDispatcherWeakref; - -function requireDispatcherWeakref () { - if (hasRequiredDispatcherWeakref) return dispatcherWeakref; - hasRequiredDispatcherWeakref = 1; +var retryAgent; +var hasRequiredRetryAgent; - /* istanbul ignore file: only for Node 12 */ +function requireRetryAgent () { + if (hasRequiredRetryAgent) return retryAgent; + hasRequiredRetryAgent = 1; - const { kConnected, kSize } = requireSymbols$4(); + const Dispatcher = requireDispatcher(); + const RetryHandler = requireRetryHandler(); - class CompatWeakRef { - constructor (value) { - this.value = value; + class RetryAgent extends Dispatcher { + #agent = null + #options = null + constructor (agent, options = {}) { + super(options); + this.#agent = agent; + this.#options = options; } - deref () { - return this.value[kConnected] === 0 && this.value[kSize] === 0 - ? undefined - : this.value + dispatch (opts, handler) { + const retry = new RetryHandler({ + ...opts, + retryOptions: this.#options + }, { + dispatch: this.#agent.dispatch.bind(this.#agent), + handler + }); + return this.#agent.dispatch(opts, retry) } - } - class CompatFinalizer { - constructor (finalizer) { - this.finalizer = finalizer; + close () { + return this.#agent.close() } - register (dispatcher, key) { - if (dispatcher.on) { - dispatcher.on('disconnect', () => { - if (dispatcher[kConnected] === 0 && dispatcher[kSize] === 0) { - this.finalizer(key); - } - }); - } + destroy () { + return this.#agent.destroy() } } - dispatcherWeakref = function () { - // FIXME: remove workaround when the Node bug is fixed - // https://github.com/nodejs/node/issues/49344#issuecomment-1741776308 - if (process.env.NODE_V8_COVERAGE) { - return { - WeakRef: CompatWeakRef, - FinalizationRegistry: CompatFinalizer - } - } - return { - WeakRef: commonjsGlobal.WeakRef || CompatWeakRef, - FinalizationRegistry: commonjsGlobal.FinalizationRegistry || CompatFinalizer - } - }; - return dispatcherWeakref; + retryAgent = RetryAgent; + return retryAgent; } -var agent; -var hasRequiredAgent; +var api = {}; -function requireAgent () { - if (hasRequiredAgent) return agent; - hasRequiredAgent = 1; +var apiRequest = {exports: {}}; - const { InvalidArgumentError } = requireErrors(); - const { kClients, kRunning, kClose, kDestroy, kDispatch, kInterceptors } = requireSymbols$4(); - const DispatcherBase = requireDispatcherBase(); - const Pool = requirePool(); - const Client = requireClient(); - const util = requireUtil$7(); - const createRedirectInterceptor = requireRedirectInterceptor(); - const { WeakRef, FinalizationRegistry } = requireDispatcherWeakref()(); +var readable; +var hasRequiredReadable; - const kOnConnect = Symbol('onConnect'); - const kOnDisconnect = Symbol('onDisconnect'); - const kOnConnectionError = Symbol('onConnectionError'); - const kMaxRedirections = Symbol('maxRedirections'); - const kOnDrain = Symbol('onDrain'); - const kFactory = Symbol('factory'); - const kFinalizer = Symbol('finalizer'); - const kOptions = Symbol('options'); +function requireReadable () { + if (hasRequiredReadable) return readable; + hasRequiredReadable = 1; - function defaultFactory (origin, opts) { - return opts && opts.connections === 1 - ? new Client(origin, opts) - : new Pool(origin, opts) - } + const assert = require$$0$3; + const { Readable } = require$$0$4; + const { RequestAbortedError, NotSupportedError, InvalidArgumentError, AbortError } = requireErrors(); + const util = requireUtil$8(); + const { ReadableStreamFrom } = requireUtil$8(); - class Agent extends DispatcherBase { - constructor ({ factory = defaultFactory, maxRedirections = 0, connect, ...options } = {}) { - super(); - - 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') - } - - if (connect && typeof connect !== 'function') { - connect = { ...connect }; - } - - this[kInterceptors] = options.interceptors && 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 } - : undefined; - this[kMaxRedirections] = maxRedirections; - this[kFactory] = factory; - this[kClients] = new Map(); - this[kFinalizer] = new FinalizationRegistry(/* istanbul ignore next: gc is undeterministic */ key => { - const ref = this[kClients].get(key); - if (ref !== undefined && ref.deref() === undefined) { - this[kClients].delete(key); - } - }); - - const agent = this; - - this[kOnDrain] = (origin, targets) => { - agent.emit('drain', origin, [agent, ...targets]); - }; - - this[kOnConnect] = (origin, targets) => { - agent.emit('connect', origin, [agent, ...targets]); - }; - - this[kOnDisconnect] = (origin, targets, err) => { - agent.emit('disconnect', origin, [agent, ...targets], err); - }; - - this[kOnConnectionError] = (origin, targets, err) => { - agent.emit('connectionError', origin, [agent, ...targets], err); - }; - } - - get [kRunning] () { - let ret = 0; - for (const ref of this[kClients].values()) { - const client = ref.deref(); - /* istanbul ignore next: gc is undeterministic */ - if (client) { - 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.') - } - - const ref = this[kClients].get(key); - - let dispatcher = ref ? ref.deref() : null; - 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, new WeakRef(dispatcher)); - this[kFinalizer].register(dispatcher, key); - } - - return dispatcher.dispatch(opts, handler) - } - - async [kClose] () { - const closePromises = []; - for (const ref of this[kClients].values()) { - const client = ref.deref(); - /* istanbul ignore else: gc is undeterministic */ - if (client) { - closePromises.push(client.close()); - } - } - - await Promise.all(closePromises); - } - - async [kDestroy] (err) { - const destroyPromises = []; - for (const ref of this[kClients].values()) { - const client = ref.deref(); - /* istanbul ignore else: gc is undeterministic */ - if (client) { - destroyPromises.push(client.destroy(err)); - } - } - - await Promise.all(destroyPromises); - } - } - - agent = Agent; - return agent; -} - -var api = {}; - -var apiRequest = {exports: {}}; - -var readable; -var hasRequiredReadable; - -function requireReadable () { - if (hasRequiredReadable) return readable; - hasRequiredReadable = 1; - - const assert = require$$0$3; - const { Readable } = require$$0$5; - const { RequestAbortedError, NotSupportedError, InvalidArgumentError } = requireErrors(); - const util = requireUtil$7(); - const { ReadableStreamFrom, toUSVString } = requireUtil$7(); - - let Blob; - - const kConsume = Symbol('kConsume'); - const kReading = Symbol('kReading'); - const kBody = Symbol('kBody'); - const kAbort = Symbol('abort'); - const kContentType = Symbol('kContentType'); + const kConsume = Symbol('kConsume'); + const kReading = Symbol('kReading'); + const kBody = Symbol('kBody'); + const kAbort = Symbol('kAbort'); + const kContentType = Symbol('kContentType'); + const kContentLength = Symbol('kContentLength'); const noop = () => {}; - readable = class BodyReadable extends Readable { + class BodyReadable extends Readable { constructor ({ resume, abort, contentType = '', + contentLength, highWaterMark = 64 * 1024 // Same as nodejs fs streams. }) { super({ @@ -11852,6 +13590,7 @@ function requireReadable () { this[kConsume] = null; this[kBody] = null; this[kContentType] = contentType; + this[kContentLength] = contentLength; // Is stream being consumed through Readable API? // This is an optimization so that we avoid checking @@ -11861,11 +13600,6 @@ function requireReadable () { } destroy (err) { - if (this.destroyed) { - // Node < 16 - return this - } - if (!err && !this._readableState.endEmitted) { err = new RequestAbortedError(); } @@ -11877,15 +13611,18 @@ function requireReadable () { return super.destroy(err) } - emit (ev, ...args) { - if (ev === 'data') { - // Node < 16.7 - this._readableState.dataEmitted = true; - } else if (ev === 'error') { - // Node < 16 - this._readableState.errorEmitted = true; + _destroy (err, callback) { + // Workaround for Node "bug". If the stream is destroyed in same + // tick as it is created, then a user who is waiting for a + // promise (i.e micro tick) for installing a 'error' listener will + // never get a chance and will always encounter an unhandled exception. + if (!this[kReading]) { + setImmediate(() => { + callback(err); + }); + } else { + callback(err); } - return super.emit(ev, ...args) } on (ev, ...args) { @@ -11915,7 +13652,7 @@ function requireReadable () { } push (chunk) { - if (this[kConsume] && chunk !== null && this.readableLength === 0) { + if (this[kConsume] && chunk !== null) { consumePush(this[kConsume], chunk); return this[kReading] ? super.push(chunk) : true } @@ -11937,6 +13674,11 @@ function requireReadable () { 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') @@ -11966,37 +13708,35 @@ function requireReadable () { return this[kBody] } - dump (opts) { - let limit = opts && Number.isFinite(opts.limit) ? opts.limit : 262144; - const signal = opts && opts.signal; + async dump (opts) { + let limit = Number.isFinite(opts?.limit) ? opts.limit : 128 * 1024; + const signal = opts?.signal; - if (signal) { - try { - if (typeof signal !== 'object' || !('aborted' in signal)) { - throw new InvalidArgumentError('signal must be an AbortSignal') - } - util.throwIfAborted(signal); - } catch (err) { - return Promise.reject(err) - } + if (signal != null && (typeof signal !== 'object' || !('aborted' in signal))) { + throw new InvalidArgumentError('signal must be an AbortSignal') } - if (this.closed) { - return Promise.resolve(null) + signal?.throwIfAborted(); + + if (this._readableState.closeEmitted) { + return null } - return new Promise((resolve, reject) => { - const signalListenerCleanup = signal - ? util.addAbortListener(signal, () => { - this.destroy(); - }) - : noop; + 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 () { - signalListenerCleanup(); - if (signal && signal.aborted) { - reject(signal.reason || Object.assign(new Error('The operation was aborted'), { name: 'AbortError' })); + signal?.removeEventListener('abort', onAbort); + if (signal?.aborted) { + reject(signal.reason ?? new AbortError()); } else { resolve(null); } @@ -12011,7 +13751,7 @@ function requireReadable () { .resume(); }) } - }; + } // https://streams.spec.whatwg.org/#readablestream-locked function isLocked (self) { @@ -12025,33 +13765,46 @@ function requireReadable () { } async function consume (stream, type) { - if (isUnusable(stream)) { - throw new TypeError('unusable') - } - assert(!stream[kConsume]); return new Promise((resolve, reject) => { - stream[kConsume] = { - type, - stream, - resolve, - reject, - length: 0, - body: [] - }; + 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()); - } - }); + stream + .on('error', function (err) { + consumeFinish(this[kConsume], err); + }) + .on('close', function () { + if (this[kConsume].body !== null) { + consumeFinish(this[kConsume], new RequestAbortedError()); + } + }); - process.nextTick(consumeStart, stream[kConsume]); + consumeStart(stream[kConsume]); + }); + } }) } @@ -12062,8 +13815,16 @@ function requireReadable () { const { _readableState: state } = consume.stream; - for (const chunk of state.buffer) { - consumePush(consume, chunk); + if (state.bufferIndex) { + const start = state.bufferIndex; + const end = state.buffer.length; + for (let n = start; n < end; n++) { + consumePush(consume, state.buffer[n]); + } + } else { + for (const chunk of state.buffer) { + consumePush(consume, chunk); + } } if (state.endEmitted) { @@ -12081,29 +13842,67 @@ function requireReadable () { } } + /** + * @param {Buffer[]} chunks + * @param {number} length + */ + 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; + + // Skip BOM. + const start = + bufferLength > 2 && + buffer[0] === 0xef && + buffer[1] === 0xbb && + buffer[2] === 0xbf + ? 3 + : 0; + return buffer.utf8Slice(start, bufferLength) + } + + /** + * @param {Buffer[]} chunks + * @param {number} length + * @returns {Uint8Array} + */ + function chunksConcat (chunks, length) { + if (chunks.length === 0 || length === 0) { + return new Uint8Array(0) + } + if (chunks.length === 1) { + // fast-path + 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 (consume) { const { type, body, resolve, stream, length } = consume; try { if (type === 'text') { - resolve(toUSVString(Buffer.concat(body))); + resolve(chunksDecode(body, length)); } else if (type === 'json') { - resolve(JSON.parse(Buffer.concat(body))); + resolve(JSON.parse(chunksDecode(body, length))); } else if (type === 'arrayBuffer') { - const dst = new Uint8Array(length); - - let pos = 0; - for (const buf of body) { - dst.set(buf, pos); - pos += buf.byteLength; - } - - resolve(dst.buffer); + resolve(chunksConcat(body, length).buffer); } else if (type === 'blob') { - if (!Blob) { - Blob = require('buffer').Blob; - } resolve(new Blob(body, { type: stream[kContentType] })); + } else if (type === 'bytes') { + resolve(chunksConcat(body, length)); } consumeFinish(consume); @@ -12135,125 +13934,111 @@ function requireReadable () { consume.length = 0; consume.body = null; } + + readable = { Readable: BodyReadable, chunksDecode }; return readable; } -var util$5; -var hasRequiredUtil$5; +var util$6; +var hasRequiredUtil$6; -function requireUtil$5 () { - if (hasRequiredUtil$5) return util$5; - hasRequiredUtil$5 = 1; +function requireUtil$6 () { + if (hasRequiredUtil$6) return util$6; + hasRequiredUtil$6 = 1; const assert = require$$0$3; const { ResponseStatusCodeError } = requireErrors(); - const { toUSVString } = requireUtil$7(); + + const { chunksDecode } = requireReadable(); + const CHUNK_LIMIT = 128 * 1024; async function getResolveErrorBodyCallback ({ callback, body, contentType, statusCode, statusMessage, headers }) { assert(body); let chunks = []; - let limit = 0; - - for await (const chunk of body) { - chunks.push(chunk); - limit += chunk.length; - if (limit > 128 * 1024) { - chunks = null; - break - } - } - - if (statusCode === 204 || !contentType || !chunks) { - process.nextTick(callback, new ResponseStatusCodeError(`Response status code ${statusCode}${statusMessage ? `: ${statusMessage}` : ''}`, statusCode, headers)); - return - } + let length = 0; try { - if (contentType.startsWith('application/json')) { - const payload = JSON.parse(toUSVString(Buffer.concat(chunks))); - process.nextTick(callback, new ResponseStatusCodeError(`Response status code ${statusCode}${statusMessage ? `: ${statusMessage}` : ''}`, statusCode, headers, payload)); - return - } - - if (contentType.startsWith('text/')) { - const payload = toUSVString(Buffer.concat(chunks)); - process.nextTick(callback, new ResponseStatusCodeError(`Response status code ${statusCode}${statusMessage ? `: ${statusMessage}` : ''}`, statusCode, headers, payload)); - return + for await (const chunk of body) { + chunks.push(chunk); + length += chunk.length; + if (length > CHUNK_LIMIT) { + chunks = []; + length = 0; + break + } } - } catch (err) { - // Process in a fallback if error - } - - process.nextTick(callback, new ResponseStatusCodeError(`Response status code ${statusCode}${statusMessage ? `: ${statusMessage}` : ''}`, statusCode, headers)); - } - - util$5 = { getResolveErrorBodyCallback }; - return util$5; -} - -var abortSignal; -var hasRequiredAbortSignal; - -function requireAbortSignal () { - if (hasRequiredAbortSignal) return abortSignal; - hasRequiredAbortSignal = 1; - const { addAbortListener } = requireUtil$7(); - const { RequestAbortedError } = requireErrors(); - - const kListener = Symbol('kListener'); - const kSignal = Symbol('kSignal'); - - function abort (self) { - if (self.abort) { - self.abort(); - } else { - self.onError(new RequestAbortedError()); + } catch { + chunks = []; + length = 0; + // Do nothing.... } - } - function addSignal (self, signal) { - self[kSignal] = null; - self[kListener] = null; + const message = `Response status code ${statusCode}${statusMessage ? `: ${statusMessage}` : ''}`; - if (!signal) { + if (statusCode === 204 || !contentType || !length) { + queueMicrotask(() => callback(new ResponseStatusCodeError(message, statusCode, headers))); return } - if (signal.aborted) { - abort(self); - return - } - - self[kSignal] = signal; - self[kListener] = () => { - abort(self); - }; - - addAbortListener(self[kSignal], self[kListener]); - } + const stackTraceLimit = Error.stackTraceLimit; + Error.stackTraceLimit = 0; + let payload; - function removeSignal (self) { - if (!self[kSignal]) { - return + try { + if (isContentTypeApplicationJson(contentType)) { + payload = JSON.parse(chunksDecode(chunks, length)); + } else if (isContentTypeText(contentType)) { + payload = chunksDecode(chunks, length); + } + } catch { + // process in a callback to avoid throwing in the microtask queue + } finally { + Error.stackTraceLimit = stackTraceLimit; } + queueMicrotask(() => callback(new ResponseStatusCodeError(message, statusCode, headers, payload))); + } - if ('removeEventListener' in self[kSignal]) { - self[kSignal].removeEventListener('abort', self[kListener]); - } else { - self[kSignal].removeListener('abort', self[kListener]); - } + const 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' + ) + }; - self[kSignal] = null; - self[kListener] = null; - } + const isContentTypeText = (contentType) => { + return ( + contentType.length > 4 && + contentType[4] === '/' && + contentType[0] === 't' && + contentType[1] === 'e' && + contentType[2] === 'x' && + contentType[3] === 't' + ) + }; - abortSignal = { - addSignal, - removeSignal + util$6 = { + getResolveErrorBodyCallback, + isContentTypeApplicationJson, + isContentTypeText }; - return abortSignal; + return util$6; } var hasRequiredApiRequest; @@ -12262,15 +14047,12 @@ function requireApiRequest () { if (hasRequiredApiRequest) return apiRequest.exports; hasRequiredApiRequest = 1; - const Readable = requireReadable(); - const { - InvalidArgumentError, - RequestAbortedError - } = requireErrors(); - const util = requireUtil$7(); - const { getResolveErrorBodyCallback } = requireUtil$5(); - const { AsyncResource } = require$$4$2; - const { addSignal, removeSignal } = requireAbortSignal(); + const assert = require$$0$3; + const { Readable } = requireReadable(); + const { InvalidArgumentError, RequestAbortedError } = requireErrors(); + const util = requireUtil$8(); + const { getResolveErrorBodyCallback } = requireUtil$6(); + const { AsyncResource } = require$$5$2; class RequestHandler extends AsyncResource { constructor (opts, callback) { @@ -12309,6 +14091,7 @@ function requireApiRequest () { throw err } + this.method = method; this.responseHeaders = responseHeaders || null; this.opaque = opaque || null; this.callback = callback; @@ -12320,6 +14103,9 @@ function requireApiRequest () { 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) => { @@ -12327,14 +14113,36 @@ function requireApiRequest () { }); } - addSignal(this, signal); + 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.callback) { - throw new RequestAbortedError() + if (this.reason) { + abort(this.reason); + return } + assert(this.callback); + this.abort = abort; this.context = context; } @@ -12353,14 +14161,27 @@ function requireApiRequest () { const parsedHeaders = responseHeaders === 'raw' ? util.parseHeaders(rawHeaders) : headers; const contentType = parsedHeaders['content-type']; - const body = new Readable({ resume, abort, contentType, highWaterMark }); + const contentLength = parsedHeaders['content-length']; + const res = new Readable({ + 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 = body; + this.res = res; if (callback !== null) { if (this.throwOnError && statusCode >= 400) { this.runInAsyncScope(getResolveErrorBodyCallback, null, - { callback, body, contentType, statusCode, statusMessage, headers } + { callback, body: res, contentType, statusCode, statusMessage, headers } ); } else { this.runInAsyncScope(callback, null, null, { @@ -12368,7 +14189,7 @@ function requireApiRequest () { headers, trailers: this.trailers, opaque, - body, + body: res, context }); } @@ -12376,25 +14197,17 @@ function requireApiRequest () { } onData (chunk) { - const { res } = this; - return res.push(chunk) + return this.res.push(chunk) } onComplete (trailers) { - const { res } = this; - - removeSignal(this); - util.parseHeaders(trailers, this.trailers); - - res.push(null); + this.res.push(null); } onError (err) { const { res, callback, body, opaque } = this; - removeSignal(this); - if (callback) { // TODO: Does this need queueMicrotask? this.callback = null; @@ -12415,6 +14228,12 @@ function requireApiRequest () { this.body = null; util.destroy(body, err); } + + if (this.removeAbortListener) { + res?.off('close', this.removeAbortListener); + this.removeAbortListener(); + this.removeAbortListener = null; + } } } @@ -12433,7 +14252,7 @@ function requireApiRequest () { if (typeof callback !== 'function') { throw err } - const opaque = opts && opts.opaque; + const opaque = opts?.opaque; queueMicrotask(() => callback(err, { opaque })); } } @@ -12443,6 +14262,72 @@ function requireApiRequest () { return apiRequest.exports; } +var abortSignal; +var hasRequiredAbortSignal; + +function requireAbortSignal () { + if (hasRequiredAbortSignal) return abortSignal; + hasRequiredAbortSignal = 1; + const { addAbortListener } = requireUtil$8(); + const { RequestAbortedError } = requireErrors(); + + const kListener = Symbol('kListener'); + const kSignal = 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; + } + + abortSignal = { + addSignal, + removeSignal + }; + return abortSignal; +} + var apiStream; var hasRequiredApiStream; @@ -12450,15 +14335,12 @@ function requireApiStream () { if (hasRequiredApiStream) return apiStream; hasRequiredApiStream = 1; - const { finished, PassThrough } = require$$0$5; - const { - InvalidArgumentError, - InvalidReturnValueError, - RequestAbortedError - } = requireErrors(); - const util = requireUtil$7(); - const { getResolveErrorBodyCallback } = requireUtil$5(); - const { AsyncResource } = require$$4$2; + const assert = require$$0$3; + const { finished, PassThrough } = require$$0$4; + const { InvalidArgumentError, InvalidReturnValueError } = requireErrors(); + const util = requireUtil$8(); + const { getResolveErrorBodyCallback } = requireUtil$6(); + const { AsyncResource } = require$$5$2; const { addSignal, removeSignal } = requireAbortSignal(); class StreamHandler extends AsyncResource { @@ -12520,10 +14402,13 @@ function requireApiStream () { } onConnect (abort, context) { - if (!this.callback) { - throw new RequestAbortedError() + if (this.reason) { + abort(this.reason); + return } + assert(this.callback); + this.abort = abort; this.context = context; } @@ -12598,7 +14483,7 @@ function requireApiStream () { const needDrain = res.writableNeedDrain !== undefined ? res.writableNeedDrain - : res._writableState && res._writableState.needDrain; + : res._writableState?.needDrain; return needDrain !== true } @@ -12662,7 +14547,7 @@ function requireApiStream () { if (typeof callback !== 'function') { throw err } - const opaque = opts && opts.opaque; + const opaque = opts?.opaque; queueMicrotask(() => callback(err, { opaque })); } } @@ -12682,14 +14567,14 @@ function requireApiPipeline () { Readable, Duplex, PassThrough - } = require$$0$5; + } = require$$0$4; const { InvalidArgumentError, InvalidReturnValueError, RequestAbortedError } = requireErrors(); - const util = requireUtil$7(); - const { AsyncResource } = require$$4$2; + const util = requireUtil$8(); + const { AsyncResource } = require$$5$2; const { addSignal, removeSignal } = requireAbortSignal(); const assert = require$$0$3; @@ -12778,7 +14663,7 @@ function requireApiPipeline () { read: () => { const { body } = this; - if (body && body.resume) { + if (body?.resume) { body.resume(); } }, @@ -12825,12 +14710,14 @@ function requireApiPipeline () { onConnect (abort, context) { const { ret, res } = this; - assert(!res, 'pipeline cannot be retried'); - - if (ret.destroyed) { - throw new RequestAbortedError() + if (this.reason) { + abort(this.reason); + return } + assert(!res, 'pipeline cannot be retried'); + assert(!ret.destroyed); + this.abort = abort; this.context = context; } @@ -12935,9 +14822,9 @@ function requireApiUpgrade () { if (hasRequiredApiUpgrade) return apiUpgrade; hasRequiredApiUpgrade = 1; - const { InvalidArgumentError, RequestAbortedError, SocketError } = requireErrors(); - const { AsyncResource } = require$$4$2; - const util = requireUtil$7(); + const { InvalidArgumentError, SocketError } = requireErrors(); + const { AsyncResource } = require$$5$2; + const util = requireUtil$8(); const { addSignal, removeSignal } = requireAbortSignal(); const assert = require$$0$3; @@ -12969,10 +14856,13 @@ function requireApiUpgrade () { } onConnect (abort, context) { - if (!this.callback) { - throw new RequestAbortedError() + if (this.reason) { + abort(this.reason); + return } + assert(this.callback); + this.abort = abort; this.context = null; } @@ -12982,9 +14872,9 @@ function requireApiUpgrade () { } onUpgrade (statusCode, rawHeaders, socket) { - const { callback, opaque, context } = this; + assert(statusCode === 101); - assert.strictEqual(statusCode, 101); + const { callback, opaque, context } = this; removeSignal(this); @@ -13032,7 +14922,7 @@ function requireApiUpgrade () { if (typeof callback !== 'function') { throw err } - const opaque = opts && opts.opaque; + const opaque = opts?.opaque; queueMicrotask(() => callback(err, { opaque })); } } @@ -13048,9 +14938,10 @@ function requireApiConnect () { if (hasRequiredApiConnect) return apiConnect; hasRequiredApiConnect = 1; - const { AsyncResource } = require$$4$2; - const { InvalidArgumentError, RequestAbortedError, SocketError } = requireErrors(); - const util = requireUtil$7(); + const assert = require$$0$3; + const { AsyncResource } = require$$5$2; + const { InvalidArgumentError, SocketError } = requireErrors(); + const util = requireUtil$8(); const { addSignal, removeSignal } = requireAbortSignal(); class ConnectHandler extends AsyncResource { @@ -13080,10 +14971,13 @@ function requireApiConnect () { } onConnect (abort, context) { - if (!this.callback) { - throw new RequestAbortedError() + if (this.reason) { + abort(this.reason); + return } + assert(this.callback); + this.abort = abort; this.context = context; } @@ -13144,7 +15038,7 @@ function requireApiConnect () { if (typeof callback !== 'function') { throw err } - const opaque = opts && opts.opaque; + const opaque = opts?.opaque; queueMicrotask(() => callback(err, { opaque })); } } @@ -13176,6 +15070,11 @@ function requireMockErrors () { const { UndiciError } = requireErrors(); + const kMockNotMatchedError = Symbol.for('undici.error.UND_MOCK_ERR_MOCK_NOT_MATCHED'); + + /** + * The request does not match any registered mock dispatches. + */ class MockNotMatchedError extends UndiciError { constructor (message) { super(message); @@ -13184,6 +15083,12 @@ function requireMockErrors () { 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 } mockErrors = { @@ -13238,13 +15143,13 @@ function requireMockUtils () { kOrigin, kGetNetConnect } = requireMockSymbols(); - const { buildURL, nop } = requireUtil$7(); + const { buildURL } = requireUtil$8(); const { STATUS_CODES } = require$$2$1; const { types: { isPromise } - } = require$$0$2; + } = require$$0$6; function matchValue (match, value) { if (typeof match === 'string') { @@ -13348,6 +15253,10 @@ function requireMockUtils () { 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 { @@ -13368,19 +15277,20 @@ function requireMockUtils () { // Match method matchedMockDispatches = matchedMockDispatches.filter(({ method }) => matchValue(method, key.method)); if (matchedMockDispatches.length === 0) { - throw new MockNotMatchedError(`Mock dispatch not matched for method '${key.method}'`) + throw new MockNotMatchedError(`Mock dispatch not matched for method '${key.method}' on path '${resolvedPath}'`) } // Match body 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}'`) + throw new MockNotMatchedError(`Mock dispatch not matched for body '${key.body}' on path '${resolvedPath}'`) } // Match headers matchedMockDispatches = matchedMockDispatches.filter((mockDispatch) => matchHeaders(mockDispatch, key.headers)); if (matchedMockDispatches.length === 0) { - throw new MockNotMatchedError(`Mock dispatch not matched for headers '${typeof key.headers === 'object' ? JSON.stringify(key.headers) : key.headers}'`) + 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] @@ -13418,11 +15328,21 @@ function requireMockUtils () { } function generateKeyValues (data) { - return Object.entries(data).reduce((keyValuePairs, [key, value]) => [ - ...keyValuePairs, - Buffer.from(`${key}`), - Array.isArray(value) ? value.map(x => Buffer.from(`${x}`)) : Buffer.from(`${value}`) - ], []) + 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 } /** @@ -13504,10 +15424,10 @@ function requireMockUtils () { const responseHeaders = generateKeyValues(headers); const responseTrailers = generateKeyValues(trailers); - handler.abort = nop; - handler.onHeaders(statusCode, responseHeaders, resume, getStatusText(statusCode)); - handler.onData(Buffer.from(responseData)); - handler.onComplete(responseTrailers); + 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); } @@ -13577,7 +15497,8 @@ function requireMockUtils () { buildMockDispatch, checkNetConnect, buildMockOptions, - getHeaderByName + getHeaderByName, + buildHeadersFromArray }; return mockUtils; } @@ -13600,7 +15521,7 @@ function requireMockInterceptor () { kMockDispatch } = requireMockSymbols(); const { InvalidArgumentError } = requireErrors(); - const { buildURL } = requireUtil$7(); + const { buildURL } = requireUtil$8(); /** * Defines the scope API for an interceptor reply @@ -13664,7 +15585,7 @@ function requireMockInterceptor () { if (opts.query) { opts.path = buildURL(opts.path, opts.query); } else { - // Matches https://github.com/nodejs/undici/blob/main/lib/fetch/index.js#L1811 + // Matches https://github.com/nodejs/undici/blob/main/lib/web/fetch/index.js#L1811 const parsedURL = new URL(opts.path, 'data://'); opts.path = parsedURL.pathname + parsedURL.search; } @@ -13680,7 +15601,7 @@ function requireMockInterceptor () { this[kContentLength] = false; } - createMockScopeDispatchData (statusCode, data, responseOptions = {}) { + createMockScopeDispatchData ({ statusCode, data, responseOptions }) { const responseData = getResponseData(data); const contentLength = this[kContentLength] ? { 'content-length': responseData.length } : {}; const headers = { ...this[kDefaultHeaders], ...contentLength, ...responseOptions.headers }; @@ -13689,14 +15610,11 @@ function requireMockInterceptor () { return { statusCode, data, headers, trailers } } - validateReplyParameters (statusCode, data, responseOptions) { - if (typeof statusCode === 'undefined') { + validateReplyParameters (replyParameters) { + if (typeof replyParameters.statusCode === 'undefined') { throw new InvalidArgumentError('statusCode must be defined') } - if (typeof data === 'undefined') { - throw new InvalidArgumentError('data must be defined') - } - if (typeof responseOptions !== 'object') { + if (typeof replyParameters.responseOptions !== 'object' || replyParameters.responseOptions === null) { throw new InvalidArgumentError('responseOptions must be an object') } } @@ -13704,28 +15622,28 @@ function requireMockInterceptor () { /** * Mock an undici request with a defined reply. */ - reply (replyData) { + reply (replyOptionsCallbackOrStatusCode) { // Values of reply aren't available right now as they // can only be available when the reply callback is invoked. - if (typeof replyData === 'function') { + if (typeof replyOptionsCallbackOrStatusCode === 'function') { // We'll first wrap the provided callback in another function, // this function will properly resolve the data from the callback // when invoked. const wrappedDefaultsCallback = (opts) => { // Our reply options callback contains the parameter for statusCode, data and options. - const resolvedData = replyData(opts); + const resolvedData = replyOptionsCallbackOrStatusCode(opts); // Check if it is in the right format - if (typeof resolvedData !== 'object') { + if (typeof resolvedData !== 'object' || resolvedData === null) { throw new InvalidArgumentError('reply options callback must return an object') } - const { statusCode, data = '', responseOptions = {} } = resolvedData; - this.validateReplyParameters(statusCode, data, responseOptions); + const replyParameters = { data: '', responseOptions: {}, ...resolvedData }; + this.validateReplyParameters(replyParameters); // Since the values can be obtained immediately we return them // from this higher order function that will be resolved later. return { - ...this.createMockScopeDispatchData(statusCode, data, responseOptions) + ...this.createMockScopeDispatchData(replyParameters) } }; @@ -13738,11 +15656,15 @@ function requireMockInterceptor () { // we should have 1-3 parameters. So we spread the arguments of // this function to obtain the parameters, since replyData will always // just be the statusCode. - const [statusCode, data = '', responseOptions = {}] = [...arguments]; - this.validateReplyParameters(statusCode, data, responseOptions); + const replyParameters = { + statusCode: replyOptionsCallbackOrStatusCode, + data: arguments[1] === undefined ? '' : arguments[1], + responseOptions: arguments[2] === undefined ? {} : arguments[2] + }; + this.validateReplyParameters(replyParameters); // Send in-already provided data like usual - const dispatchData = this.createMockScopeDispatchData(statusCode, data, responseOptions); + const dispatchData = this.createMockScopeDispatchData(replyParameters); const newMockDispatch = addMockDispatch(this[kDispatches], this[kDispatchKey], dispatchData); return new MockScope(newMockDispatch) } @@ -13804,7 +15726,7 @@ function requireMockClient () { if (hasRequiredMockClient) return mockClient; hasRequiredMockClient = 1; - const { promisify } = require$$0$2; + const { promisify } = require$$0$6; const Client = requireClient(); const { buildMockDispatch } = requireMockUtils(); const { @@ -13871,7 +15793,7 @@ function requireMockPool () { if (hasRequiredMockPool) return mockPool; hasRequiredMockPool = 1; - const { promisify } = require$$0$2; + const { promisify } = require$$0$6; const Pool = requirePool(); const { buildMockDispatch } = requireMockUtils(); const { @@ -13975,8 +15897,11 @@ function requirePendingInterceptorsFormatter () { if (hasRequiredPendingInterceptorsFormatter) return pendingInterceptorsFormatter; hasRequiredPendingInterceptorsFormatter = 1; - const { Transform } = require$$0$5; - const { Console } = require$$1$3; + const { Transform } = require$$0$4; + const { Console } = require$$1$4; + + const PERSISTENT = process.versions.icu ? '✅' : 'Y '; + const NOT_PERSISTENT = process.versions.icu ? '❌' : 'N '; /** * Gets the output of `console.table(…)` as a string. @@ -14004,7 +15929,7 @@ function requirePendingInterceptorsFormatter () { Origin: origin, Path: path, 'Status code': statusCode, - Persistent: persist ? '✅' : '❌', + Persistent: persist ? PERSISTENT : NOT_PERSISTENT, Invocations: timesInvoked, Remaining: persist ? Infinity : times - timesInvoked })); @@ -14044,16 +15969,6 @@ function requireMockAgent () { const Pluralizer = requirePluralizer(); const PendingInterceptorsFormatter = requirePendingInterceptorsFormatter(); - class FakeWeakRef { - constructor (value) { - this.value = value; - } - - deref () { - return this.value - } - } - class MockAgent extends Dispatcher { constructor (opts) { super(opts); @@ -14062,10 +15977,10 @@ function requireMockAgent () { this[kIsMockActive] = true; // Instantiate Agent and encapsulate - if ((opts && opts.agent && typeof opts.agent.dispatch !== 'function')) { + if ((opts?.agent && typeof opts.agent.dispatch !== 'function')) { throw new InvalidArgumentError('Argument opts.agent must implement Agent') } - const agent = opts && opts.agent ? opts.agent : new Agent(opts); + const agent = opts?.agent ? opts.agent : new Agent(opts); this[kAgent] = agent; this[kClients] = agent[kClients]; @@ -14126,7 +16041,7 @@ function requireMockAgent () { } [kMockAgentSet] (origin, dispatcher) { - this[kClients].set(origin, new FakeWeakRef(dispatcher)); + this[kClients].set(origin, dispatcher); } [kFactory] (origin) { @@ -14138,9 +16053,9 @@ function requireMockAgent () { [kMockAgentGet] (origin) { // First check if we can immediately find it - const ref = this[kClients].get(origin); - if (ref) { - return ref.deref() + const client = this[kClients].get(origin); + if (client) { + return client } // If the origin is not a string create a dummy parent pool and return to user @@ -14151,8 +16066,7 @@ function requireMockAgent () { } // If we match, create a pool and assign the same dispatches - for (const [keyMatcher, nonExplicitRef] of Array.from(this[kClients])) { - const nonExplicitDispatcher = nonExplicitRef.deref(); + 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); @@ -14170,7 +16084,7 @@ function requireMockAgent () { const mockAgentClients = this[kClients]; return Array.from(mockAgentClients.entries()) - .flatMap(([origin, scope]) => scope.deref()[kDispatches].map(dispatch => ({ ...dispatch, origin }))) + .flatMap(([origin, scope]) => scope[kDispatches].map(dispatch => ({ ...dispatch, origin }))) .filter(({ pending }) => pending) } @@ -14195,629 +16109,669 @@ ${pendingInterceptorsFormatter.format(pending)} return mockAgent; } -var proxyAgent; -var hasRequiredProxyAgent; +var global$1; +var hasRequiredGlobal; -function requireProxyAgent () { - if (hasRequiredProxyAgent) return proxyAgent; - hasRequiredProxyAgent = 1; +function requireGlobal () { + if (hasRequiredGlobal) return global$1; + hasRequiredGlobal = 1; - const { kProxy, kClose, kDestroy, kInterceptors } = requireSymbols$4(); - const { URL } = require$$1$4; + // We include a version number for the Dispatcher API. In case of breaking changes, + // this version number must be increased to avoid conflicts. + const globalDispatcher = Symbol.for('undici.globalDispatcher.1'); + const { InvalidArgumentError } = requireErrors(); const Agent = requireAgent(); - const Pool = requirePool(); - const DispatcherBase = requireDispatcherBase(); - const { InvalidArgumentError, RequestAbortedError } = requireErrors(); - const buildConnector = requireConnect(); - - const kAgent = Symbol('proxy agent'); - const kClient = Symbol('proxy client'); - const kProxyHeaders = Symbol('proxy headers'); - const kRequestTls = Symbol('request tls settings'); - const kProxyTls = Symbol('proxy tls settings'); - const kConnectEndpoint = Symbol('connect endpoint function'); - function defaultProtocolPort (protocol) { - return protocol === 'https:' ? 443 : 80 + if (getGlobalDispatcher() === undefined) { + setGlobalDispatcher(new Agent()); } - function buildProxyOptions (opts) { - if (typeof opts === 'string') { - opts = { uri: opts }; - } - - if (!opts || !opts.uri) { - throw new InvalidArgumentError('Proxy opts.uri is mandatory') - } - - return { - uri: opts.uri, - protocol: opts.protocol || 'https' + 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 defaultFactory (origin, opts) { - return new Pool(origin, opts) + function getGlobalDispatcher () { + return globalThis[globalDispatcher] } - class ProxyAgent extends DispatcherBase { - constructor (opts) { - super(opts); - this[kProxy] = buildProxyOptions(opts); - this[kAgent] = new Agent(opts); - this[kInterceptors] = opts.interceptors && opts.interceptors.ProxyAgent && Array.isArray(opts.interceptors.ProxyAgent) - ? opts.interceptors.ProxyAgent - : []; + global$1 = { + setGlobalDispatcher, + getGlobalDispatcher + }; + return global$1; +} - if (typeof opts === 'string') { - opts = { uri: opts }; - } +var decoratorHandler; +var hasRequiredDecoratorHandler; - if (!opts || !opts.uri) { - throw new InvalidArgumentError('Proxy opts.uri is mandatory') - } +function requireDecoratorHandler () { + if (hasRequiredDecoratorHandler) return decoratorHandler; + hasRequiredDecoratorHandler = 1; - const { clientFactory = defaultFactory } = opts; + decoratorHandler = class DecoratorHandler { + #handler - if (typeof clientFactory !== 'function') { - throw new InvalidArgumentError('Proxy opts.clientFactory must be a function.') + constructor (handler) { + if (typeof handler !== 'object' || handler === null) { + throw new TypeError('handler must be an object') } + this.#handler = handler; + } - this[kRequestTls] = opts.requestTls; - this[kProxyTls] = opts.proxyTls; - this[kProxyHeaders] = opts.headers || {}; + onConnect (...args) { + return this.#handler.onConnect?.(...args) + } - const resolvedUrl = new URL(opts.uri); - const { origin, port, host, username, password } = resolvedUrl; + onError (...args) { + return this.#handler.onError?.(...args) + } - if (opts.auth && opts.token) { - throw new InvalidArgumentError('opts.auth cannot be used in combination with opts.token') - } else if (opts.auth) { - /* @deprecated in favour of opts.token */ - 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')}`; - } + onUpgrade (...args) { + return this.#handler.onUpgrade?.(...args) + } - const connect = buildConnector({ ...opts.proxyTls }); - this[kConnectEndpoint] = buildConnector({ ...opts.requestTls }); - this[kClient] = clientFactory(resolvedUrl, { connect }); - this[kAgent] = new Agent({ - ...opts, - connect: async (opts, callback) => { - let requestedHost = opts.host; - if (!opts.port) { - requestedHost += `:${defaultProtocolPort(opts.protocol)}`; - } - try { - const { socket, statusCode } = await this[kClient].connect({ - origin, - port, - path: requestedHost, - signal: opts.signal, - headers: { - ...this[kProxyHeaders], - host - } - }); - if (statusCode !== 200) { - socket.on('error', () => {}).destroy(); - callback(new RequestAbortedError(`Proxy response (${statusCode}) !== 200 when HTTP Tunneling`)); - } - if (opts.protocol !== 'https:') { - callback(null, socket); - return - } - let servername; - if (this[kRequestTls]) { - servername = this[kRequestTls].servername; - } else { - servername = opts.servername; - } - this[kConnectEndpoint]({ ...opts, servername, httpSocket: socket }, callback); - } catch (err) { - callback(err); - } - } - }); + onResponseStarted (...args) { + return this.#handler.onResponseStarted?.(...args) } - dispatch (opts, handler) { - const { host } = new URL(opts.origin); - const headers = buildHeaders(opts.headers); - throwIfProxyAuthIsSent(headers); - return this[kAgent].dispatch( - { - ...opts, - headers: { - ...headers, - host - } - }, - handler - ) + onHeaders (...args) { + return this.#handler.onHeaders?.(...args) } - async [kClose] () { - await this[kAgent].close(); - await this[kClient].close(); + onData (...args) { + return this.#handler.onData?.(...args) } - async [kDestroy] () { - await this[kAgent].destroy(); - await this[kClient].destroy(); + onComplete (...args) { + return this.#handler.onComplete?.(...args) } - } - /** - * @param {string[] | Record} headers - * @returns {Record} - */ - function buildHeaders (headers) { - // When using undici.fetch, the headers list is stored - // as an array. - if (Array.isArray(headers)) { - /** @type {Record} */ - const headersPair = {}; + onBodySent (...args) { + return this.#handler.onBodySent?.(...args) + } + }; + return decoratorHandler; +} - for (let i = 0; i < headers.length; i += 2) { - headersPair[headers[i]] = headers[i + 1]; - } +var redirect; +var hasRequiredRedirect; - return headersPair - } +function requireRedirect () { + if (hasRequiredRedirect) return redirect; + hasRequiredRedirect = 1; + const RedirectHandler = requireRedirectHandler(); - return headers - } + redirect = opts => { + const globalMaxRedirections = opts?.maxRedirections; + return dispatch => { + return function redirectInterceptor (opts, handler) { + const { maxRedirections = globalMaxRedirections, ...baseOpts } = opts; - /** - * @param {Record} headers - * - * Previous versions of ProxyAgent suggests the Proxy-Authorization in request headers - * Nevertheless, it was changed and to avoid a security vulnerability by end users - * this check was created. - * It should be removed in the next major version for performance reasons - */ - 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') + if (!maxRedirections) { + return dispatch(opts, handler) + } + + const redirectHandler = new RedirectHandler( + dispatch, + maxRedirections, + opts, + handler + ); + + return dispatch(baseOpts, redirectHandler) + } } - } + }; + return redirect; +} - proxyAgent = ProxyAgent; - return proxyAgent; +var retry; +var hasRequiredRetry; + +function requireRetry () { + if (hasRequiredRetry) return retry; + hasRequiredRetry = 1; + const RetryHandler = requireRetryHandler(); + + retry = globalOpts => { + return dispatch => { + return function retryInterceptor (opts, handler) { + return dispatch( + opts, + new RetryHandler( + { ...opts, retryOptions: { ...globalOpts, ...opts.retryOptions } }, + { + handler, + dispatch + } + ) + ) + } + } + }; + return retry; } -var RetryHandler_1; -var hasRequiredRetryHandler; +var dump; +var hasRequiredDump; -function requireRetryHandler () { - if (hasRequiredRetryHandler) return RetryHandler_1; - hasRequiredRetryHandler = 1; - const assert = require$$0$3; +function requireDump () { + if (hasRequiredDump) return dump; + hasRequiredDump = 1; - const { kRetryHandlerDefaultRetry } = requireSymbols$4(); - const { RequestRetryError } = requireErrors(); - const { isDisturbed, parseHeaders, parseRangeHeader } = requireUtil$7(); + const util = requireUtil$8(); + const { InvalidArgumentError, RequestAbortedError } = requireErrors(); + const DecoratorHandler = requireDecoratorHandler(); - function calculateRetryAfterHeader (retryAfter) { - const current = Date.now(); - const diff = new Date(retryAfter).getTime() - current; + class DumpHandler extends DecoratorHandler { + #maxSize = 1024 * 1024 + #abort = null + #dumped = false + #aborted = false + #size = 0 + #reason = null + #handler = null - return diff - } + constructor ({ maxSize }, handler) { + super(handler); - 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 ?? {}; + if (maxSize != null && (!Number.isFinite(maxSize) || maxSize < 1)) { + throw new InvalidArgumentError('maxSize must be a number greater than 0') + } - this.dispatch = handlers.dispatch; - this.handler = handlers.handler; - this.opts = dispatchOpts; - this.abort = null; - this.aborted = false; - this.retryOpts = { - retry: retryFn ?? RetryHandler[kRetryHandlerDefaultRetry], - retryAfter: retryAfter ?? true, - maxTimeout: maxTimeout ?? 30 * 1000, // 30s, - timeout: 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' - ] - }; + this.#maxSize = maxSize ?? this.#maxSize; + this.#handler = handler; + } - this.retryCount = 0; - this.start = 0; - this.end = null; - this.etag = null; - this.resume = null; + onConnect (abort) { + this.#abort = abort; - // Handle possible onConnect duplication - this.handler.onConnect(reason => { - this.aborted = true; - if (this.abort) { - this.abort(reason); - } else { - this.reason = reason; - } - }); + this.#handler.onConnect(this.#customAbort.bind(this)); } - onRequestSent () { - if (this.handler.onRequestSent) { - this.handler.onRequestSent(); - } + #customAbort (reason) { + this.#aborted = true; + this.#reason = reason; } - onUpgrade (statusCode, headers, socket) { - if (this.handler.onUpgrade) { - this.handler.onUpgrade(statusCode, headers, socket); + // 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 + })` + ) } - } - onConnect (abort) { - if (this.aborted) { - abort(this.reason); - } else { - this.abort = abort; + if (this.#aborted) { + return true } + + return this.#handler.onHeaders( + statusCode, + rawHeaders, + resume, + statusMessage + ) } - onBodySent (chunk) { - if (this.handler.onBodySent) return this.handler.onBodySent(chunk) + onError (err) { + if (this.#dumped) { + return + } + + err = this.#reason ?? err; + + this.#handler.onError(err); } - static [kRetryHandlerDefaultRetry] (err, { state, opts }, cb) { - const { statusCode, code, headers } = err; - const { method, retryOptions } = opts; - const { - maxRetries, - timeout, - maxTimeout, - timeoutFactor, - statusCodes, - errorCodes, - methods - } = retryOptions; - let { counter, currentTimeout } = state; + onData (chunk) { + this.#size = this.#size + chunk.length; - currentTimeout = - currentTimeout != null && currentTimeout > 0 ? currentTimeout : timeout; + if (this.#size >= this.#maxSize) { + this.#dumped = true; - // Any code that is not a Undici's originated and allowed to retry - if ( - code && - code !== 'UND_ERR_REQ_RETRY' && - code !== 'UND_ERR_SOCKET' && - !errorCodes.includes(code) - ) { - cb(err); - return + if (this.#aborted) { + this.#handler.onError(this.#reason); + } else { + this.#handler.onComplete([]); + } } - // If a set of method are provided and the current method is not in the list - if (Array.isArray(methods) && !methods.includes(method)) { - cb(err); - return - } + return true + } - // If a set of status code are provided and the current status code is not in the list - if ( - statusCode != null && - Array.isArray(statusCodes) && - !statusCodes.includes(statusCode) - ) { - cb(err); + onComplete (trailers) { + if (this.#dumped) { return } - // If we reached the max number of retries - if (counter > maxRetries) { - cb(err); + if (this.#aborted) { + this.#handler.onError(this.reason); return } - let retryAfterHeader = headers != null && headers['retry-after']; - if (retryAfterHeader) { - retryAfterHeader = Number(retryAfterHeader); - retryAfterHeader = isNaN(retryAfterHeader) - ? calculateRetryAfterHeader(retryAfterHeader) - : retryAfterHeader * 1e3; // Retry-After is in seconds + 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) } + } + } - const retryTimeout = - retryAfterHeader > 0 - ? Math.min(retryAfterHeader, maxTimeout) - : Math.min(currentTimeout * timeoutFactor ** counter, maxTimeout); + dump = createDumpInterceptor; + return dump; +} - state.currentTimeout = retryTimeout; +var dns; +var hasRequiredDns; - setTimeout(() => cb(null), retryTimeout); +function requireDns () { + if (hasRequiredDns) return dns; + hasRequiredDns = 1; + const { isIP } = require$$0$5; + const { lookup } = require$$1$5; + const DecoratorHandler = requireDecoratorHandler(); + const { InvalidArgumentError, InformationalError } = requireErrors(); + const maxInt = Math.pow(2, 31) - 1; + + class DNSInstance { + #maxTTL = 0 + #maxItems = 0 + #records = 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; } - onHeaders (statusCode, rawHeaders, resume, statusMessage) { - const headers = parseHeaders(rawHeaders); + get full () { + return this.#records.size === this.#maxItems + } - this.retryCount += 1; + runLookup (origin, opts, cb) { + const ips = this.#records.get(origin.hostname); - if (statusCode >= 300) { - this.abort( - new RequestRetryError('Request failed', statusCode, { - headers, - count: this.retryCount - }) - ); - return false + // If full, we just return the origin + if (ips == null && this.full) { + cb(null, origin.origin); + return } - // Checkpoint for resume from where we left it - if (this.resume != null) { - this.resume = null; + const newOpts = { + affinity: this.affinity, + dualStack: this.dualStack, + lookup: this.lookup, + pick: this.pick, + ...opts.dns, + maxTTL: this.#maxTTL, + maxItems: this.#maxItems + }; - if (statusCode !== 206) { - return true - } + // If no IPs we lookup + 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 + } - const contentRange = parseRangeHeader(headers['content-range']); - // If no content range - if (!contentRange) { - this.abort( - new RequestRetryError('Content-Range mismatch', statusCode, { - headers, - count: this.retryCount - }) + this.setRecords(origin, addresses); + const records = this.#records.get(origin.hostname); + + const ip = this.pick( + origin, + records, + newOpts.affinity ); - return false - } - // Let's start with a weak etag check - if (this.etag != null && this.etag !== headers.etag) { - this.abort( - new RequestRetryError('ETag mismatch', statusCode, { - headers, - count: this.retryCount - }) + let port; + if (typeof ip.port === 'number') { + port = `:${ip.port}`; + } else if (origin.port !== '') { + port = `:${origin.port}`; + } else { + port = ''; + } + + cb( + null, + `${origin.protocol}//${ + ip.family === 6 ? `[${ip.address}]` : ip.address + }${port}` ); - return false - } + }); + } else { + // If there's IPs we pick + const ip = this.pick( + origin, + ips, + newOpts.affinity + ); - const { start, size, end = size } = contentRange; + // If no IPs we lookup - deleting old records + if (ip == null) { + this.#records.delete(origin.hostname); + this.runLookup(origin, opts, cb); + return + } - assert(this.start === start, 'content-range mismatch'); - assert(this.end == null || this.end === end, 'content-range mismatch'); + let port; + if (typeof ip.port === 'number') { + port = `:${ip.port}`; + } else if (origin.port !== '') { + port = `:${origin.port}`; + } else { + port = ''; + } - this.resume = resume; - return true + cb( + null, + `${origin.protocol}//${ + ip.family === 6 ? `[${ip.address}]` : ip.address + }${port}` + ); } + } - if (this.end == null) { - if (statusCode === 206) { - // First time we receive 206 - const range = parseRangeHeader(headers['content-range']); - - if (range == null) { - return this.handler.onHeaders( - statusCode, - rawHeaders, - resume, - statusMessage - ) + #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 { start, size, end = size } = range; + const results = new Map(); - assert( - start != null && Number.isFinite(start) && this.start !== start, - 'content-range mismatch' - ); - assert(Number.isFinite(start)); - assert( - end != null && Number.isFinite(end) && this.end !== end, - 'invalid content-length' - ); + for (const addr of addresses) { + // On linux we found duplicates, we attempt to remove them with + // the latest record + results.set(`${addr.address}:${addr.family}`, addr); + } - this.start = start; - this.end = end; + cb(null, results.values()); } + ); + } - // We make our best to checkpoint the body for further range headers - if (this.end == null) { - const contentLength = headers['content-length']; - this.end = contentLength != null ? Number(contentLength) : null; + #defaultPick (origin, hostnameRecords, affinity) { + let ip = null; + const { records, offset } = hostnameRecords; + + let family; + if (this.dualStack) { + if (affinity == null) { + // Balance between ip families + if (offset == null || offset === maxInt) { + hostnameRecords.offset = 0; + affinity = 4; + } else { + hostnameRecords.offset++; + affinity = (hostnameRecords.offset & 1) === 1 ? 6 : 4; + } } - assert(Number.isFinite(this.start)); - assert( - this.end == null || Number.isFinite(this.end), - 'invalid content-length' - ); + if (records[affinity] != null && records[affinity].ips.length > 0) { + family = records[affinity]; + } else { + family = records[affinity === 4 ? 6 : 4]; + } + } else { + family = records[affinity]; + } - this.resume = resume; - this.etag = headers.etag != null ? headers.etag : null; + // If no IPs we return null + if (family == null || family.ips.length === 0) { + return ip + } - return this.handler.onHeaders( - statusCode, - rawHeaders, - resume, - statusMessage - ) + if (family.offset == null || family.offset === maxInt) { + family.offset = 0; + } else { + family.offset++; } - const err = new RequestRetryError('Request failed', statusCode, { - headers, - count: this.retryCount - }); + const position = family.offset % family.ips.length; + ip = family.ips[position] ?? null; - this.abort(err); + if (ip == null) { + return ip + } - return false + if (Date.now() - ip.timestamp > ip.ttl) { // record TTL is already in ms + // We delete expired records + // It is possible that they have different TTL, so we manage them individually + family.ips.splice(position, 1); + return this.pick(origin, hostnameRecords, affinity) + } + + return ip } - onData (chunk) { - this.start += chunk.length; + 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') { + // The record TTL is expected to be in ms + record.ttl = Math.min(record.ttl, this.#maxTTL); + } else { + record.ttl = this.#maxTTL; + } - return this.handler.onData(chunk) + const familyRecords = records.records[record.family] ?? { ips: [] }; + + familyRecords.ips.push(record); + records.records[record.family] = familyRecords; + } + + this.#records.set(origin.hostname, records); } - onComplete (rawTrailers) { - this.retryCount = 0; - return this.handler.onComplete(rawTrailers) + getHandler (meta, opts) { + return new DNSDispatchHandler(this, meta, opts) + } + } + + class DNSDispatchHandler 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) { - if (this.aborted || isDisturbed(this.opts.body)) { - return this.handler.onError(err) - } + switch (err.code) { + case 'ETIMEDOUT': + case 'ECONNREFUSED': { + if (this.#state.dualStack) { + // We delete the record and retry + this.#state.runLookup(this.#origin, this.#opts, (err, newOrigin) => { + if (err) { + return this.#handler.onError(err) + } - this.retryOpts.retry( - err, - { - state: { counter: this.retryCount++, currentTimeout: this.retryAfter }, - opts: { retryOptions: this.retryOpts, ...this.opts } - }, - onRetry.bind(this) - ); + const dispatchOpts = { + ...this.#opts, + origin: newOrigin + }; - function onRetry (err) { - if (err != null || this.aborted || isDisturbed(this.opts.body)) { - return this.handler.onError(err) - } + this.#dispatch(dispatchOpts, this); + }); - if (this.start !== 0) { - this.opts = { - ...this.opts, - headers: { - ...this.opts.headers, - range: `bytes=${this.start}-${this.end ?? ''}` - } - }; - } + // if dual-stack disabled, we error out + return + } - try { - this.dispatch(this.opts, this); - } catch (err) { - this.handler.onError(err); + this.#handler.onError(err); + return } + case 'ENOTFOUND': + this.#state.deleteRecord(this.#origin); + // eslint-disable-next-line no-fallthrough + default: + this.#handler.onError(err); + break } } } - RetryHandler_1 = RetryHandler; - return RetryHandler_1; -} - -var global$1; -var hasRequiredGlobal; - -function requireGlobal () { - if (hasRequiredGlobal) return global$1; - hasRequiredGlobal = 1; - - // We include a version number for the Dispatcher API. In case of breaking changes, - // this version number must be increased to avoid conflicts. - const globalDispatcher = Symbol.for('undici.globalDispatcher.1'); - const { InvalidArgumentError } = requireErrors(); - const Agent = requireAgent(); - - if (getGlobalDispatcher() === undefined) { - setGlobalDispatcher(new Agent()); - } - - function setGlobalDispatcher (agent) { - if (!agent || typeof agent.dispatch !== 'function') { - throw new InvalidArgumentError('Argument agent must implement Agent') + dns = interceptorOpts => { + if ( + interceptorOpts?.maxTTL != null && + (typeof interceptorOpts?.maxTTL !== 'number' || interceptorOpts?.maxTTL < 0) + ) { + throw new InvalidArgumentError('Invalid maxTTL. Must be a positive number') } - Object.defineProperty(globalThis, globalDispatcher, { - value: agent, - writable: true, - enumerable: false, - configurable: false - }); - } - - function getGlobalDispatcher () { - return globalThis[globalDispatcher] - } - - global$1 = { - setGlobalDispatcher, - getGlobalDispatcher - }; - return global$1; -} -var DecoratorHandler_1; -var hasRequiredDecoratorHandler; - -function requireDecoratorHandler () { - if (hasRequiredDecoratorHandler) return DecoratorHandler_1; - hasRequiredDecoratorHandler = 1; - - DecoratorHandler_1 = class DecoratorHandler { - constructor (handler) { - this.handler = handler; + 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' + ) } - onConnect (...args) { - return this.handler.onConnect(...args) + if ( + interceptorOpts?.affinity != null && + interceptorOpts?.affinity !== 4 && + interceptorOpts?.affinity !== 6 + ) { + throw new InvalidArgumentError('Invalid affinity. Must be either 4 or 6') } - onError (...args) { - return this.handler.onError(...args) + if ( + interceptorOpts?.dualStack != null && + typeof interceptorOpts?.dualStack !== 'boolean' + ) { + throw new InvalidArgumentError('Invalid dualStack. Must be a boolean') } - onUpgrade (...args) { - return this.handler.onUpgrade(...args) + if ( + interceptorOpts?.lookup != null && + typeof interceptorOpts?.lookup !== 'function' + ) { + throw new InvalidArgumentError('Invalid lookup. Must be a function') } - onHeaders (...args) { - return this.handler.onHeaders(...args) + if ( + interceptorOpts?.pick != null && + typeof interceptorOpts?.pick !== 'function' + ) { + throw new InvalidArgumentError('Invalid pick. Must be a function') } - onData (...args) { - return this.handler.onData(...args) + const dualStack = interceptorOpts?.dualStack ?? true; + let affinity; + if (dualStack) { + affinity = interceptorOpts?.affinity ?? null; + } else { + affinity = interceptorOpts?.affinity ?? 4; } - onComplete (...args) { - return this.handler.onComplete(...args) - } + const opts = { + maxTTL: interceptorOpts?.maxTTL ?? 10e3, // Expressed in ms + lookup: interceptorOpts?.lookup ?? null, + pick: interceptorOpts?.pick ?? null, + dualStack, + affinity, + maxItems: interceptorOpts?.maxItems ?? Infinity + }; - onBodySent (...args) { - return this.handler.onBodySent(...args) + 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 + } } }; - return DecoratorHandler_1; + return dns; } var headers; @@ -14827,17 +16781,16 @@ function requireHeaders () { if (hasRequiredHeaders) return headers; hasRequiredHeaders = 1; - const { kHeadersList, kConstruct } = requireSymbols$4(); - const { kGuard } = requireSymbols$3(); - const { kEnumerableProperty } = requireUtil$7(); + const { kConstruct } = requireSymbols$4(); + const { kEnumerableProperty } = requireUtil$8(); const { - makeIterator, + iteratorMixin, isValidHeaderName, isValidHeaderValue - } = requireUtil$6(); - const util = require$$0$2; + } = requireUtil$7(); const { webidl } = requireWebidl(); const assert = require$$0$3; + const util = require$$0$6; const kHeadersMap = Symbol('headers map'); const kHeadersSortedMap = Symbol('headers map sorted'); @@ -14928,21 +16881,27 @@ function requireHeaders () { // 3. If headers’s guard is "immutable", then throw a TypeError. // 4. Otherwise, if headers’s guard is "request" and name is a // forbidden header name, return. + // 5. Otherwise, if headers’s guard is "request-no-cors": + // TODO // Note: undici does not implement forbidden header names - if (headers[kGuard] === 'immutable') { + if (getHeadersGuard(headers) === 'immutable') { throw new TypeError('immutable') - } else if (headers[kGuard] === 'request-no-cors') ; + } // 6. Otherwise, if headers’s guard is "response" and name is a // forbidden response-header name, return. // 7. Append (name, value) to headers’s header list. - return headers[kHeadersList].append(name, value) + return getHeadersList(headers).append(name, value, false) // 8. If headers’s guard is "request-no-cors", then remove // privileged no-CORS request headers from headers } + function compareHeaderName (a, b) { + return a[0] < b[0] ? -1 : 1 + } + class HeadersList { /** @type {[string, string][]|null} */ cookies = null @@ -14958,14 +16917,17 @@ function requireHeaders () { } } - // https://fetch.spec.whatwg.org/#header-list-contains - contains (name) { + /** + * @see https://fetch.spec.whatwg.org/#header-list-contains + * @param {string} name + * @param {boolean} isLowerCase + */ + contains (name, isLowerCase) { // A header list list contains a header name name if list // contains a header whose name is a byte-case-insensitive // match for name. - name = name.toLowerCase(); - return this[kHeadersMap].has(name) + return this[kHeadersMap].has(isLowerCase ? name : name.toLowerCase()) } clear () { @@ -14974,13 +16936,18 @@ function requireHeaders () { this.cookies = null; } - // https://fetch.spec.whatwg.org/#concept-header-list-append - append (name, value) { + /** + * @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; // 1. If list contains name, then set name to the first such // header’s name. - const lowercaseName = name.toLowerCase(); + const lowercaseName = isLowerCase ? name : name.toLowerCase(); const exists = this[kHeadersMap].get(lowercaseName); // 2. Append (name, value) to list. @@ -14995,15 +16962,19 @@ function requireHeaders () { } if (lowercaseName === 'set-cookie') { - this.cookies ??= []; - this.cookies.push(value); + (this.cookies ??= []).push(value); } } - // https://fetch.spec.whatwg.org/#concept-header-list-set - set (name, 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 = name.toLowerCase(); + const lowercaseName = isLowerCase ? name : name.toLowerCase(); if (lowercaseName === 'set-cookie') { this.cookies = [value]; @@ -15016,11 +16987,14 @@ function requireHeaders () { this[kHeadersMap].set(lowercaseName, { name, value }); } - // https://fetch.spec.whatwg.org/#concept-header-list-delete - delete (name) { + /** + * @see https://fetch.spec.whatwg.org/#concept-header-list-delete + * @param {string} name + * @param {boolean} isLowerCase + */ + delete (name, isLowerCase) { this[kHeadersSortedMap] = null; - - name = name.toLowerCase(); + if (!isLowerCase) name = name.toLowerCase(); if (name === 'set-cookie') { this.cookies = null; @@ -15029,20 +17003,23 @@ function requireHeaders () { this[kHeadersMap].delete(name); } - // https://fetch.spec.whatwg.org/#concept-header-list-get - get (name) { - const value = this[kHeadersMap].get(name.toLowerCase()); - + /** + * @see https://fetch.spec.whatwg.org/#concept-header-list-get + * @param {string} name + * @param {boolean} isLowerCase + * @returns {string | null} + */ + get (name, isLowerCase) { // 1. If list does not contain name, then return null. // 2. Return the values of all headers in list whose name // is a byte-case-insensitive match for name, // separated from each other by 0x2C 0x20, in order. - return value === undefined ? null : value.value + return this[kHeadersMap].get(isLowerCase ? name : name.toLowerCase())?.value ?? null } * [Symbol.iterator] () { // use the lowercased name - for (const [name, { value }] of this[kHeadersMap]) { + for (const { 0: name, 1: { value } } of this[kHeadersMap]) { yield [name, value]; } } @@ -15050,7 +17027,7 @@ function requireHeaders () { get entries () { const headers = {}; - if (this[kHeadersMap].size) { + if (this[kHeadersMap].size !== 0) { for (const { name, value } of this[kHeadersMap].values()) { headers[name] = value; } @@ -15058,24 +17035,125 @@ function requireHeaders () { 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); + // In most cases, you will use the fast-path. + // fast-path: Use binary insertion sort for small arrays. + if (size <= 32) { + if (size === 0) { + // If empty, it is an empty array. To avoid the first index assignment. + return array + } + // Improve performance by unrolling loop and avoiding double-loop. + // Double-loop-less version of the binary insertion sort. + const iterator = this[kHeadersMap][Symbol.iterator](); + const firstValue = iterator.next().value; + // set [name, value] to first index. + array[0] = [firstValue[0], firstValue[1].value]; + // https://fetch.spec.whatwg.org/#concept-header-list-sort-and-combine + // 3.2.2. Assert: value is non-null. + assert(firstValue[1].value !== null); + for ( + let i = 1, j = 0, right = 0, left = 0, pivot = 0, x, value; + i < size; + ++i + ) { + // get next value + value = iterator.next().value; + // set [name, value] to current index. + x = array[i] = [value[0], value[1].value]; + // https://fetch.spec.whatwg.org/#concept-header-list-sort-and-combine + // 3.2.2. Assert: value is non-null. + assert(x[1] !== null); + left = 0; + right = i; + // binary search + while (left < right) { + // middle index + pivot = left + ((right - left) >> 1); + // compare header name + 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; + } + } + /* c8 ignore next 4 */ + if (!iterator.next().done) { + // This is for debugging and will never be called. + throw new TypeError('Unreachable') + } + return array + } else { + // This case would be a rare occurrence. + // slow-path: fallback + let i = 0; + for (const { 0: name, 1: { value } } of this[kHeadersMap]) { + array[i++] = [name, value]; + // https://fetch.spec.whatwg.org/#concept-header-list-sort-and-combine + // 3.2.2. Assert: value is non-null. + assert(value !== null); + } + return array.sort(compareHeaderName) + } + } } // https://fetch.spec.whatwg.org/#headers-class class Headers { + #guard + #headersList + constructor (init = undefined) { + webidl.util.markAsUncloneable(this); + if (init === kConstruct) { return } - this[kHeadersList] = new HeadersList(); + + this.#headersList = new HeadersList(); // The new Headers(init) constructor steps are: // 1. Set this’s guard to "none". - this[kGuard] = 'none'; + this.#guard = 'none'; // 2. If init is given, then fill this with init. if (init !== undefined) { - init = webidl.converters.HeadersInit(init); + init = webidl.converters.HeadersInit(init, 'Headers contructor', 'init'); fill(this, init); } } @@ -15084,10 +17162,11 @@ function requireHeaders () { append (name, value) { webidl.brandCheck(this, Headers); - webidl.argumentLengthCheck(arguments, 2, { header: 'Headers.append' }); + webidl.argumentLengthCheck(arguments, 2, 'Headers.append'); - name = webidl.converters.ByteString(name); - value = webidl.converters.ByteString(value); + const prefix = 'Headers.append'; + name = webidl.converters.ByteString(name, prefix, 'name'); + value = webidl.converters.ByteString(value, prefix, 'value'); return appendHeader(this, name, value) } @@ -15096,9 +17175,10 @@ function requireHeaders () { delete (name) { webidl.brandCheck(this, Headers); - webidl.argumentLengthCheck(arguments, 1, { header: 'Headers.delete' }); + webidl.argumentLengthCheck(arguments, 1, 'Headers.delete'); - name = webidl.converters.ByteString(name); + const prefix = 'Headers.delete'; + name = webidl.converters.ByteString(name, prefix, 'name'); // 1. If name is not a header name, then throw a TypeError. if (!isValidHeaderName(name)) { @@ -15119,34 +17199,35 @@ function requireHeaders () { // 5. Otherwise, if this’s guard is "response" and name is // a forbidden response-header name, return. // Note: undici does not implement forbidden header names - if (this[kGuard] === 'immutable') { + if (this.#guard === 'immutable') { throw new TypeError('immutable') - } else if (this[kGuard] === 'request-no-cors') ; + } // 6. If this’s header list does not contain name, then // return. - if (!this[kHeadersList].contains(name)) { + if (!this.#headersList.contains(name, false)) { return } // 7. Delete name from this’s header list. // 8. If this’s guard is "request-no-cors", then remove // privileged no-CORS request headers from this. - this[kHeadersList].delete(name); + this.#headersList.delete(name, false); } // https://fetch.spec.whatwg.org/#dom-headers-get get (name) { webidl.brandCheck(this, Headers); - webidl.argumentLengthCheck(arguments, 1, { header: 'Headers.get' }); + webidl.argumentLengthCheck(arguments, 1, 'Headers.get'); - name = webidl.converters.ByteString(name); + const prefix = 'Headers.get'; + name = webidl.converters.ByteString(name, prefix, 'name'); // 1. If name is not a header name, then throw a TypeError. if (!isValidHeaderName(name)) { throw webidl.errors.invalidArgument({ - prefix: 'Headers.get', + prefix, value: name, type: 'header name' }) @@ -15154,21 +17235,22 @@ function requireHeaders () { // 2. Return the result of getting name from this’s header // list. - return this[kHeadersList].get(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, { header: 'Headers.has' }); + webidl.argumentLengthCheck(arguments, 1, 'Headers.has'); - name = webidl.converters.ByteString(name); + const prefix = 'Headers.has'; + name = webidl.converters.ByteString(name, prefix, 'name'); // 1. If name is not a header name, then throw a TypeError. if (!isValidHeaderName(name)) { throw webidl.errors.invalidArgument({ - prefix: 'Headers.has', + prefix, value: name, type: 'header name' }) @@ -15176,17 +17258,18 @@ function requireHeaders () { // 2. Return true if this’s header list contains name; // otherwise false. - return this[kHeadersList].contains(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, { header: 'Headers.set' }); + webidl.argumentLengthCheck(arguments, 2, 'Headers.set'); - name = webidl.converters.ByteString(name); - value = webidl.converters.ByteString(value); + const prefix = 'Headers.set'; + name = webidl.converters.ByteString(name, prefix, 'name'); + value = webidl.converters.ByteString(value, prefix, 'value'); // 1. Normalize value. value = headerValueNormalize(value); @@ -15195,13 +17278,13 @@ function requireHeaders () { // header value, then throw a TypeError. if (!isValidHeaderName(name)) { throw webidl.errors.invalidArgument({ - prefix: 'Headers.set', + prefix, value: name, type: 'header name' }) } else if (!isValidHeaderValue(value)) { throw webidl.errors.invalidArgument({ - prefix: 'Headers.set', + prefix, value, type: 'header value' }) @@ -15216,14 +17299,14 @@ function requireHeaders () { // 6. Otherwise, if this’s guard is "response" and name is a // forbidden response-header name, return. // Note: undici does not implement forbidden header names - if (this[kGuard] === 'immutable') { + if (this.#guard === 'immutable') { throw new TypeError('immutable') - } else if (this[kGuard] === 'request-no-cors') ; + } // 7. Set (name, value) in this’s header list. // 8. If this’s guard is "request-no-cors", then remove // privileged no-CORS request headers from this - this[kHeadersList].set(name, value); + this.#headersList.set(name, value, false); } // https://fetch.spec.whatwg.org/#dom-headers-getsetcookie @@ -15234,7 +17317,7 @@ function requireHeaders () { // 2. Return the values of all headers in this’s header list whose name is // a byte-case-insensitive match for `Set-Cookie`, in order. - const list = this[kHeadersList].cookies; + const list = this.#headersList.cookies; if (list) { return [...list] @@ -15245,8 +17328,8 @@ function requireHeaders () { // https://fetch.spec.whatwg.org/#concept-header-list-sort-and-combine get [kHeadersSortedMap] () { - if (this[kHeadersList][kHeadersSortedMap]) { - return this[kHeadersList][kHeadersSortedMap] + if (this.#headersList[kHeadersSortedMap]) { + return this.#headersList[kHeadersSortedMap] } // 1. Let headers be an empty list of headers with the key being the name @@ -15255,12 +17338,19 @@ function requireHeaders () { // 2. Let names be the result of convert header names to a sorted-lowercase // set with all the names of the headers in list. - const names = [...this[kHeadersList]].sort((a, b) => a[0] < b[0] ? -1 : 1); - const cookies = this[kHeadersList].cookies; + const names = this.#headersList.toSortedArray(); + + const cookies = this.#headersList.cookies; + + // fast-path + if (cookies === null || cookies.length === 1) { + // Note: The non-null assertion of value has already been done by `HeadersList#toSortedArray` + return (this.#headersList[kHeadersSortedMap] = names) + } // 3. For each name of names: for (let i = 0; i < names.length; ++i) { - const [name, value] = names[i]; + const { 0: name, 1: value } = names[i]; // 1. If name is `set-cookie`, then: if (name === 'set-cookie') { // 1. Let values be a list of all values of headers in list whose name @@ -15277,95 +17367,47 @@ function requireHeaders () { // 1. Let value be the result of getting name from list. // 2. Assert: value is non-null. - assert(value !== null); + // Note: This operation was done by `HeadersList#toSortedArray`. // 3. Append (name, value) to headers. headers.push([name, value]); } } - this[kHeadersList][kHeadersSortedMap] = headers; - // 4. Return headers. - return headers + return (this.#headersList[kHeadersSortedMap] = headers) } - keys () { - webidl.brandCheck(this, Headers); + [util.inspect.custom] (depth, options) { + options.depth ??= depth; - if (this[kGuard] === 'immutable') { - const value = this[kHeadersSortedMap]; - return makeIterator(() => value, 'Headers', - 'key') - } - - return makeIterator( - () => [...this[kHeadersSortedMap].values()], - 'Headers', - 'key' - ) + return `Headers ${util.formatWithOptions(options, this.#headersList.entries)}` } - values () { - webidl.brandCheck(this, Headers); - - if (this[kGuard] === 'immutable') { - const value = this[kHeadersSortedMap]; - return makeIterator(() => value, 'Headers', - 'value') - } - - return makeIterator( - () => [...this[kHeadersSortedMap].values()], - 'Headers', - 'value' - ) + static getHeadersGuard (o) { + return o.#guard } - entries () { - webidl.brandCheck(this, Headers); - - if (this[kGuard] === 'immutable') { - const value = this[kHeadersSortedMap]; - return makeIterator(() => value, 'Headers', - 'key+value') - } - - return makeIterator( - () => [...this[kHeadersSortedMap].values()], - 'Headers', - 'key+value' - ) + static setHeadersGuard (o, guard) { + o.#guard = guard; } - /** - * @param {(value: string, key: string, self: Headers) => void} callbackFn - * @param {unknown} thisArg - */ - forEach (callbackFn, thisArg = globalThis) { - webidl.brandCheck(this, Headers); - - webidl.argumentLengthCheck(arguments, 1, { header: 'Headers.forEach' }); - - if (typeof callbackFn !== 'function') { - throw new TypeError( - "Failed to execute 'forEach' on 'Headers': parameter 1 is not of type 'Function'." - ) - } - - for (const [key, value] of this) { - callbackFn.apply(thisArg, [value, key, this]); - } + static getHeadersList (o) { + return o.#headersList } - [Symbol.for('nodejs.util.inspect.custom')] () { - webidl.brandCheck(this, Headers); - - return this[kHeadersList] + static setHeadersList (o, list) { + o.#headersList = list; } } - Headers.prototype[Symbol.iterator] = Headers.prototype.entries; + const { getHeadersGuard, setHeadersGuard, getHeadersList, setHeadersList } = Headers; + Reflect.deleteProperty(Headers, 'getHeadersGuard'); + Reflect.deleteProperty(Headers, 'setHeadersGuard'); + Reflect.deleteProperty(Headers, 'getHeadersList'); + Reflect.deleteProperty(Headers, 'setHeadersList'); + + iteratorMixin('Headers', Headers, kHeadersSortedMap, 0, 1); Object.defineProperties(Headers.prototype, { append: kEnumerableProperty, @@ -15374,11 +17416,6 @@ function requireHeaders () { has: kEnumerableProperty, set: kEnumerableProperty, getSetCookie: kEnumerableProperty, - keys: kEnumerableProperty, - values: kEnumerableProperty, - entries: kEnumerableProperty, - forEach: kEnumerableProperty, - [Symbol.iterator]: { enumerable: false }, [Symbol.toStringTag]: { value: 'Headers', configurable: true @@ -15388,13 +17425,25 @@ function requireHeaders () { } }); - webidl.converters.HeadersInit = function (V) { + webidl.converters.HeadersInit = function (V, prefix, argument) { if (webidl.util.Type(V) === 'Object') { - if (V[Symbol.iterator]) { - return webidl.converters['sequence>'](V) + const iterator = Reflect.get(V, Symbol.iterator); + + // A work-around to ensure we send the properly-cased Headers when V is a Headers object. + // Read https://github.com/nodejs/undici/pull/3159#issuecomment-2075537226 before touching, please. + if (!util.types.isProxy(V) && iterator === Headers.prototype.entries) { // Headers object + try { + return getHeadersList(V).entriesList + } catch { + // fall-through + } + } + + if (typeof iterator === 'function') { + return webidl.converters['sequence>'](V, prefix, argument, iterator.bind(V)) } - return webidl.converters['record'](V) + return webidl.converters['record'](V, prefix, argument) } throw webidl.errors.conversionFailed({ @@ -15406,8 +17455,14 @@ function requireHeaders () { headers = { fill, + // for test. + compareHeaderName, Headers, - HeadersList + HeadersList, + getHeadersGuard, + setHeadersGuard, + setHeadersList, + getHeadersList }; return headers; } @@ -15419,9 +17474,10 @@ function requireResponse () { if (hasRequiredResponse) return response; hasRequiredResponse = 1; - const { Headers, HeadersList, fill } = requireHeaders(); - const { extractBody, cloneBody, mixinBody } = requireBody(); - const util = requireUtil$7(); + const { Headers, HeadersList, fill, getHeadersGuard, setHeadersGuard, setHeadersList } = requireHeaders(); + const { extractBody, cloneBody, mixinBody, hasFinalizationRegistry, streamRegistry, bodyUnusable } = requireBody(); + const util = requireUtil$8(); + const nodeUtil = require$$0$6; const { kEnumerableProperty } = util; const { isValidReasonPhrase, @@ -15430,47 +17486,38 @@ function requireResponse () { isBlobLike, serializeJavascriptValueToJSONString, isErrorLike, - isomorphicEncode - } = requireUtil$6(); + isomorphicEncode, + environmentSettingsObject: relevantRealm + } = requireUtil$7(); const { redirectStatusSet, - nullBodyStatus, - DOMException - } = requireConstants$3(); - const { kState, kHeaders, kGuard, kRealm } = requireSymbols$3(); + nullBodyStatus + } = requireConstants$2(); + const { kState, kHeaders } = requireSymbols$3(); const { webidl } = requireWebidl(); const { FormData } = requireFormdata(); - const { getGlobalOrigin } = requireGlobal$1(); - const { URLSerializer } = requireDataURL(); - const { kHeadersList, kConstruct } = requireSymbols$4(); + const { URLSerializer } = requireDataUrl(); + const { kConstruct } = requireSymbols$4(); const assert = require$$0$3; - const { types } = require$$0$2; + const { types } = require$$0$6; - const ReadableStream = globalThis.ReadableStream || require$$14.ReadableStream; const textEncoder = new TextEncoder('utf-8'); // https://fetch.spec.whatwg.org/#response-class class Response { // Creates network error Response. static error () { - // TODO - const relevantRealm = { settingsObject: {} }; - // The static error() method steps are to return the result of creating a // Response object, given a new network error, "immutable", and this’s // relevant Realm. - const responseObject = new Response(); - responseObject[kState] = makeNetworkError(); - responseObject[kRealm] = relevantRealm; - responseObject[kHeaders][kHeadersList] = responseObject[kState].headersList; - responseObject[kHeaders][kGuard] = 'immutable'; - responseObject[kHeaders][kRealm] = relevantRealm; + const responseObject = fromInnerResponse(makeNetworkError(), 'immutable'); + return responseObject } // https://fetch.spec.whatwg.org/#dom-response-json static json (data, init = {}) { - webidl.argumentLengthCheck(arguments, 1, { header: 'Response.json' }); + webidl.argumentLengthCheck(arguments, 1, 'Response.json'); if (init !== null) { init = webidl.converters.ResponseInit(init); @@ -15486,11 +17533,7 @@ function requireResponse () { // 3. Let responseObject be the result of creating a Response object, given a new response, // "response", and this’s relevant Realm. - const relevantRealm = { settingsObject: {} }; - const responseObject = new Response(); - responseObject[kRealm] = relevantRealm; - responseObject[kHeaders][kGuard] = 'response'; - responseObject[kHeaders][kRealm] = relevantRealm; + const responseObject = fromInnerResponse(makeResponse({}), 'response'); // 4. Perform initialize a response given responseObject, init, and (body, "application/json"). initializeResponse(responseObject, init, { body: body[0], type: 'application/json' }); @@ -15501,9 +17544,7 @@ function requireResponse () { // Creates a redirect Response that redirects to url with status status. static redirect (url, status = 302) { - const relevantRealm = { settingsObject: {} }; - - webidl.argumentLengthCheck(arguments, 1, { header: 'Response.redirect' }); + webidl.argumentLengthCheck(arguments, 1, 'Response.redirect'); url = webidl.converters.USVString(url); status = webidl.converters['unsigned short'](status); @@ -15514,24 +17555,19 @@ function requireResponse () { // TODO: base-URL? let parsedURL; try { - parsedURL = new URL(url, getGlobalOrigin()); + parsedURL = new URL(url, relevantRealm.settingsObject.baseUrl); } catch (err) { - throw Object.assign(new TypeError('Failed to parse URL from ' + url), { - cause: err - }) + throw new TypeError(`Failed to parse URL from ${url}`, { cause: err }) } // 3. If status is not a redirect status, then throw a RangeError. if (!redirectStatusSet.has(status)) { - throw new RangeError('Invalid status code ' + status) + throw new RangeError(`Invalid status code ${status}`) } // 4. Let responseObject be the result of creating a Response object, // given a new response, "immutable", and this’s relevant Realm. - const responseObject = new Response(); - responseObject[kRealm] = relevantRealm; - responseObject[kHeaders][kGuard] = 'immutable'; - responseObject[kHeaders][kRealm] = relevantRealm; + const responseObject = fromInnerResponse(makeResponse({}), 'immutable'); // 5. Set responseObject’s response’s status to status. responseObject[kState].status = status; @@ -15540,7 +17576,7 @@ function requireResponse () { const value = isomorphicEncode(URLSerializer(parsedURL)); // 7. Append `Location`/value to responseObject’s response’s header list. - responseObject[kState].headersList.append('location', value); + responseObject[kState].headersList.append('location', value, true); // 8. Return responseObject. return responseObject @@ -15548,15 +17584,17 @@ function requireResponse () { // 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); - // TODO - this[kRealm] = { settingsObject: {} }; - // 1. Set this’s response to a new response. this[kState] = makeResponse({}); @@ -15564,9 +17602,8 @@ function requireResponse () { // Realm, whose header list is this’s response’s header list and guard // is "response". this[kHeaders] = new Headers(kConstruct); - this[kHeaders][kGuard] = 'response'; - this[kHeaders][kHeadersList] = this[kState].headersList; - this[kHeaders][kRealm] = this[kRealm]; + setHeadersGuard(this[kHeaders], 'response'); + setHeadersList(this[kHeaders], this[kState].headersList); // 3. Let bodyWithType be null. let bodyWithType = null; @@ -15667,7 +17704,7 @@ function requireResponse () { webidl.brandCheck(this, Response); // 1. If this is unusable, then throw a TypeError. - if (this.bodyUsed || (this.body && this.body.locked)) { + if (bodyUnusable(this)) { throw webidl.errors.exception({ header: 'Response.clone', message: 'Body has already been consumed.' @@ -15677,16 +17714,36 @@ function requireResponse () { // 2. Let clonedResponse be the result of cloning this’s response. const clonedResponse = cloneResponse(this[kState]); + // Note: To re-register because of a new stream. + if (hasFinalizationRegistry && this[kState].body?.stream) { + streamRegistry.register(this, new WeakRef(this[kState].body.stream)); + } + // 3. Return the result of creating a Response object, given // clonedResponse, this’s headers’s guard, and this’s relevant Realm. - const clonedResponseObject = new Response(); - clonedResponseObject[kState] = clonedResponse; - clonedResponseObject[kRealm] = this[kRealm]; - clonedResponseObject[kHeaders][kHeadersList] = clonedResponse.headersList; - clonedResponseObject[kHeaders][kGuard] = this[kHeaders][kGuard]; - clonedResponseObject[kHeaders][kRealm] = this[kHeaders][kRealm]; + return fromInnerResponse(clonedResponse, getHeadersGuard(this[kHeaders])) + } + + [nodeUtil.inspect.custom] (depth, options) { + if (options.depth === null) { + options.depth = 2; + } + + options.colors ??= true; - return clonedResponseObject + 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)}` } } @@ -15735,7 +17792,7 @@ function requireResponse () { // 3. If response’s body is non-null, then set newResponse’s body to the // result of cloning response’s body. if (response.body != null) { - newResponse.body = cloneBody(response.body); + newResponse.body = cloneBody(newResponse, response.body); } // 4. Return newResponse. @@ -15754,10 +17811,10 @@ function requireResponse () { cacheState: '', statusText: '', ...init, - headersList: init.headersList - ? new HeadersList(init.headersList) + headersList: init?.headersList + ? new HeadersList(init?.headersList) : new HeadersList(), - urlList: init.urlList ? [...init.urlList] : [] + urlList: init?.urlList ? [...init.urlList] : [] } } @@ -15773,6 +17830,16 @@ function requireResponse () { }) } + // @see https://fetch.spec.whatwg.org/#concept-network-error + function isNetworkError (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, @@ -15896,7 +17963,7 @@ function requireResponse () { if (nullBodyStatus.includes(response.status)) { throw webidl.errors.exception({ header: 'Response constructor', - message: 'Invalid response status code ' + response.status + message: `Invalid response status code ${response.status}` }) } @@ -15905,12 +17972,37 @@ function requireResponse () { // 3. If body's type is non-null and response's header list does not contain // `Content-Type`, then append (`Content-Type`, body's type) to response's header list. - if (body.type != null && !response[kState].headersList.contains('Content-Type')) { - response[kState].headersList.append('content-type', body.type); + if (body.type != null && !response[kState].headersList.contains('content-type', true)) { + response[kState].headersList.append('content-type', body.type, true); } } } + /** + * @see https://fetch.spec.whatwg.org/#response-create + * @param {any} innerResponse + * @param {'request' | 'immutable' | 'request-no-cors' | 'response' | 'none'} guard + * @returns {Response} + */ + function fromInnerResponse (innerResponse, guard) { + const response = new Response(kConstruct); + response[kState] = innerResponse; + response[kHeaders] = new Headers(kConstruct); + setHeadersList(response[kHeaders], innerResponse.headersList); + setHeadersGuard(response[kHeaders], guard); + + if (hasFinalizationRegistry && innerResponse.body?.stream) { + // If the target (response) is reclaimed, the cleanup callback may be called at some point with + // the held value provided for it (innerResponse.body.stream). The held value can be any value: + // a primitive or an object, even undefined. If the held value is an object, the registry keeps + // a strong reference to it (so it can pass it to the cleanup callback later). Reworded from + // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/FinalizationRegistry + streamRegistry.register(response, new WeakRef(innerResponse.body.stream)); + } + + return response + } + webidl.converters.ReadableStream = webidl.interfaceConverter( ReadableStream ); @@ -15924,34 +18016,34 @@ function requireResponse () { ); // https://fetch.spec.whatwg.org/#typedefdef-xmlhttprequestbodyinit - webidl.converters.XMLHttpRequestBodyInit = function (V) { + webidl.converters.XMLHttpRequestBodyInit = function (V, prefix, name) { if (typeof V === 'string') { - return webidl.converters.USVString(V) + return webidl.converters.USVString(V, prefix, name) } if (isBlobLike(V)) { - return webidl.converters.Blob(V, { strict: false }) + return webidl.converters.Blob(V, prefix, name, { strict: false }) } - if (types.isArrayBuffer(V) || types.isTypedArray(V) || types.isDataView(V)) { - return webidl.converters.BufferSource(V) + if (ArrayBuffer.isView(V) || types.isArrayBuffer(V)) { + return webidl.converters.BufferSource(V, prefix, name) } if (util.isFormDataLike(V)) { - return webidl.converters.FormData(V, { strict: false }) + return webidl.converters.FormData(V, prefix, name, { strict: false }) } if (V instanceof URLSearchParams) { - return webidl.converters.URLSearchParams(V) + return webidl.converters.URLSearchParams(V, prefix, name) } - return webidl.converters.DOMString(V) + return webidl.converters.DOMString(V, prefix, name) }; // https://fetch.spec.whatwg.org/#bodyinit - webidl.converters.BodyInit = function (V) { + webidl.converters.BodyInit = function (V, prefix, argument) { if (V instanceof ReadableStream) { - return webidl.converters.ReadableStream(V) + return webidl.converters.ReadableStream(V, prefix, argument) } // Note: the spec doesn't include async iterables, @@ -15960,19 +18052,19 @@ function requireResponse () { return V } - return webidl.converters.XMLHttpRequestBodyInit(V) + return webidl.converters.XMLHttpRequestBodyInit(V, prefix, argument) }; webidl.converters.ResponseInit = webidl.dictionaryConverter([ { key: 'status', converter: webidl.converters['unsigned short'], - defaultValue: 200 + defaultValue: () => 200 }, { key: 'statusText', converter: webidl.converters.ByteString, - defaultValue: '' + defaultValue: () => '' }, { key: 'headers', @@ -15981,36 +18073,91 @@ function requireResponse () { ]); response = { + isNetworkError, makeNetworkError, makeResponse, makeAppropriateNetworkError, filterResponse, Response, - cloneResponse + cloneResponse, + fromInnerResponse }; return response; } +var dispatcherWeakref; +var hasRequiredDispatcherWeakref; + +function requireDispatcherWeakref () { + if (hasRequiredDispatcherWeakref) return dispatcherWeakref; + hasRequiredDispatcherWeakref = 1; + + const { kConnected, kSize } = requireSymbols$4(); + + class CompatWeakRef { + constructor (value) { + this.value = value; + } + + deref () { + return this.value[kConnected] === 0 && this.value[kSize] === 0 + ? undefined + : this.value + } + } + + class CompatFinalizer { + 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) {} + } + + dispatcherWeakref = function () { + // FIXME: remove workaround when the Node bug is backported to v18 + // https://github.com/nodejs/node/issues/49344#issuecomment-1741776308 + 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 } + }; + return dispatcherWeakref; +} + /* globals AbortController */ -var request$2; +var request$1; var hasRequiredRequest; function requireRequest () { - if (hasRequiredRequest) return request$2; + if (hasRequiredRequest) return request$1; hasRequiredRequest = 1; - const { extractBody, mixinBody, cloneBody } = requireBody(); - const { Headers, fill: fillHeaders, HeadersList } = requireHeaders(); + const { extractBody, mixinBody, cloneBody, bodyUnusable } = requireBody(); + const { Headers, fill: fillHeaders, HeadersList, setHeadersGuard, getHeadersGuard, setHeadersList, getHeadersList } = requireHeaders(); const { FinalizationRegistry } = requireDispatcherWeakref()(); - const util = requireUtil$7(); + const util = requireUtil$8(); + const nodeUtil = require$$0$6; const { isValidHTTPToken, sameOrigin, - normalizeMethod, - makePolicyContainer, - normalizeMethodRecord - } = requireUtil$6(); + environmentSettingsObject + } = requireUtil$7(); const { forbiddenMethodsSet, corsSafeListedMethodsSet, @@ -16020,17 +18167,14 @@ function requireRequest () { requestCredentials, requestCache, requestDuplex - } = requireConstants$3(); - const { kEnumerableProperty } = util; - const { kHeaders, kSignal, kState, kGuard, kRealm } = requireSymbols$3(); + } = requireConstants$2(); + const { kEnumerableProperty, normalizedMethodRecordsBase, normalizedMethodRecords } = util; + const { kHeaders, kSignal, kState, kDispatcher } = requireSymbols$3(); const { webidl } = requireWebidl(); - const { getGlobalOrigin } = requireGlobal$1(); - const { URLSerializer } = requireDataURL(); - const { kHeadersList, kConstruct } = requireSymbols$4(); + const { URLSerializer } = requireDataUrl(); + const { kConstruct } = requireSymbols$4(); const assert = require$$0$3; - const { getMaxListeners, setMaxListeners, getEventListeners, defaultMaxListeners } = require$$4$1; - - let TransformStream = globalThis.TransformStream; + const { getMaxListeners, setMaxListeners, getEventListeners, defaultMaxListeners } = require$$8; const kAbortController = Symbol('abortController'); @@ -16038,29 +18182,62 @@ function requireRequest () { signal.removeEventListener('abort', abort); }); + const dependentControllerMap = new WeakMap(); + + function buildAbort (acRef) { + return abort + + function abort () { + const ac = acRef.deref(); + if (ac !== undefined) { + // Currently, there is a problem with FinalizationRegistry. + // https://github.com/nodejs/node/issues/49344 + // https://github.com/nodejs/node/issues/47748 + // In the case of abort, the first step is to unregister from it. + // If the controller can refer to it, it is still registered. + // It will be removed in the future. + requestFinalizer.unregister(abort); + + // Unsubscribe a listener. + // FinalizationRegistry will no longer be called, so this must be done. + this.removeEventListener('abort', abort); + + ac.abort(this.reason); + + const controllerList = dependentControllerMap.get(ac.signal); + + if (controllerList !== undefined) { + if (controllerList.size !== 0) { + for (const ref of controllerList) { + const ctrl = ref.deref(); + if (ctrl !== undefined) { + ctrl.abort(this.reason); + } + } + controllerList.clear(); + } + dependentControllerMap.delete(ac.signal); + } + } + } + } + + let patchMethodWarning = false; + // https://fetch.spec.whatwg.org/#request-class class Request { // https://fetch.spec.whatwg.org/#dom-request constructor (input, init = {}) { + webidl.util.markAsUncloneable(this); if (input === kConstruct) { return } - webidl.argumentLengthCheck(arguments, 1, { header: 'Request constructor' }); - - input = webidl.converters.RequestInfo(input); - init = webidl.converters.RequestInit(init); + const prefix = 'Request constructor'; + webidl.argumentLengthCheck(arguments, 1, prefix); - // https://html.spec.whatwg.org/multipage/webappapis.html#environment-settings-object - this[kRealm] = { - settingsObject: { - baseUrl: getGlobalOrigin(), - get origin () { - return this.baseUrl?.origin - }, - policyContainer: makePolicyContainer() - } - }; + input = webidl.converters.RequestInfo(input, prefix, 'input'); + init = webidl.converters.RequestInit(init, prefix, 'init'); // 1. Let request be null. let request = null; @@ -16069,13 +18246,15 @@ function requireRequest () { let fallbackMode = null; // 3. Let baseURL be this’s relevant settings object’s API base URL. - const baseUrl = this[kRealm].settingsObject.baseUrl; + const baseUrl = environmentSettingsObject.settingsObject.baseUrl; // 4. Let signal be null. let signal = null; // 5. If input is a string, then: if (typeof input === 'string') { + this[kDispatcher] = init.dispatcher; + // 1. Let parsedURL be the result of parsing input with baseURL. // 2. If parsedURL is failure, then throw a TypeError. let parsedURL; @@ -16099,6 +18278,8 @@ function requireRequest () { // 5. Set fallbackMode to "cors". fallbackMode = 'cors'; } else { + this[kDispatcher] = init.dispatcher || input[kDispatcher]; + // 6. Otherwise: // 7. Assert: input is a Request object. @@ -16112,7 +18293,7 @@ function requireRequest () { } // 7. Let origin be this’s relevant settings object’s origin. - const origin = this[kRealm].settingsObject.origin; + const origin = environmentSettingsObject.settingsObject.origin; // 8. Let window be "client". let window = 'client'; @@ -16148,7 +18329,7 @@ function requireRequest () { // unsafe-request flag Set. unsafeRequest: request.unsafeRequest, // client This’s relevant settings object. - client: this[kRealm].settingsObject, + client: environmentSettingsObject.settingsObject, // window window. window, // priority request’s priority. @@ -16237,7 +18418,7 @@ function requireRequest () { // then set request’s referrer to "client". if ( (parsedReferrer.protocol === 'about:' && parsedReferrer.hostname === 'client') || - (origin && !sameOrigin(parsedReferrer, this[kRealm].settingsObject.baseUrl)) + (origin && !sameOrigin(parsedReferrer, environmentSettingsObject.settingsObject.baseUrl)) ) { request.referrer = 'client'; } else { @@ -16313,21 +18494,40 @@ function requireRequest () { // 1. Let method be init["method"]. let method = init.method; - // 2. If method is not a method or method is a forbidden method, then - // throw a TypeError. - if (!isValidHTTPToken(method)) { - throw new TypeError(`'${method}' is not a valid HTTP method.`) - } + const mayBeNormalized = normalizedMethodRecords[method]; + + if (mayBeNormalized !== undefined) { + // Note: Bypass validation DELETE, GET, HEAD, OPTIONS, POST, PUT, PATCH and these lowercase ones + request.method = mayBeNormalized; + } else { + // 2. If method is not a method or method is a forbidden method, then + // throw a TypeError. + 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.`) + } + + // 3. Normalize method. + // https://fetch.spec.whatwg.org/#concept-method-normalize + // Note: must be in uppercase + method = normalizedMethodRecordsBase[upperCase] ?? method; - if (forbiddenMethodsSet.has(method.toUpperCase())) { - throw new TypeError(`'${method}' HTTP method is unsupported.`) + // 4. Set request’s method to method. + request.method = method; } - // 3. Normalize method. - method = normalizeMethodRecord[method] ?? normalizeMethod(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' + }); - // 4. Set request’s method to method. - request.method = method; + patchMethodWarning = true; + } } // 26. If init["signal"] exists, then set signal to it. @@ -16344,7 +18544,6 @@ function requireRequest () { // (https://dom.spec.whatwg.org/#dom-abortsignal-any) const ac = new AbortController(); this[kSignal] = ac.signal; - this[kSignal][kRealm] = this[kRealm]; // 29. If signal is not null, then make this’s signal follow signal. if (signal != null) { @@ -16368,12 +18567,7 @@ function requireRequest () { this[kAbortController] = ac; const acRef = new WeakRef(ac); - const abort = function () { - const ac = acRef.deref(); - if (ac !== undefined) { - ac.abort(this.reason); - } - }; + const abort = buildAbort(acRef); // Third-party AbortControllers may not work with these. // See, https://github.com/nodejs/undici/pull/1910#issuecomment-1464495619. @@ -16381,14 +18575,18 @@ function requireRequest () { // If the max amount of listeners is equal to the default, increase it // This is only available in node >= v19.9.0 if (typeof getMaxListeners === 'function' && getMaxListeners(signal) === defaultMaxListeners) { - setMaxListeners(100, signal); + setMaxListeners(1500, signal); } else if (getEventListeners(signal, 'abort').length >= defaultMaxListeners) { - setMaxListeners(100, signal); + setMaxListeners(1500, signal); } } catch {} util.addAbortListener(signal, abort); - requestFinalizer.register(ac, { signal, abort }); + // The third argument must be a registry key to be unregistered. + // Without it, you cannot unregister. + // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/FinalizationRegistry + // abort is used as the unregister key. (because it is unique) + requestFinalizer.register(ac, { signal, abort }, abort); } } @@ -16396,9 +18594,8 @@ function requireRequest () { // Realm, whose header list is request’s header list and guard is // "request". this[kHeaders] = new Headers(kConstruct); - this[kHeaders][kHeadersList] = request.headersList; - this[kHeaders][kGuard] = 'request'; - this[kHeaders][kRealm] = this[kRealm]; + setHeadersList(this[kHeaders], request.headersList); + setHeadersGuard(this[kHeaders], 'request'); // 31. If this’s request’s mode is "no-cors", then: if (mode === 'no-cors') { @@ -16411,13 +18608,13 @@ function requireRequest () { } // 2. Set this’s headers’s guard to "request-no-cors". - this[kHeaders][kGuard] = 'request-no-cors'; + setHeadersGuard(this[kHeaders], 'request-no-cors'); } // 32. If init is not empty, then: if (initHasKey) { /** @type {HeadersList} */ - const headersList = this[kHeaders][kHeadersList]; + const headersList = getHeadersList(this[kHeaders]); // 1. Let headers be a copy of this’s headers and its associated header // list. // 2. If init["headers"] exists, then set headers to init["headers"]. @@ -16429,8 +18626,8 @@ function requireRequest () { // 4. If headers is a Headers object, then for each header in its header // list, append header’s name/header’s value to this’s headers. if (headers instanceof HeadersList) { - for (const [key, val] of headers) { - headersList.append(key, val); + for (const { name, value } of headers.rawValues()) { + headersList.append(name, value, false); } // Note: Copy the `set-cookie` meta-data. headersList.cookies = headers.cookies; @@ -16471,7 +18668,7 @@ function requireRequest () { // 3, If Content-Type is non-null and this’s headers’s header list does // not contain `Content-Type`, then append `Content-Type`/Content-Type to // this’s headers. - if (contentType && !this[kHeaders][kHeadersList].contains('content-type')) { + if (contentType && !getHeadersList(this[kHeaders]).contains('content-type', true)) { this[kHeaders].append('content-type', contentType); } } @@ -16507,17 +18704,13 @@ function requireRequest () { // 40. If initBody is null and inputBody is non-null, then: if (initBody == null && inputBody != null) { // 1. If input is unusable, then throw a TypeError. - if (util.isDisturbed(inputBody.stream) || inputBody.stream.locked) { + if (bodyUnusable(input)) { throw new TypeError( 'Cannot construct a Request with a Request object that has already been used.' ) } // 2. Set finalBody to the result of creating a proxy for inputBody. - if (!TransformStream) { - TransformStream = require$$14.TransformStream; - } - // https://streams.spec.whatwg.org/#readablestream-create-a-proxy const identityTransform = new TransformStream(); inputBody.stream.pipeThrough(identityTransform); @@ -16671,7 +18864,7 @@ function requireRequest () { } // Returns a boolean indicating whether or not request is for a history - // navigation (a.k.a. back-foward navigation). + // navigation (a.k.a. back-forward navigation). get isHistoryNavigation () { webidl.brandCheck(this, Request); @@ -16713,7 +18906,7 @@ function requireRequest () { webidl.brandCheck(this, Request); // 1. If this is unusable, then throw a TypeError. - if (this.bodyUsed || this.body?.locked) { + if (bodyUnusable(this)) { throw new TypeError('unusable') } @@ -16722,80 +18915,103 @@ function requireRequest () { // 3. Let clonedRequestObject be the result of creating a Request object, // given clonedRequest, this’s headers’s guard, and this’s relevant Realm. - const clonedRequestObject = new Request(kConstruct); - clonedRequestObject[kState] = clonedRequest; - clonedRequestObject[kRealm] = this[kRealm]; - clonedRequestObject[kHeaders] = new Headers(kConstruct); - clonedRequestObject[kHeaders][kHeadersList] = clonedRequest.headersList; - clonedRequestObject[kHeaders][kGuard] = this[kHeaders][kGuard]; - clonedRequestObject[kHeaders][kRealm] = this[kHeaders][kRealm]; - // 4. Make clonedRequestObject’s signal follow this’s signal. const ac = new AbortController(); if (this.signal.aborted) { ac.abort(this.signal.reason); } else { + let list = dependentControllerMap.get(this.signal); + if (list === undefined) { + list = new Set(); + dependentControllerMap.set(this.signal, list); + } + const acRef = new WeakRef(ac); + list.add(acRef); util.addAbortListener( - this.signal, - () => { - ac.abort(this.signal.reason); - } + ac.signal, + buildAbort(acRef) ); } - clonedRequestObject[kSignal] = ac.signal; // 4. Return clonedRequestObject. - return clonedRequestObject + 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(Request); + // https://fetch.spec.whatwg.org/#requests function makeRequest (init) { - // https://fetch.spec.whatwg.org/#requests - const request = { - method: 'GET', - localURLsOnly: false, - unsafeRequest: false, - body: null, - client: null, - reservedClient: null, - replacesClientId: '', - window: 'client', - keepalive: false, - serviceWorkers: 'all', - initiator: '', - destination: '', - priority: null, - origin: 'client', - policyContainer: 'client', - referrer: 'client', - referrerPolicy: '', - mode: 'no-cors', - useCORSPreflightFlag: false, - credentials: 'same-origin', - useCredentials: false, - cache: 'default', - redirect: 'follow', - integrity: '', - cryptoGraphicsNonceMetadata: '', - parserMetadata: '', - reloadNavigation: false, - historyNavigation: false, - userActivation: false, - taintedOrigin: false, - redirectCount: 0, - responseTainting: 'basic', - preventNoCacheCacheControlHeaderModification: false, - done: false, - timingAllowFailed: false, - ...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() - }; - request.url = request.urlList[0]; - return request + } } // https://fetch.spec.whatwg.org/#concept-request-clone @@ -16808,13 +19024,30 @@ function requireRequest () { // 2. If request’s body is non-null, set newRequest’s body to the // result of cloning request’s body. if (request.body != null) { - newRequest.body = cloneBody(request.body); + newRequest.body = cloneBody(newRequest, request.body); } // 3. Return newRequest. return newRequest } + /** + * @see https://fetch.spec.whatwg.org/#request-create + * @param {any} innerRequest + * @param {AbortSignal} signal + * @param {'request' | 'immutable' | 'request-no-cors' | 'response' | 'none'} guard + * @returns {Request} + */ + function fromInnerRequest (innerRequest, signal, guard) { + const request = new Request(kConstruct); + request[kState] = innerRequest; + request[kSignal] = signal; + request[kHeaders] = new Headers(kConstruct); + setHeadersList(request[kHeaders], innerRequest.headersList); + setHeadersGuard(request[kHeaders], guard); + return request + } + Object.defineProperties(Request.prototype, { method: kEnumerableProperty, url: kEnumerableProperty, @@ -16847,16 +19080,16 @@ function requireRequest () { ); // https://fetch.spec.whatwg.org/#requestinfo - webidl.converters.RequestInfo = function (V) { + webidl.converters.RequestInfo = function (V, prefix, argument) { if (typeof V === 'string') { - return webidl.converters.USVString(V) + return webidl.converters.USVString(V, prefix, argument) } if (V instanceof Request) { - return webidl.converters.Request(V) + return webidl.converters.Request(V, prefix, argument) } - return webidl.converters.USVString(V) + return webidl.converters.USVString(V, prefix, argument) }; webidl.converters.AbortSignal = webidl.interfaceConverter( @@ -16926,6 +19159,8 @@ function requireRequest () { converter: webidl.nullableConverter( (signal) => webidl.converters.AbortSignal( signal, + 'RequestInit', + 'signal', { strict: false } ) ) @@ -16938,11 +19173,15 @@ function requireRequest () { key: 'duplex', converter: webidl.converters.DOMString, allowedValues: requestDuplex + }, + { + key: 'dispatcher', // undici specific option + converter: webidl.converters.any } ]); - request$2 = { Request, makeRequest }; - return request$2; + request$1 = { Request, makeRequest, fromInnerRequest, cloneRequest }; + return request$1; } var fetch_1; @@ -16953,15 +19192,15 @@ function requireFetch () { hasRequiredFetch = 1; const { - Response, makeNetworkError, makeAppropriateNetworkError, filterResponse, - makeResponse + makeResponse, + fromInnerResponse } = requireResponse(); - const { Headers } = requireHeaders(); - const { Request, makeRequest } = requireRequest(); - const zlib = require$$3$1; + const { HeadersList } = requireHeaders(); + const { Request, cloneRequest } = requireRequest(); + const zlib = require$$1$2; const { bytesMatch, makePolicyContainer, @@ -16990,33 +19229,38 @@ function requireFetch () { isomorphicEncode, urlIsLocal, urlIsHttpHttpsScheme, - urlHasHttpsScheme - } = requireUtil$6(); - const { kState, kHeaders, kGuard, kRealm } = requireSymbols$3(); + urlHasHttpsScheme, + clampAndCoarsenConnectionTimingInfo, + simpleRangeHeaderValue, + buildContentRange, + createInflate, + extractMimeType + } = requireUtil$7(); + const { kState, kDispatcher } = requireSymbols$3(); const assert = require$$0$3; - const { safelyExtractBody } = requireBody(); + const { safelyExtractBody, extractBody } = requireBody(); const { redirectStatusSet, nullBodyStatus, safeMethodsSet, requestBodyHeader, - subresourceSet, - DOMException - } = requireConstants$3(); - const { kHeadersList } = requireSymbols$4(); - const EE = require$$4$1; - const { Readable, pipeline } = require$$0$5; - const { addAbortListener, isErrored, isReadable, nodeMajor, nodeMinor } = requireUtil$7(); - const { dataURLProcessor, serializeAMimeType } = requireDataURL(); - const { TransformStream } = require$$14; + subresourceSet + } = requireConstants$2(); + const EE = require$$8; + const { Readable, pipeline, finished } = require$$0$4; + const { addAbortListener, isErrored, isReadable, bufferToLowerCasedHeaderName } = requireUtil$8(); + const { dataURLProcessor, serializeAMimeType, minimizeSupportedMimeType } = requireDataUrl(); const { getGlobalDispatcher } = requireGlobal(); const { webidl } = requireWebidl(); const { STATUS_CODES } = require$$2$1; const GET_OR_HEAD = ['GET', 'HEAD']; + const defaultUserAgent = typeof __UNDICI_IS_NODE__ !== 'undefined' || typeof esbuildDetection !== 'undefined' + ? 'node' + : 'undici'; + /** @type {import('buffer').resolveObjectURL} */ let resolveObjectURL; - let ReadableStream = globalThis.ReadableStream; class Fetch extends EE { constructor (dispatcher) { @@ -17026,12 +19270,6 @@ function requireFetch () { this.connection = null; this.dump = false; this.state = 'ongoing'; - // 2 terminated listeners get added per request, - // but only 1 gets removed. If there are 20 redirects, - // 21 listeners will be added. - // See https://github.com/nodejs/undici/issues/1711 - // TODO (fix): Find and fix root cause for leaked listener. - this.setMaxListeners(21); } terminate (reason) { @@ -17071,12 +19309,16 @@ function requireFetch () { } } + function handleFetchDone (response) { + finalizeAndReportTiming(response, 'fetch'); + } + // https://fetch.spec.whatwg.org/#fetch-method - function fetch (input, init = {}) { - webidl.argumentLengthCheck(arguments, 1, { header: 'globalThis.fetch' }); + function fetch (input, init = undefined) { + webidl.argumentLengthCheck(arguments, 1, 'globalThis.fetch'); // 1. Let p be a new promise. - const p = createDeferredPromise(); + let p = createDeferredPromise(); // 2. Let requestObject be the result of invoking the initial value of // Request as constructor with input and init as arguments. If this throws @@ -17116,7 +19358,6 @@ function requireFetch () { let responseObject = null; // 8. Let relevantRealm be this’s relevant Realm. - const relevantRealm = null; // 9. Let locallyAborted be false. let locallyAborted = false; @@ -17137,16 +19378,17 @@ function requireFetch () { // 3. Abort controller with requestObject’s signal’s abort reason. controller.abort(requestObject.signal.reason); + const realResponse = responseObject?.deref(); + // 4. Abort the fetch() call with p, request, responseObject, // and requestObject’s signal’s abort reason. - abortFetch(p, request, responseObject, requestObject.signal.reason); + abortFetch(p, request, realResponse, requestObject.signal.reason); } ); // 12. Let handleFetchDone given response response be to finalize and // report timing with response, globalObject, and "fetch". - const handleFetchDone = (response) => - finalizeAndReportTiming(response, 'fetch'); + // see function handleFetchDone // 13. Set controller to the result of calling fetch given request, // with processResponseEndOfBody set to handleFetchDone, and processResponse @@ -17155,7 +19397,7 @@ function requireFetch () { const processResponse = (response) => { // 1. If locallyAborted is true, terminate these substeps. if (locallyAborted) { - return Promise.resolve() + return } // 2. If response’s aborted flag is set, then: @@ -17168,36 +19410,30 @@ function requireFetch () { // deserializedError. abortFetch(p, request, responseObject, controller.serializedAbortReason); - return Promise.resolve() + return } // 3. If response is a network error, then reject p with a TypeError // and terminate these substeps. if (response.type === 'error') { - p.reject( - Object.assign(new TypeError('fetch failed'), { cause: response.error }) - ); - return Promise.resolve() + p.reject(new TypeError('fetch failed', { cause: response.error })); + return } // 4. Set responseObject to the result of creating a Response object, // given response, "immutable", and relevantRealm. - responseObject = new Response(); - responseObject[kState] = response; - responseObject[kRealm] = relevantRealm; - responseObject[kHeaders][kHeadersList] = response.headersList; - responseObject[kHeaders][kGuard] = 'immutable'; - responseObject[kHeaders][kRealm] = relevantRealm; + responseObject = new WeakRef(fromInnerResponse(response, 'immutable')); // 5. Resolve p with responseObject. - p.resolve(responseObject); + p.resolve(responseObject.deref()); + p = null; }; controller = fetching({ request, processResponseEndOfBody: handleFetchDone, processResponse, - dispatcher: init.dispatcher ?? getGlobalDispatcher() // undici + dispatcher: requestObject[kDispatcher] // undici }); // 14. Return p. @@ -17260,7 +19496,7 @@ function requireFetch () { // global, and cacheState. markResourceTiming( timingInfo, - originalURL, + originalURL.href, initiatorType, globalThis, cacheState @@ -17268,23 +19504,15 @@ function requireFetch () { } // https://w3c.github.io/resource-timing/#dfn-mark-resource-timing - function markResourceTiming (timingInfo, originalURL, initiatorType, globalThis, cacheState) { - if (nodeMajor > 18 || (nodeMajor === 18 && nodeMinor >= 2)) { - performance.markResourceTiming(timingInfo, originalURL.href, initiatorType, globalThis, cacheState); - } - } + const markResourceTiming = performance.markResourceTiming; // https://fetch.spec.whatwg.org/#abort-fetch function abortFetch (p, request, responseObject, error) { - // Note: AbortSignal.reason was added in node v17.2.0 - // which would give us an undefined error to reject with. - // Remove this once node v16 is no longer supported. - if (!error) { - error = new DOMException('The operation was aborted.', 'AbortError'); - } - // 1. Reject promise with error. - p.reject(error); + if (p) { + // We might have already resolved the promise at this stage + p.reject(error); + } // 2. If request’s body is not null and is readable, then cancel request’s // body with error. @@ -17328,8 +19556,11 @@ function requireFetch () { processResponseEndOfBody, processResponseConsumeBody, useParallelQueue = false, - dispatcher // undici + dispatcher = getGlobalDispatcher() // undici }) { + // Ensure that the dispatcher is set accordingly + assert(dispatcher); + // 1. Let taskDestination be null. let taskDestination = null; @@ -17354,9 +19585,9 @@ function requireFetch () { // 5. Let timingInfo be a new fetch timing info whose start time and // post-redirect start time are the coarsened shared current time given // crossOriginIsolatedCapability. - const currenTime = coarsenedSharedCurrentTime(crossOriginIsolatedCapability); + const currentTime = coarsenedSharedCurrentTime(crossOriginIsolatedCapability); const timingInfo = createOpaqueTimingInfo({ - startTime: currenTime + startTime: currentTime }); // 6. Let fetchParams be a new fetch params whose @@ -17402,8 +19633,7 @@ function requireFetch () { // 9. If request’s origin is "client", then set request’s origin to request’s // client’s origin. if (request.origin === 'client') { - // TODO: What if request.client is null? - request.origin = request.client?.origin; + request.origin = request.client.origin; } // 10. If all of the following conditions are true: @@ -17425,7 +19655,7 @@ function requireFetch () { } // 12. If request’s header list does not contain `Accept`, then: - if (!request.headersList.contains('accept')) { + if (!request.headersList.contains('accept', true)) { // 1. Let value be `*/*`. const value = '*/*'; @@ -17442,14 +19672,14 @@ function requireFetch () { // TODO // 3. Append `Accept`/value to request’s header list. - request.headersList.append('accept', value); + request.headersList.append('accept', value, true); } // 13. If request’s header list does not contain `Accept-Language`, then // user agents should append `Accept-Language`/an appropriate value to // request’s header list. - if (!request.headersList.contains('accept-language')) { - request.headersList.append('accept-language', '*'); + if (!request.headersList.contains('accept-language', true)) { + request.headersList.append('accept-language', '*', true); } // 14. If request’s priority is null, then use request’s initiator and @@ -17653,7 +19883,7 @@ function requireFetch () { response.type === 'opaque' && internalResponse.status === 206 && internalResponse.rangeRequested && - !request.headers.contains('range') + !request.headers.contains('range', true) ) { response = internalResponse = makeNetworkError(); } @@ -17738,7 +19968,7 @@ function requireFetch () { } case 'blob:': { if (!resolveObjectURL) { - resolveObjectURL = require$$7.resolveObjectURL; + resolveObjectURL = require$$0$2.resolveObjectURL; } // 1. Let blobURLEntry be request’s current URL’s blob URL entry. @@ -17750,38 +19980,118 @@ function requireFetch () { return Promise.resolve(makeNetworkError('NetworkError when attempting to fetch resource.')) } - const blobURLEntryObject = resolveObjectURL(blobURLEntry.toString()); + const blob = resolveObjectURL(blobURLEntry.toString()); // 2. If request’s method is not `GET`, blobURLEntry is null, or blobURLEntry’s // object is not a Blob object, then return a network error. - if (request.method !== 'GET' || !isBlobLike(blobURLEntryObject)) { + if (request.method !== 'GET' || !isBlobLike(blob)) { return Promise.resolve(makeNetworkError('invalid method')) } - // 3. Let bodyWithType be the result of safely extracting blobURLEntry’s object. - const bodyWithType = safelyExtractBody(blobURLEntryObject); + // 3. Let blob be blobURLEntry’s object. + // Note: done above - // 4. Let body be bodyWithType’s body. - const body = bodyWithType[0]; + // 4. Let response be a new response. + const response = makeResponse(); - // 5. Let length be body’s length, serialized and isomorphic encoded. - const length = isomorphicEncode(`${body.length}`); + // 5. Let fullLength be blob’s size. + const fullLength = blob.size; - // 6. Let type be bodyWithType’s type if it is non-null; otherwise the empty byte sequence. - const type = bodyWithType[1] ?? ''; + // 6. Let serializedFullLength be fullLength, serialized and isomorphic encoded. + const serializedFullLength = isomorphicEncode(`${fullLength}`); - // 7. Return a new response whose status message is `OK`, header list is - // « (`Content-Length`, length), (`Content-Type`, type) », and body is body. - const response = makeResponse({ - statusText: 'OK', - headersList: [ - ['content-length', { name: 'Content-Length', value: length }], - ['content-type', { name: 'Content-Type', value: type }] - ] - }); + // 7. Let type be blob’s type. + const type = blob.type; + + // 8. If request’s header list does not contain `Range`: + // 9. Otherwise: + if (!request.headersList.contains('range', true)) { + // 1. Let bodyWithType be the result of safely extracting blob. + // Note: in the FileAPI a blob "object" is a Blob *or* a MediaSource. + // In node, this can only ever be a Blob. Therefore we can safely + // use extractBody directly. + const bodyWithType = extractBody(blob); + + // 2. Set response’s status message to `OK`. + response.statusText = 'OK'; + + // 3. Set response’s body to bodyWithType’s body. + response.body = bodyWithType[0]; - response.body = body; + // 4. Set response’s header list to « (`Content-Length`, serializedFullLength), (`Content-Type`, type) ». + response.headersList.set('content-length', serializedFullLength, true); + response.headersList.set('content-type', type, true); + } else { + // 1. Set response’s range-requested flag. + response.rangeRequested = true; + + // 2. Let rangeHeader be the result of getting `Range` from request’s header list. + const rangeHeader = request.headersList.get('range', true); + // 3. Let rangeValue be the result of parsing a single range header value given rangeHeader and true. + const rangeValue = simpleRangeHeaderValue(rangeHeader, true); + + // 4. If rangeValue is failure, then return a network error. + if (rangeValue === 'failure') { + return Promise.resolve(makeNetworkError('failed to fetch the data URL')) + } + + // 5. Let (rangeStart, rangeEnd) be rangeValue. + let { rangeStartValue: rangeStart, rangeEndValue: rangeEnd } = rangeValue; + + // 6. If rangeStart is null: + // 7. Otherwise: + if (rangeStart === null) { + // 1. Set rangeStart to fullLength − rangeEnd. + rangeStart = fullLength - rangeEnd; + + // 2. Set rangeEnd to rangeStart + rangeEnd − 1. + rangeEnd = rangeStart + rangeEnd - 1; + } else { + // 1. If rangeStart is greater than or equal to fullLength, then return a network error. + if (rangeStart >= fullLength) { + return Promise.resolve(makeNetworkError('Range start is greater than the blob\'s size.')) + } + + // 2. If rangeEnd is null or rangeEnd is greater than or equal to fullLength, then set + // rangeEnd to fullLength − 1. + if (rangeEnd === null || rangeEnd >= fullLength) { + rangeEnd = fullLength - 1; + } + } + + // 8. Let slicedBlob be the result of invoking slice blob given blob, rangeStart, + // rangeEnd + 1, and type. + const slicedBlob = blob.slice(rangeStart, rangeEnd, type); + + // 9. Let slicedBodyWithType be the result of safely extracting slicedBlob. + // Note: same reason as mentioned above as to why we use extractBody + const slicedBodyWithType = extractBody(slicedBlob); + + // 10. Set response’s body to slicedBodyWithType’s body. + response.body = slicedBodyWithType[0]; + + // 11. Let serializedSlicedLength be slicedBlob’s size, serialized and isomorphic encoded. + const serializedSlicedLength = isomorphicEncode(`${slicedBlob.size}`); + + // 12. Let contentRange be the result of invoking build a content range given rangeStart, + // rangeEnd, and fullLength. + const contentRange = buildContentRange(rangeStart, rangeEnd, fullLength); + + // 13. Set response’s status to 206. + response.status = 206; + + // 14. Set response’s status message to `Partial Content`. + response.statusText = 'Partial Content'; + + // 15. Set response’s header list to « (`Content-Length`, serializedSlicedLength), + // (`Content-Type`, type), (`Content-Range`, contentRange) ». + response.headersList.set('content-length', serializedSlicedLength, true); + response.headersList.set('content-type', type, true); + response.headersList.set('content-range', contentRange, true); + } + + // 10. Return response. return Promise.resolve(response) } case 'data:': { @@ -17843,92 +20153,128 @@ function requireFetch () { // https://fetch.spec.whatwg.org/#fetch-finale function fetchFinale (fetchParams, response) { - // 1. If response is a network error, then: - if (response.type === 'error') { - // 1. Set response’s URL list to « fetchParams’s request’s URL list[0] ». - response.urlList = [fetchParams.request.urlList[0]]; - - // 2. Set response’s timing info to the result of creating an opaque timing - // info for fetchParams’s timing info. - response.timingInfo = createOpaqueTimingInfo({ - startTime: fetchParams.timingInfo.startTime - }); - } + // 1. Let timingInfo be fetchParams’s timing info. + let timingInfo = fetchParams.timingInfo; - // 2. Let processResponseEndOfBody be the following steps: + // 2. If response is not a network error and fetchParams’s request’s client is a secure context, + // then set timingInfo’s server-timing headers to the result of getting, decoding, and splitting + // `Server-Timing` from response’s internal response’s header list. + // TODO + + // 3. Let processResponseEndOfBody be the following steps: const processResponseEndOfBody = () => { - // 1. Set fetchParams’s request’s done flag. - fetchParams.request.done = true; + // 1. Let unsafeEndTime be the unsafe shared current time. + const unsafeEndTime = Date.now(); // ? - // If fetchParams’s process response end-of-body is not null, - // then queue a fetch task to run fetchParams’s process response - // end-of-body given response with fetchParams’s task destination. - if (fetchParams.processResponseEndOfBody != null) { - queueMicrotask(() => fetchParams.processResponseEndOfBody(response)); + // 2. If fetchParams’s request’s destination is "document", then set fetchParams’s controller’s + // full timing info to fetchParams’s timing info. + if (fetchParams.request.destination === 'document') { + fetchParams.controller.fullTimingInfo = timingInfo; } - }; - // 3. If fetchParams’s process response is non-null, then queue a fetch task - // to run fetchParams’s process response given response, with fetchParams’s - // task destination. - if (fetchParams.processResponse != null) { - queueMicrotask(() => fetchParams.processResponse(response)); - } + // 3. Set fetchParams’s controller’s report timing steps to the following steps given a global object global: + fetchParams.controller.reportTimingSteps = () => { + // 1. If fetchParams’s request’s URL’s scheme is not an HTTP(S) scheme, then return. + if (fetchParams.request.url.protocol !== 'https:') { + return + } - // 4. If response’s body is null, then run processResponseEndOfBody. - if (response.body == null) { - processResponseEndOfBody(); - } else { - // 5. Otherwise: + // 2. Set timingInfo’s end time to the relative high resolution time given unsafeEndTime and global. + timingInfo.endTime = unsafeEndTime; + + // 3. Let cacheState be response’s cache state. + let cacheState = response.cacheState; + + // 4. Let bodyInfo be response’s body info. + const bodyInfo = response.bodyInfo; + + // 5. If response’s timing allow passed flag is not set, then set timingInfo to the result of creating an + // opaque timing info for timingInfo and set cacheState to the empty string. + if (!response.timingAllowPassed) { + timingInfo = createOpaqueTimingInfo(timingInfo); - // 1. Let transformStream be a new a TransformStream. + cacheState = ''; + } + + // 6. Let responseStatus be 0. + let responseStatus = 0; + + // 7. If fetchParams’s request’s mode is not "navigate" or response’s has-cross-origin-redirects is false: + if (fetchParams.request.mode !== 'navigator' || !response.hasCrossOriginRedirects) { + // 1. Set responseStatus to response’s status. + responseStatus = response.status; + + // 2. Let mimeType be the result of extracting a MIME type from response’s header list. + const mimeType = extractMimeType(response.headersList); - // 2. Let identityTransformAlgorithm be an algorithm which, given chunk, - // enqueues chunk in transformStream. - const identityTransformAlgorithm = (chunk, controller) => { - controller.enqueue(chunk); + // 3. If mimeType is not failure, then set bodyInfo’s content type to the result of minimizing a supported MIME type given mimeType. + if (mimeType !== 'failure') { + bodyInfo.contentType = minimizeSupportedMimeType(mimeType); + } + } + + // 8. If fetchParams’s request’s initiator type is non-null, then mark resource timing given timingInfo, + // fetchParams’s request’s URL, fetchParams’s request’s initiator type, global, cacheState, bodyInfo, + // and responseStatus. + if (fetchParams.request.initiatorType != null) { + // TODO: update markresourcetiming + markResourceTiming(timingInfo, fetchParams.request.url.href, fetchParams.request.initiatorType, globalThis, cacheState, bodyInfo, responseStatus); + } }; - // 3. Set up transformStream with transformAlgorithm set to identityTransformAlgorithm - // and flushAlgorithm set to processResponseEndOfBody. - const transformStream = new TransformStream({ - start () {}, - transform: identityTransformAlgorithm, - flush: processResponseEndOfBody - }, { - size () { - return 1 + // 4. Let processResponseEndOfBodyTask be the following steps: + const processResponseEndOfBodyTask = () => { + // 1. Set fetchParams’s request’s done flag. + fetchParams.request.done = true; + + // 2. If fetchParams’s process response end-of-body is non-null, then run fetchParams’s process + // response end-of-body given response. + if (fetchParams.processResponseEndOfBody != null) { + queueMicrotask(() => fetchParams.processResponseEndOfBody(response)); } - }, { - size () { - return 1 + + // 3. If fetchParams’s request’s initiator type is non-null and fetchParams’s request’s client’s + // global object is fetchParams’s task destination, then run fetchParams’s controller’s report + // timing steps given fetchParams’s request’s client’s global object. + if (fetchParams.request.initiatorType != null) { + fetchParams.controller.reportTimingSteps(); } - }); + }; - // 4. Set response’s body to the result of piping response’s body through transformStream. - response.body = { stream: response.body.stream.pipeThrough(transformStream) }; - } + // 5. Queue a fetch task to run processResponseEndOfBodyTask with fetchParams’s task destination + queueMicrotask(() => processResponseEndOfBodyTask()); + }; - // 6. If fetchParams’s process response consume body is non-null, then: - if (fetchParams.processResponseConsumeBody != null) { - // 1. Let processBody given nullOrBytes be this step: run fetchParams’s - // process response consume body given response and nullOrBytes. - const processBody = (nullOrBytes) => fetchParams.processResponseConsumeBody(response, nullOrBytes); + // 4. If fetchParams’s process response is non-null, then queue a fetch task to run fetchParams’s + // process response given response, with fetchParams’s task destination. + if (fetchParams.processResponse != null) { + queueMicrotask(() => { + fetchParams.processResponse(response); + fetchParams.processResponse = null; + }); + } - // 2. Let processBodyError be this step: run fetchParams’s process - // response consume body given response and failure. - const processBodyError = (failure) => fetchParams.processResponseConsumeBody(response, failure); + // 5. Let internalResponse be response, if response is a network error; otherwise response’s internal response. + const internalResponse = response.type === 'error' ? response : (response.internalResponse ?? response); - // 3. If response’s body is null, then queue a fetch task to run processBody - // given null, with fetchParams’s task destination. - if (response.body == null) { - queueMicrotask(() => processBody(null)); - } else { - // 4. Otherwise, fully read response’s body given processBody, processBodyError, - // and fetchParams’s task destination. - return fullyReadBody(response.body, processBody, processBodyError) - } - return Promise.resolve() + // 6. If internalResponse’s body is null, then run processResponseEndOfBody. + // 7. Otherwise: + if (internalResponse.body == null) { + processResponseEndOfBody(); + } else { + // mcollina: all the following steps of the specs are skipped. + // The internal transform stream is not needed. + // See https://github.com/nodejs/undici/pull/3093#issuecomment-2050198541 + + // 1. Let transformStream be a new TransformStream. + // 2. Let identityTransformAlgorithm be an algorithm which, given chunk, enqueues chunk in transformStream. + // 3. Set up transformStream with transformAlgorithm set to identityTransformAlgorithm and flushAlgorithm + // set to processResponseEndOfBody. + // 4. Set internalResponse’s body’s stream to the result of internalResponse’s body’s stream piped through transformStream. + + finished(internalResponse.body.stream, () => { + processResponseEndOfBody(); + }); } } @@ -18003,7 +20349,7 @@ function requireFetch () { // encouraged to, transmit an RST_STREAM frame. // See, https://github.com/whatwg/fetch/issues/1288 if (request.redirect !== 'manual') { - fetchParams.controller.connection.destroy(); + fetchParams.controller.connection.destroy(undefined, false); } // 2. Switch on request’s redirect mode: @@ -18134,14 +20480,14 @@ function requireFetch () { // delete headerName from request’s header list. if (!sameOrigin(requestCurrentURL(request), locationURL)) { // https://fetch.spec.whatwg.org/#cors-non-wildcard-request-header-name - request.headersList.delete('authorization'); + request.headersList.delete('authorization', true); // https://fetch.spec.whatwg.org/#authentication-entries request.headersList.delete('proxy-authorization', true); // "Cookie" and "Host" are forbidden request-headers, which undici doesn't implement. - request.headersList.delete('cookie'); - request.headersList.delete('host'); + request.headersList.delete('cookie', true); + request.headersList.delete('host', true); } // 14. If request’s body is non-null, then set request’s body to the first return @@ -18207,7 +20553,7 @@ function requireFetch () { // Otherwise: // 1. Set httpRequest to a clone of request. - httpRequest = makeRequest(request); + httpRequest = cloneRequest(request); // 2. Set httpFetchParams to a copy of fetchParams. httpFetchParams = { ...fetchParams }; @@ -18248,7 +20594,7 @@ function requireFetch () { // `Content-Length`/contentLengthHeaderValue to httpRequest’s header // list. if (contentLengthHeaderValue != null) { - httpRequest.headersList.append('content-length', contentLengthHeaderValue); + httpRequest.headersList.append('content-length', contentLengthHeaderValue, true); } // 9. If contentLengthHeaderValue is non-null, then append (`Content-Length`, @@ -18262,7 +20608,7 @@ function requireFetch () { // `Referer`/httpRequest’s referrer, serialized and isomorphic encoded, // to httpRequest’s header list. if (httpRequest.referrer instanceof URL) { - httpRequest.headersList.append('referer', isomorphicEncode(httpRequest.referrer.href)); + httpRequest.headersList.append('referer', isomorphicEncode(httpRequest.referrer.href), true); } // 12. Append a request `Origin` header for httpRequest. @@ -18274,8 +20620,8 @@ function requireFetch () { // 14. If httpRequest’s header list does not contain `User-Agent`, then // user agents should append `User-Agent`/default `User-Agent` value to // httpRequest’s header list. - if (!httpRequest.headersList.contains('user-agent')) { - httpRequest.headersList.append('user-agent', typeof esbuildDetection === 'undefined' ? 'undici' : 'node'); + if (!httpRequest.headersList.contains('user-agent', true)) { + httpRequest.headersList.append('user-agent', defaultUserAgent); } // 15. If httpRequest’s cache mode is "default" and httpRequest’s header @@ -18284,11 +20630,11 @@ function requireFetch () { // httpRequest’s cache mode to "no-store". if ( httpRequest.cache === 'default' && - (httpRequest.headersList.contains('if-modified-since') || - httpRequest.headersList.contains('if-none-match') || - httpRequest.headersList.contains('if-unmodified-since') || - httpRequest.headersList.contains('if-match') || - httpRequest.headersList.contains('if-range')) + (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'; } @@ -18300,44 +20646,44 @@ function requireFetch () { if ( httpRequest.cache === 'no-cache' && !httpRequest.preventNoCacheCacheControlHeaderModification && - !httpRequest.headersList.contains('cache-control') + !httpRequest.headersList.contains('cache-control', true) ) { - httpRequest.headersList.append('cache-control', 'max-age=0'); + httpRequest.headersList.append('cache-control', 'max-age=0', true); } // 17. If httpRequest’s cache mode is "no-store" or "reload", then: if (httpRequest.cache === 'no-store' || httpRequest.cache === 'reload') { // 1. If httpRequest’s header list does not contain `Pragma`, then append // `Pragma`/`no-cache` to httpRequest’s header list. - if (!httpRequest.headersList.contains('pragma')) { - httpRequest.headersList.append('pragma', 'no-cache'); + if (!httpRequest.headersList.contains('pragma', true)) { + httpRequest.headersList.append('pragma', 'no-cache', true); } // 2. If httpRequest’s header list does not contain `Cache-Control`, // then append `Cache-Control`/`no-cache` to httpRequest’s header list. - if (!httpRequest.headersList.contains('cache-control')) { - httpRequest.headersList.append('cache-control', 'no-cache'); + if (!httpRequest.headersList.contains('cache-control', true)) { + httpRequest.headersList.append('cache-control', 'no-cache', true); } } // 18. If httpRequest’s header list contains `Range`, then append // `Accept-Encoding`/`identity` to httpRequest’s header list. - if (httpRequest.headersList.contains('range')) { - httpRequest.headersList.append('accept-encoding', 'identity'); + if (httpRequest.headersList.contains('range', true)) { + httpRequest.headersList.append('accept-encoding', 'identity', true); } // 19. Modify httpRequest’s header list per HTTP. Do not append a given // header if httpRequest’s header list contains that header’s name. // TODO: https://github.com/whatwg/fetch/issues/1285#issuecomment-896560129 - if (!httpRequest.headersList.contains('accept-encoding')) { + if (!httpRequest.headersList.contains('accept-encoding', true)) { if (urlHasHttpsScheme(requestCurrentURL(httpRequest))) { - httpRequest.headersList.append('accept-encoding', 'br, gzip, deflate'); + httpRequest.headersList.append('accept-encoding', 'br, gzip, deflate', true); } else { - httpRequest.headersList.append('accept-encoding', 'gzip, deflate'); + httpRequest.headersList.append('accept-encoding', 'gzip, deflate', true); } } - httpRequest.headersList.delete('host'); + httpRequest.headersList.delete('host', true); // 21. If there’s a proxy-authentication entry, use it as appropriate. // TODO: proxy-authentication @@ -18354,7 +20700,7 @@ function requireFetch () { // 24. If httpRequest’s cache mode is neither "no-store" nor "reload", // then: - if (httpRequest.mode !== 'no-store' && httpRequest.mode !== 'reload') ; + if (httpRequest.cache !== 'no-store' && httpRequest.cache !== 'reload') ; // 9. If aborted, then return the appropriate network error for fetchParams. // TODO @@ -18363,7 +20709,7 @@ function requireFetch () { if (response == null) { // 1. If httpRequest’s cache mode is "only-if-cached", then return a // network error. - if (httpRequest.mode === 'only-if-cached') { + if (httpRequest.cache === 'only-if-cached') { return makeNetworkError('only if cached') } @@ -18401,7 +20747,7 @@ function requireFetch () { // 12. If httpRequest’s header list contains `Range`, then set response’s // range-requested flag. - if (httpRequest.headersList.contains('range')) { + if (httpRequest.headersList.contains('range', true)) { response.rangeRequested = true; } @@ -18483,10 +20829,12 @@ function requireFetch () { fetchParams.controller.connection = { abort: null, destroyed: false, - destroy (err) { + destroy (err, abort = true) { if (!this.destroyed) { this.destroyed = true; - this.abort?.(err ?? new DOMException('The operation was aborted.', 'AbortError')); + if (abort) { + this.abort?.(err ?? new DOMException('The operation was aborted.', 'AbortError')); + } } } }; @@ -18655,14 +21003,18 @@ function requireFetch () { // 11. Let pullAlgorithm be an action that resumes the ongoing fetch // if it is suspended. - const pullAlgorithm = () => { - fetchParams.controller.resume(); + const pullAlgorithm = async () => { + await fetchParams.controller.resume(); }; // 12. Let cancelAlgorithm be an algorithm that aborts fetchParams’s // controller with reason, given reason. const cancelAlgorithm = (reason) => { - fetchParams.controller.abort(reason); + // If the aborted fetch was already terminated, then we do not + // need to do anything. + if (!isCancelled(fetchParams)) { + fetchParams.controller.abort(reason); + } }; // 13. Let highWaterMark be a non-negative, non-NaN number, chosen by @@ -18674,13 +21026,8 @@ function requireFetch () { // TODO // 15. Let stream be a new ReadableStream. - // 16. Set up stream with pullAlgorithm set to pullAlgorithm, - // cancelAlgorithm set to cancelAlgorithm, highWaterMark set to - // highWaterMark, and sizeAlgorithm set to sizeAlgorithm. - if (!ReadableStream) { - ReadableStream = require$$14.ReadableStream; - } - + // 16. Set up stream with byte reading support with pullAlgorithm set to pullAlgorithm, + // cancelAlgorithm set to cancelAlgorithm. const stream = new ReadableStream( { async start (controller) { @@ -18691,20 +21038,15 @@ function requireFetch () { }, async cancel (reason) { await cancelAlgorithm(reason); - } - }, - { - highWaterMark: 0, - size () { - return 1 - } + }, + type: 'bytes' } ); // 17. Run these steps, but abort when the ongoing fetch is terminated: // 1. Set response’s body to a new body whose stream is stream. - response.body = { stream }; + response.body = { stream, source: null, length: null }; // 2. If response is not a network error and request’s cache mode is // not "no-store", then update response in httpCache for request. @@ -18723,6 +21065,7 @@ function requireFetch () { // 19. Run these steps in parallel: // 1. Run these steps, but abort when fetchParams is canceled: + fetchParams.controller.onAborted = onAborted; fetchParams.controller.on('terminated', onAborted); fetchParams.controller.resume = async () => { // 1. While true @@ -18777,7 +21120,10 @@ function requireFetch () { // 7. Enqueue a Uint8Array wrapping an ArrayBuffer containing bytes // into stream. - fetchParams.controller.controller.enqueue(new Uint8Array(bytes)); + const buffer = new Uint8Array(bytes); + if (buffer.byteLength) { + fetchParams.controller.controller.enqueue(buffer); + } // 8. If stream is errored, then terminate the ongoing fetch. if (isErrored(stream)) { @@ -18787,7 +21133,7 @@ function requireFetch () { // 9. If stream doesn’t need more data ask the user agent to suspend // the ongoing fetch. - if (!fetchParams.controller.controller.desiredSize) { + if (fetchParams.controller.controller.desiredSize <= 0) { return } } @@ -18826,7 +21172,7 @@ function requireFetch () { // 20. Return response. return response - async function dispatch ({ body }) { + function dispatch ({ body }) { const url = requestCurrentURL(request); /** @type {import('../..').Agent} */ const agent = fetchParams.controller.dispatcher; @@ -18836,7 +21182,7 @@ function requireFetch () { path: url.pathname + url.search, origin: url.origin, method: request.method, - body: fetchParams.controller.dispatcher.isMockActive ? request.body && (request.body.source || request.body.stream) : body, + body: agent.isMockActive ? request.body && (request.body.source || request.body.stream) : body, headers: request.headersList.entries, maxRedirections: 0, upgrade: request.mode === 'websocket' ? 'websocket' : undefined @@ -18849,67 +21195,71 @@ function requireFetch () { // TODO (fix): Do we need connection here? const { connection } = fetchParams.controller; + // Set timingInfo’s final connection timing info to the result of calling clamp and coarsen + // connection timing info with connection’s timing info, timingInfo’s post-redirect start + // time, and fetchParams’s cross-origin isolated capability. + // TODO: implement connection timing + timingInfo.finalConnectionTimingInfo = clampAndCoarsenConnectionTimingInfo(undefined, 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; } + + // Set timingInfo’s final network-request start time to the coarsened shared current time given + // fetchParams’s cross-origin isolated capability. + timingInfo.finalNetworkRequestStartTime = coarsenedSharedCurrentTime(fetchParams.crossOriginIsolatedCapability); + }, + + onResponseStarted () { + // Set timingInfo’s final network-response start time to the coarsened shared current + // time given fetchParams’s cross-origin isolated capability, immediately after the + // user agent’s HTTP parser receives the first byte of the response (e.g., frame header + // bytes for HTTP/2 or response status line for HTTP/1.x). + timingInfo.finalNetworkResponseStartTime = coarsenedSharedCurrentTime(fetchParams.crossOriginIsolatedCapability); }, - onHeaders (status, headersList, resume, statusText) { + onHeaders (status, rawHeaders, resume, statusText) { if (status < 200) { return } - let codings = []; let location = ''; - const headers = new Headers(); - - // For H2, the headers are a plain JS object - // We distinguish between them and iterate accordingly - if (Array.isArray(headersList)) { - for (let n = 0; n < headersList.length; n += 2) { - const key = headersList[n + 0].toString('latin1'); - const val = headersList[n + 1].toString('latin1'); - if (key.toLowerCase() === 'content-encoding') { - // https://www.rfc-editor.org/rfc/rfc7231#section-3.1.2.1 - // "All content-coding values are case-insensitive..." - codings = val.toLowerCase().split(',').map((x) => x.trim()); - } else if (key.toLowerCase() === 'location') { - location = val; - } - - headers[kHeadersList].append(key, val); - } - } else { - const keys = Object.keys(headersList); - for (const key of keys) { - const val = headersList[key]; - if (key.toLowerCase() === 'content-encoding') { - // https://www.rfc-editor.org/rfc/rfc7231#section-3.1.2.1 - // "All content-coding values are case-insensitive..." - codings = val.toLowerCase().split(',').map((x) => x.trim()).reverse(); - } else if (key.toLowerCase() === 'location') { - location = val; - } + const headersList = new HeadersList(); - headers[kHeadersList].append(key, val); - } + 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 Readable({ read: resume }); const decoders = []; - const willFollow = request.redirect === 'follow' && - location && + const willFollow = location && request.redirect === 'follow' && redirectStatusSet.has(status); // https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Encoding if (request.method !== 'HEAD' && request.method !== 'CONNECT' && !nullBodyStatus.includes(status) && !willFollow) { - for (const coding of codings) { + // https://www.rfc-editor.org/rfc/rfc7231#section-3.1.2.1 + const contentEncoding = headersList.get('content-encoding', true); + // "All content-coding values are case-insensitive..." + /** @type {string[]} */ + const codings = contentEncoding ? contentEncoding.toLowerCase().split(',') : []; + + // Limit the number of content-encodings to prevent resource exhaustion. + // CVE fix similar to urllib3 (GHSA-gm62-xv2j-4w53) and curl (CVE-2022-32206). + 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(); // https://www.rfc-editor.org/rfc/rfc9112.html#section-7.2 if (coding === 'x-gzip' || coding === 'gzip') { decoders.push(zlib.createGunzip({ @@ -18921,9 +21271,15 @@ function requireFetch () { finishFlush: zlib.constants.Z_SYNC_FLUSH })); } else if (coding === 'deflate') { - decoders.push(zlib.createInflate()); + decoders.push(createInflate({ + flush: zlib.constants.Z_SYNC_FLUSH, + finishFlush: zlib.constants.Z_SYNC_FLUSH + })); } else if (coding === 'br') { - decoders.push(zlib.createBrotliDecompress()); + decoders.push(zlib.createBrotliDecompress({ + flush: zlib.constants.BROTLI_OPERATION_FLUSH, + finishFlush: zlib.constants.BROTLI_OPERATION_FLUSH + })); } else { decoders.length = 0; break @@ -18931,13 +21287,19 @@ function requireFetch () { } } + const onError = this.onError.bind(this); + resolve({ status, statusText, - headersList: headers[kHeadersList], + headersList, body: decoders.length - ? pipeline(this.body, ...decoders, () => { }) - : this.body.on('error', () => {}) + ? pipeline(this.body, ...decoders, (err) => { + if (err) { + this.onError(err); + } + }).on('error', onError) + : this.body.on('error', onError) }); return true @@ -18971,6 +21333,10 @@ function requireFetch () { 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); @@ -18988,24 +21354,21 @@ function requireFetch () { reject(error); }, - onUpgrade (status, headersList, socket) { + onUpgrade (status, rawHeaders, socket) { if (status !== 101) { return } - const headers = new Headers(); - - for (let n = 0; n < headersList.length; n += 2) { - const key = headersList[n + 0].toString('latin1'); - const val = headersList[n + 1].toString('latin1'); + const headersList = new HeadersList(); - headers[kHeadersList].append(key, val); + 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: headers[kHeadersList], + headersList, socket }); @@ -19059,7 +21422,7 @@ function requireProgressevent () { */ class ProgressEvent extends Event { constructor (type, eventInitDict = {}) { - type = webidl.converters.DOMString(type); + type = webidl.converters.DOMString(type, 'ProgressEvent constructor', 'type'); eventInitDict = webidl.converters.ProgressEventInit(eventInitDict ?? {}); super(type, eventInitDict); @@ -19094,32 +21457,32 @@ function requireProgressevent () { { key: 'lengthComputable', converter: webidl.converters.boolean, - defaultValue: false + defaultValue: () => false }, { key: 'loaded', converter: webidl.converters['unsigned long long'], - defaultValue: 0 + defaultValue: () => 0 }, { key: 'total', converter: webidl.converters['unsigned long long'], - defaultValue: 0 + defaultValue: () => 0 }, { key: 'bubbles', converter: webidl.converters.boolean, - defaultValue: false + defaultValue: () => false }, { key: 'cancelable', converter: webidl.converters.boolean, - defaultValue: false + defaultValue: () => false }, { key: 'composed', converter: webidl.converters.boolean, - defaultValue: false + defaultValue: () => false } ]); @@ -19427,12 +21790,12 @@ function requireEncoding () { return encoding; } -var util$4; -var hasRequiredUtil$4; +var util$5; +var hasRequiredUtil$5; -function requireUtil$4 () { - if (hasRequiredUtil$4) return util$4; - hasRequiredUtil$4 = 1; +function requireUtil$5 () { + if (hasRequiredUtil$5) return util$5; + hasRequiredUtil$5 = 1; const { kState, @@ -19443,11 +21806,10 @@ function requireUtil$4 () { } = requireSymbols$2(); const { ProgressEvent } = requireProgressevent(); const { getEncoding } = requireEncoding(); - const { DOMException } = requireConstants$3(); - const { serializeAMimeType, parseMIMEType } = requireDataURL(); - const { types } = require$$0$2; - const { StringDecoder } = require$$6; - const { btoa } = require$$7; + const { serializeAMimeType, parseMIMEType } = requireDataUrl(); + const { types } = require$$0$6; + const { StringDecoder } = require$$5$3; + const { btoa } = require$$0$2; /** @type {PropertyDescriptor} */ const staticPropertyDescriptors = { @@ -19819,12 +22181,12 @@ function requireUtil$4 () { }, new Uint8Array(size)) } - util$4 = { + util$5 = { staticPropertyDescriptors, readOperation, fireAProgressEvent }; - return util$4; + return util$5; } var filereader; @@ -19838,7 +22200,7 @@ function requireFilereader () { staticPropertyDescriptors, readOperation, fireAProgressEvent - } = requireUtil$4(); + } = requireUtil$5(); const { kState, kError, @@ -19847,7 +22209,7 @@ function requireFilereader () { kAborted } = requireSymbols$2(); const { webidl } = requireWebidl(); - const { kEnumerableProperty } = requireUtil$7(); + const { kEnumerableProperty } = requireUtil$8(); class FileReader extends EventTarget { constructor () { @@ -19873,7 +22235,7 @@ function requireFilereader () { readAsArrayBuffer (blob) { webidl.brandCheck(this, FileReader); - webidl.argumentLengthCheck(arguments, 1, { header: 'FileReader.readAsArrayBuffer' }); + webidl.argumentLengthCheck(arguments, 1, 'FileReader.readAsArrayBuffer'); blob = webidl.converters.Blob(blob, { strict: false }); @@ -19889,7 +22251,7 @@ function requireFilereader () { readAsBinaryString (blob) { webidl.brandCheck(this, FileReader); - webidl.argumentLengthCheck(arguments, 1, { header: 'FileReader.readAsBinaryString' }); + webidl.argumentLengthCheck(arguments, 1, 'FileReader.readAsBinaryString'); blob = webidl.converters.Blob(blob, { strict: false }); @@ -19906,12 +22268,12 @@ function requireFilereader () { readAsText (blob, encoding = undefined) { webidl.brandCheck(this, FileReader); - webidl.argumentLengthCheck(arguments, 1, { header: 'FileReader.readAsText' }); + webidl.argumentLengthCheck(arguments, 1, 'FileReader.readAsText'); blob = webidl.converters.Blob(blob, { strict: false }); if (encoding !== undefined) { - encoding = webidl.converters.DOMString(encoding); + encoding = webidl.converters.DOMString(encoding, 'FileReader.readAsText', 'encoding'); } // The readAsText(blob, encoding) method, when invoked, @@ -19926,7 +22288,7 @@ function requireFilereader () { readAsDataURL (blob) { webidl.brandCheck(this, FileReader); - webidl.argumentLengthCheck(arguments, 1, { header: 'FileReader.readAsDataURL' }); + webidl.argumentLengthCheck(arguments, 1, 'FileReader.readAsDataURL'); blob = webidl.converters.Blob(blob, { strict: false }); @@ -20192,16 +22554,16 @@ function requireSymbols$1 () { return symbols$1; } -var util$3; -var hasRequiredUtil$3; +var util$4; +var hasRequiredUtil$4; -function requireUtil$3 () { - if (hasRequiredUtil$3) return util$3; - hasRequiredUtil$3 = 1; +function requireUtil$4 () { + if (hasRequiredUtil$4) return util$4; + hasRequiredUtil$4 = 1; const assert = require$$0$3; - const { URLSerializer } = requireDataURL(); - const { isValidHeaderName } = requireUtil$6(); + const { URLSerializer } = requireDataUrl(); + const { isValidHeaderName } = requireUtil$7(); /** * @see https://url.spec.whatwg.org/#concept-url-equals @@ -20222,7 +22584,7 @@ function requireUtil$3 () { * @see https://github.com/chromium/chromium/blob/694d20d134cb553d8d89e5500b9148012b1ba299/content/browser/cache_storage/cache_storage_cache.cc#L260-L262 * @param {string} header */ - function fieldValues (header) { + function getFieldValues (header) { assert(header !== null); const values = []; @@ -20230,23 +22592,19 @@ function requireUtil$3 () { for (let value of header.split(',')) { value = value.trim(); - if (!value.length) { - continue - } else if (!isValidHeaderName(value)) { - continue + if (isValidHeaderName(value)) { + values.push(value); } - - values.push(value); } return values } - util$3 = { + util$4 = { urlEquals, - fieldValues + getFieldValues }; - return util$3; + return util$4; } var cache; @@ -20257,17 +22615,15 @@ function requireCache () { hasRequiredCache = 1; const { kConstruct } = requireSymbols$1(); - const { urlEquals, fieldValues: getFieldValues } = requireUtil$3(); - const { kEnumerableProperty, isDisturbed } = requireUtil$7(); - const { kHeadersList } = requireSymbols$4(); + const { urlEquals, getFieldValues } = requireUtil$4(); + const { kEnumerableProperty, isDisturbed } = requireUtil$8(); const { webidl } = requireWebidl(); - const { Response, cloneResponse } = requireResponse(); - const { Request } = requireRequest(); - const { kState, kHeaders, kGuard, kRealm } = requireSymbols$3(); + const { Response, cloneResponse, fromInnerResponse } = requireResponse(); + const { Request, fromInnerRequest } = requireRequest(); + const { kState } = requireSymbols$3(); const { fetching } = requireFetch(); - const { urlIsHttpHttpsScheme, createDeferredPromise, readAllBytes } = requireUtil$6(); + const { urlIsHttpHttpsScheme, createDeferredPromise, readAllBytes } = requireUtil$7(); const assert = require$$0$3; - const { getGlobalDispatcher } = requireGlobal(); /** * @see https://w3c.github.io/ServiceWorker/#dfn-cache-batch-operation @@ -20295,17 +22651,20 @@ function requireCache () { webidl.illegalConstructor(); } + webidl.util.markAsUncloneable(this); this.#relevantRequestResponseList = arguments[1]; } async match (request, options = {}) { webidl.brandCheck(this, Cache); - webidl.argumentLengthCheck(arguments, 1, { header: 'Cache.match' }); - request = webidl.converters.RequestInfo(request); - options = webidl.converters.CacheQueryOptions(options); + 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 = await this.matchAll(request, options); + const p = this.#internalMatchAll(request, options, 1); if (p.length === 0) { return @@ -20317,76 +22676,20 @@ function requireCache () { async matchAll (request = undefined, options = {}) { webidl.brandCheck(this, Cache); - if (request !== undefined) request = webidl.converters.RequestInfo(request); - options = webidl.converters.CacheQueryOptions(options); - - // 1. - let r = null; - - // 2. - if (request !== undefined) { - if (request instanceof Request) { - // 2.1.1 - r = request[kState]; - - // 2.1.2 - if (r.method !== 'GET' && !options.ignoreMethod) { - return [] - } - } else if (typeof request === 'string') { - // 2.2.1 - r = new Request(request)[kState]; - } - } - - // 5. - // 5.1 - const responses = []; - - // 5.2 - if (request === undefined) { - // 5.2.1 - for (const requestResponse of this.#relevantRequestResponseList) { - responses.push(requestResponse[1]); - } - } else { // 5.3 - // 5.3.1 - const requestResponses = this.#queryCache(r, options); - - // 5.3.2 - for (const requestResponse of requestResponses) { - responses.push(requestResponse[1]); - } - } - - // 5.4 - // We don't implement CORs so we don't need to loop over the responses, yay! - - // 5.5.1 - const responseList = []; - - // 5.5.2 - for (const response of responses) { - // 5.5.2.1 - const responseObject = new Response(response.body?.source ?? null); - const body = responseObject[kState].body; - responseObject[kState] = response; - responseObject[kState].body = body; - responseObject[kHeaders][kHeadersList] = response.headersList; - responseObject[kHeaders][kGuard] = 'immutable'; - - responseList.push(responseObject); - } + const prefix = 'Cache.matchAll'; + if (request !== undefined) request = webidl.converters.RequestInfo(request, prefix, 'request'); + options = webidl.converters.CacheQueryOptions(options, prefix, 'options'); - // 6. - return Object.freeze(responseList) + return this.#internalMatchAll(request, options) } async add (request) { webidl.brandCheck(this, Cache); - webidl.argumentLengthCheck(arguments, 1, { header: 'Cache.add' }); - request = webidl.converters.RequestInfo(request); + const prefix = 'Cache.add'; + webidl.argumentLengthCheck(arguments, 1, prefix); + + request = webidl.converters.RequestInfo(request, prefix, 'request'); // 1. const requests = [request]; @@ -20400,9 +22703,9 @@ function requireCache () { async addAll (requests) { webidl.brandCheck(this, Cache); - webidl.argumentLengthCheck(arguments, 1, { header: 'Cache.addAll' }); - requests = webidl.converters['sequence'](requests); + const prefix = 'Cache.addAll'; + webidl.argumentLengthCheck(arguments, 1, prefix); // 1. const responsePromises = []; @@ -20411,7 +22714,17 @@ function requireCache () { const requestList = []; // 3. - for (const request of requests) { + for (let request of requests) { + if (request === undefined) { + throw webidl.errors.conversionFailed({ + prefix, + argument: 'Argument 1', + types: ['undefined is not allowed'] + }) + } + + request = webidl.converters.RequestInfo(request); + if (typeof request === 'string') { continue } @@ -20422,7 +22735,7 @@ function requireCache () { // 3.2 if (!urlIsHttpHttpsScheme(r.url) || r.method !== 'GET') { throw webidl.errors.exception({ - header: 'Cache.addAll', + header: prefix, message: 'Expected http/s scheme when method is not GET.' }) } @@ -20440,7 +22753,7 @@ function requireCache () { // 5.2 if (!urlIsHttpHttpsScheme(r.url)) { throw webidl.errors.exception({ - header: 'Cache.addAll', + header: prefix, message: 'Expected http/s scheme.' }) } @@ -20458,7 +22771,6 @@ function requireCache () { // 5.7 fetchControllers.push(fetching({ request: r, - dispatcher: getGlobalDispatcher(), processResponse (response) { // 1. if (response.type === 'error' || response.status === 206 || response.status < 200 || response.status > 299) { @@ -20561,10 +22873,12 @@ function requireCache () { async put (request, response) { webidl.brandCheck(this, Cache); - webidl.argumentLengthCheck(arguments, 2, { header: 'Cache.put' }); - request = webidl.converters.RequestInfo(request); - response = webidl.converters.Response(response); + const prefix = 'Cache.put'; + webidl.argumentLengthCheck(arguments, 2, prefix); + + request = webidl.converters.RequestInfo(request, prefix, 'request'); + response = webidl.converters.Response(response, prefix, 'response'); // 1. let innerRequest = null; @@ -20579,7 +22893,7 @@ function requireCache () { // 4. if (!urlIsHttpHttpsScheme(innerRequest.url) || innerRequest.method !== 'GET') { throw webidl.errors.exception({ - header: 'Cache.put', + header: prefix, message: 'Expected an http/s scheme when method is not GET' }) } @@ -20590,7 +22904,7 @@ function requireCache () { // 6. if (innerResponse.status === 206) { throw webidl.errors.exception({ - header: 'Cache.put', + header: prefix, message: 'Got 206 status' }) } @@ -20605,7 +22919,7 @@ function requireCache () { // 7.2.1 if (fieldValue === '*') { throw webidl.errors.exception({ - header: 'Cache.put', + header: prefix, message: 'Got * vary field value' }) } @@ -20615,7 +22929,7 @@ function requireCache () { // 8. if (innerResponse.body && (isDisturbed(innerResponse.body.stream) || innerResponse.body.stream.locked)) { throw webidl.errors.exception({ - header: 'Cache.put', + header: prefix, message: 'Response body is locked or disturbed' }) } @@ -20690,10 +23004,12 @@ function requireCache () { async delete (request, options = {}) { webidl.brandCheck(this, Cache); - webidl.argumentLengthCheck(arguments, 1, { header: 'Cache.delete' }); - request = webidl.converters.RequestInfo(request); - options = webidl.converters.CacheQueryOptions(options); + const prefix = 'Cache.delete'; + webidl.argumentLengthCheck(arguments, 1, prefix); + + request = webidl.converters.RequestInfo(request, prefix, 'request'); + options = webidl.converters.CacheQueryOptions(options, prefix, 'options'); /** * @type {Request} @@ -20750,13 +23066,15 @@ function requireCache () { * @see https://w3c.github.io/ServiceWorker/#dom-cache-keys * @param {any} request * @param {import('../../types/cache').CacheQueryOptions} options - * @returns {readonly Request[]} + * @returns {Promise} */ async keys (request = undefined, options = {}) { webidl.brandCheck(this, Cache); - if (request !== undefined) request = webidl.converters.RequestInfo(request); - options = webidl.converters.CacheQueryOptions(options); + const prefix = 'Cache.keys'; + + if (request !== undefined) request = webidl.converters.RequestInfo(request, prefix, 'request'); + options = webidl.converters.CacheQueryOptions(options, prefix, 'options'); // 1. let r = null; @@ -20809,12 +23127,11 @@ function requireCache () { // 5.4.2 for (const request of requests) { - const requestObject = new Request('https://a'); - requestObject[kState] = request; - requestObject[kHeaders][kHeadersList] = request.headersList; - requestObject[kHeaders][kGuard] = 'immutable'; - requestObject[kRealm] = request.client; - + const requestObject = fromInnerRequest( + request, + new AbortController().signal, + 'immutable' + ); // 5.4.2.1 requestList.push(requestObject); } @@ -21039,6 +23356,68 @@ function requireCache () { return true } + + #internalMatchAll (request, options, maxResponses = Infinity) { + // 1. + let r = null; + + // 2. + if (request !== undefined) { + if (request instanceof Request) { + // 2.1.1 + r = request[kState]; + + // 2.1.2 + if (r.method !== 'GET' && !options.ignoreMethod) { + return [] + } + } else if (typeof request === 'string') { + // 2.2.1 + r = new Request(request)[kState]; + } + } + + // 5. + // 5.1 + const responses = []; + + // 5.2 + if (request === undefined) { + // 5.2.1 + for (const requestResponse of this.#relevantRequestResponseList) { + responses.push(requestResponse[1]); + } + } else { // 5.3 + // 5.3.1 + const requestResponses = this.#queryCache(r, options); + + // 5.3.2 + for (const requestResponse of requestResponses) { + responses.push(requestResponse[1]); + } + } + + // 5.4 + // We don't implement CORs so we don't need to loop over the responses, yay! + + // 5.5.1 + const responseList = []; + + // 5.5.2 + for (const response of responses) { + // 5.5.2.1 + const responseObject = fromInnerResponse(response, 'immutable'); + + responseList.push(responseObject.clone()); + + if (responseList.length >= maxResponses) { + break + } + } + + // 6. + return Object.freeze(responseList) + } } Object.defineProperties(Cache.prototype, { @@ -21059,17 +23438,17 @@ function requireCache () { { key: 'ignoreSearch', converter: webidl.converters.boolean, - defaultValue: false + defaultValue: () => false }, { key: 'ignoreMethod', converter: webidl.converters.boolean, - defaultValue: false + defaultValue: () => false }, { key: 'ignoreVary', converter: webidl.converters.boolean, - defaultValue: false + defaultValue: () => false } ]; @@ -21105,7 +23484,7 @@ function requireCachestorage () { const { kConstruct } = requireSymbols$1(); const { Cache } = requireCache(); const { webidl } = requireWebidl(); - const { kEnumerableProperty } = requireUtil$7(); + const { kEnumerableProperty } = requireUtil$8(); class CacheStorage { /** @@ -21118,11 +23497,13 @@ function requireCachestorage () { if (arguments[0] !== kConstruct) { webidl.illegalConstructor(); } + + webidl.util.markAsUncloneable(this); } async match (request, options = {}) { webidl.brandCheck(this, CacheStorage); - webidl.argumentLengthCheck(arguments, 1, { header: 'CacheStorage.match' }); + webidl.argumentLengthCheck(arguments, 1, 'CacheStorage.match'); request = webidl.converters.RequestInfo(request); options = webidl.converters.MultiCacheQueryOptions(options); @@ -21159,9 +23540,11 @@ function requireCachestorage () { */ async has (cacheName) { webidl.brandCheck(this, CacheStorage); - webidl.argumentLengthCheck(arguments, 1, { header: 'CacheStorage.has' }); - cacheName = webidl.converters.DOMString(cacheName); + const prefix = 'CacheStorage.has'; + webidl.argumentLengthCheck(arguments, 1, prefix); + + cacheName = webidl.converters.DOMString(cacheName, prefix, 'cacheName'); // 2.1.1 // 2.2 @@ -21175,9 +23558,11 @@ function requireCachestorage () { */ async open (cacheName) { webidl.brandCheck(this, CacheStorage); - webidl.argumentLengthCheck(arguments, 1, { header: 'CacheStorage.open' }); - cacheName = webidl.converters.DOMString(cacheName); + const prefix = 'CacheStorage.open'; + webidl.argumentLengthCheck(arguments, 1, prefix); + + cacheName = webidl.converters.DOMString(cacheName, prefix, 'cacheName'); // 2.1 if (this.#caches.has(cacheName)) { @@ -21207,16 +23592,18 @@ function requireCachestorage () { */ async delete (cacheName) { webidl.brandCheck(this, CacheStorage); - webidl.argumentLengthCheck(arguments, 1, { header: 'CacheStorage.delete' }); - cacheName = webidl.converters.DOMString(cacheName); + 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 {string[]} + * @returns {Promise} */ async keys () { webidl.brandCheck(this, CacheStorage); @@ -21267,33 +23654,30 @@ function requireConstants$1 () { return constants$1; } -var util$2; -var hasRequiredUtil$2; +var util$3; +var hasRequiredUtil$3; -function requireUtil$2 () { - if (hasRequiredUtil$2) return util$2; - hasRequiredUtil$2 = 1; +function requireUtil$3 () { + if (hasRequiredUtil$3) return util$3; + hasRequiredUtil$3 = 1; /** * @param {string} value * @returns {boolean} */ function isCTLExcludingHtab (value) { - if (value.length === 0) { - return false - } - - for (const char of value) { - const code = char.charCodeAt(0); + for (let i = 0; i < value.length; ++i) { + const code = value.charCodeAt(i); if ( - (code >= 0x00 || code <= 0x08) || - (code >= 0x0A || code <= 0x1F) || + (code >= 0x00 && code <= 0x08) || + (code >= 0x0A && code <= 0x1F) || code === 0x7F ) { - return false + return true } } + return false } /** @@ -21306,28 +23690,29 @@ function requireUtil$2 () { * @param {string} name */ function validateCookieName (name) { - for (const char of name) { - const code = char.charCodeAt(0); + for (let i = 0; i < name.length; ++i) { + const code = name.charCodeAt(i); if ( - (code <= 0x20 || code > 0x7F) || - char === '(' || - char === ')' || - char === '>' || - char === '<' || - char === '@' || - char === ',' || - char === ';' || - char === ':' || - char === '\\' || - char === '"' || - char === '/' || - char === '[' || - char === ']' || - char === '?' || - char === '=' || - char === '{' || - char === '}' + code < 0x21 || // exclude CTLs (0-31), SP and HT + code > 0x7E || // exclude non-ascii and DEL + code === 0x22 || // " + code === 0x28 || // ( + code === 0x29 || // ) + code === 0x3C || // < + code === 0x3E || // > + code === 0x40 || // @ + code === 0x2C || // , + code === 0x3B || // ; + code === 0x3A || // : + code === 0x5C || // \ + code === 0x2F || // / + code === 0x5B || // [ + code === 0x5D || // ] + code === 0x3F || // ? + code === 0x3D || // = + code === 0x7B || // { + code === 0x7D // } ) { throw new Error('Invalid cookie name') } @@ -21343,18 +23728,30 @@ function requireUtil$2 () { * @param {string} value */ function validateCookieValue (value) { - for (const char of value) { - const code = char.charCodeAt(0); + let len = value.length; + let i = 0; + + // if the value is wrapped in DQUOTE + 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 < 0x21 || // exclude CTLs (0-31) - code === 0x22 || - code === 0x2C || - code === 0x3B || - code === 0x5C || - code > 0x7E // non-ascii + code > 0x7E || // non-ascii and DEL (127) + code === 0x22 || // " + code === 0x2C || // , + code === 0x3B || // ; + code === 0x5C // \ ) { - throw new Error('Invalid header value') + throw new Error('Invalid cookie value') } } } @@ -21364,10 +23761,14 @@ function requireUtil$2 () { * @param {string} path */ function validateCookiePath (path) { - for (const char of path) { - const code = char.charCodeAt(0); + for (let i = 0; i < path.length; ++i) { + const code = path.charCodeAt(i); - if (code < 0x21 || char === ';') { + if ( + code < 0x20 || // exclude CTLs (0-31) + code === 0x7F || // DEL + code === 0x3B // ; + ) { throw new Error('Invalid cookie path') } } @@ -21388,6 +23789,18 @@ function requireUtil$2 () { } } + const IMFDays = [ + 'Sun', 'Mon', 'Tue', 'Wed', + 'Thu', 'Fri', 'Sat' + ]; + + const IMFMonths = [ + 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', + 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec' + ]; + + const IMFPaddedNumbers = Array(61).fill(0).map((_, i) => i.toString().padStart(2, '0')); + /** * @see https://www.rfc-editor.org/rfc/rfc7231#section-7.1.1.1 * @param {number|Date} date @@ -21434,25 +23847,7 @@ function requireUtil$2 () { date = new Date(date); } - const days = [ - 'Sun', 'Mon', 'Tue', 'Wed', - 'Thu', 'Fri', 'Sat' - ]; - - const months = [ - 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', - 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec' - ]; - - const dayName = days[date.getUTCDay()]; - const day = date.getUTCDate().toString().padStart(2, '0'); - const month = months[date.getUTCMonth()]; - const year = date.getUTCFullYear(); - const hour = date.getUTCHours().toString().padStart(2, '0'); - const minute = date.getUTCMinutes().toString().padStart(2, '0'); - const second = date.getUTCSeconds().toString().padStart(2, '0'); - - return `${dayName}, ${day} ${month} ${year} ${hour}:${minute}:${second} GMT` + return `${IMFDays[date.getUTCDay()]}, ${IMFPaddedNumbers[date.getUTCDate()]} ${IMFMonths[date.getUTCMonth()]} ${date.getUTCFullYear()} ${IMFPaddedNumbers[date.getUTCHours()]}:${IMFPaddedNumbers[date.getUTCMinutes()]}:${IMFPaddedNumbers[date.getUTCSeconds()]} GMT` } /** @@ -21538,7 +23933,7 @@ function requireUtil$2 () { return out.join('; ') } - util$2 = { + util$3 = { isCTLExcludingHtab, validateCookieName, validateCookiePath, @@ -21546,19 +23941,19 @@ function requireUtil$2 () { toIMFDate, stringify }; - return util$2; + return util$3; } -var parse$3; +var parse$2; var hasRequiredParse; function requireParse () { - if (hasRequiredParse) return parse$3; + if (hasRequiredParse) return parse$2; hasRequiredParse = 1; const { maxNameValuePairSize, maxAttributeValueSize } = requireConstants$1(); - const { isCTLExcludingHtab } = requireUtil$2(); - const { collectASequenceOfCodePointsFast } = requireDataURL(); + const { isCTLExcludingHtab } = requireUtil$3(); + const { collectASequenceOfCodePointsFast } = requireDataUrl(); const assert = require$$0$3; /** @@ -21867,11 +24262,11 @@ function requireParse () { return parseUnparsedAttributes(unparsedAttributes, cookieAttributeList) } - parse$3 = { + parse$2 = { parseSetCookie, parseUnparsedAttributes }; - return parse$3; + return parse$2; } var cookies; @@ -21882,7 +24277,7 @@ function requireCookies () { hasRequiredCookies = 1; const { parseSetCookie } = requireParse(); - const { stringify } = requireUtil$2(); + const { stringify } = requireUtil$3(); const { webidl } = requireWebidl(); const { Headers } = requireHeaders(); @@ -21905,7 +24300,7 @@ function requireCookies () { * @returns {Record} */ function getCookies (headers) { - webidl.argumentLengthCheck(arguments, 1, { header: 'getCookies' }); + webidl.argumentLengthCheck(arguments, 1, 'getCookies'); webidl.brandCheck(headers, Headers, { strict: false }); @@ -21932,11 +24327,12 @@ function requireCookies () { * @returns {void} */ function deleteCookie (headers, name, attributes) { - webidl.argumentLengthCheck(arguments, 2, { header: 'deleteCookie' }); - webidl.brandCheck(headers, Headers, { strict: false }); - name = webidl.converters.DOMString(name); + const prefix = 'deleteCookie'; + webidl.argumentLengthCheck(arguments, 2, prefix); + + name = webidl.converters.DOMString(name, prefix, 'name'); attributes = webidl.converters.DeleteCookieAttributes(attributes); // Matches behavior of @@ -21954,7 +24350,7 @@ function requireCookies () { * @returns {Cookie[]} */ function getSetCookies (headers) { - webidl.argumentLengthCheck(arguments, 1, { header: 'getSetCookies' }); + webidl.argumentLengthCheck(arguments, 1, 'getSetCookies'); webidl.brandCheck(headers, Headers, { strict: false }); @@ -21973,7 +24369,7 @@ function requireCookies () { * @returns {void} */ function setCookie (headers, cookie) { - webidl.argumentLengthCheck(arguments, 2, { header: 'setCookie' }); + webidl.argumentLengthCheck(arguments, 2, 'setCookie'); webidl.brandCheck(headers, Headers, { strict: false }); @@ -21982,7 +24378,7 @@ function requireCookies () { const str = stringify(cookie); if (str) { - headers.append('Set-Cookie', stringify(cookie)); + headers.append('Set-Cookie', str); } } @@ -21990,12 +24386,12 @@ function requireCookies () { { converter: webidl.nullableConverter(webidl.converters.DOMString), key: 'path', - defaultValue: null + defaultValue: () => null }, { converter: webidl.nullableConverter(webidl.converters.DOMString), key: 'domain', - defaultValue: null + defaultValue: () => null } ]); @@ -22017,32 +24413,32 @@ function requireCookies () { return new Date(value) }), key: 'expires', - defaultValue: null + defaultValue: () => null }, { converter: webidl.nullableConverter(webidl.converters['long long']), key: 'maxAge', - defaultValue: null + defaultValue: () => null }, { converter: webidl.nullableConverter(webidl.converters.DOMString), key: 'domain', - defaultValue: null + defaultValue: () => null }, { converter: webidl.nullableConverter(webidl.converters.DOMString), key: 'path', - defaultValue: null + defaultValue: () => null }, { converter: webidl.nullableConverter(webidl.converters.boolean), key: 'secure', - defaultValue: null + defaultValue: () => null }, { converter: webidl.nullableConverter(webidl.converters.boolean), key: 'httpOnly', - defaultValue: null + defaultValue: () => null }, { converter: webidl.converters.USVString, @@ -22052,7 +24448,7 @@ function requireCookies () { { converter: webidl.sequenceConverter(webidl.converters.DOMString), key: 'unparsed', - defaultValue: [] + defaultValue: () => new Array(0) } ]); @@ -22065,85 +24461,6 @@ function requireCookies () { return cookies; } -var constants; -var hasRequiredConstants; - -function requireConstants () { - if (hasRequiredConstants) return constants; - hasRequiredConstants = 1; - - // This is a Globally Unique Identifier unique used - // to validate that the endpoint accepts websocket - // connections. - // See https://www.rfc-editor.org/rfc/rfc6455.html#section-1.3 - const uid = '258EAFA5-E914-47DA-95CA-C5AB0DC85B11'; - - /** @type {PropertyDescriptor} */ - const staticPropertyDescriptors = { - enumerable: true, - writable: false, - configurable: false - }; - - const states = { - CONNECTING: 0, - OPEN: 1, - CLOSING: 2, - CLOSED: 3 - }; - - const opcodes = { - CONTINUATION: 0x0, - TEXT: 0x1, - BINARY: 0x2, - CLOSE: 0x8, - PING: 0x9, - PONG: 0xA - }; - - const maxUnsigned16Bit = 2 ** 16 - 1; // 65535 - - const parserStates = { - INFO: 0, - PAYLOADLENGTH_16: 2, - PAYLOADLENGTH_64: 3, - READ_DATA: 4 - }; - - const emptyBuffer = Buffer.allocUnsafe(0); - - constants = { - uid, - staticPropertyDescriptors, - states, - opcodes, - maxUnsigned16Bit, - parserStates, - emptyBuffer - }; - return constants; -} - -var symbols; -var hasRequiredSymbols; - -function requireSymbols () { - if (hasRequiredSymbols) return symbols; - hasRequiredSymbols = 1; - - symbols = { - kWebSocketURL: Symbol('url'), - kReadyState: Symbol('ready state'), - kController: Symbol('controller'), - kResponse: Symbol('response'), - kBinaryType: Symbol('binary type'), - kSentClose: Symbol('sent close'), - kReceivedClose: Symbol('received close'), - kByteParser: Symbol('byte parser') - }; - return symbols; -} - var events; var hasRequiredEvents; @@ -22152,8 +24469,9 @@ function requireEvents () { hasRequiredEvents = 1; const { webidl } = requireWebidl(); - const { kEnumerableProperty } = requireUtil$7(); - const { MessagePort } = require$$0$8; + const { kEnumerableProperty } = requireUtil$8(); + const { kConstruct } = requireSymbols$4(); + const { MessagePort } = require$$1$1; /** * @see https://html.spec.whatwg.org/multipage/comms.html#messageevent @@ -22162,14 +24480,22 @@ function requireEvents () { #eventInit constructor (type, eventInitDict = {}) { - webidl.argumentLengthCheck(arguments, 1, { header: 'MessageEvent constructor' }); + if (type === kConstruct) { + super(arguments[1], arguments[2]); + webidl.util.markAsUncloneable(this); + return + } - type = webidl.converters.DOMString(type); - eventInitDict = webidl.converters.MessageEventInit(eventInitDict); + 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 () { @@ -22218,14 +24544,28 @@ function requireEvents () { ) { webidl.brandCheck(this, MessageEvent); - webidl.argumentLengthCheck(arguments, 1, { header: 'MessageEvent.initMessageEvent' }); + 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 + } } + const { createFastMessageEvent } = MessageEvent; + delete MessageEvent.createFastMessageEvent; + /** * @see https://websockets.spec.whatwg.org/#the-closeevent-interface */ @@ -22233,14 +24573,16 @@ function requireEvents () { #eventInit constructor (type, eventInitDict = {}) { - webidl.argumentLengthCheck(arguments, 1, { header: 'CloseEvent constructor' }); + const prefix = 'CloseEvent constructor'; + webidl.argumentLengthCheck(arguments, 1, prefix); - type = webidl.converters.DOMString(type); + type = webidl.converters.DOMString(type, prefix, 'type'); eventInitDict = webidl.converters.CloseEventInit(eventInitDict); super(type, eventInitDict); this.#eventInit = eventInitDict; + webidl.util.markAsUncloneable(this); } get wasClean () { @@ -22267,11 +24609,13 @@ function requireEvents () { #eventInit constructor (type, eventInitDict) { - webidl.argumentLengthCheck(arguments, 1, { header: 'ErrorEvent constructor' }); + const prefix = 'ErrorEvent constructor'; + webidl.argumentLengthCheck(arguments, 1, prefix); super(type, eventInitDict); + webidl.util.markAsUncloneable(this); - type = webidl.converters.DOMString(type); + type = webidl.converters.DOMString(type, prefix, 'type'); eventInitDict = webidl.converters.ErrorEventInit(eventInitDict ?? {}); this.#eventInit = eventInitDict; @@ -22353,17 +24697,17 @@ function requireEvents () { { key: 'bubbles', converter: webidl.converters.boolean, - defaultValue: false + defaultValue: () => false }, { key: 'cancelable', converter: webidl.converters.boolean, - defaultValue: false + defaultValue: () => false }, { key: 'composed', converter: webidl.converters.boolean, - defaultValue: false + defaultValue: () => false } ]; @@ -22372,31 +24716,29 @@ function requireEvents () { { key: 'data', converter: webidl.converters.any, - defaultValue: null + defaultValue: () => null }, { key: 'origin', converter: webidl.converters.USVString, - defaultValue: '' + defaultValue: () => '' }, { key: 'lastEventId', converter: webidl.converters.DOMString, - defaultValue: '' + 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 + defaultValue: () => null }, { key: 'ports', converter: webidl.converters['sequence'], - get defaultValue () { - return [] - } + defaultValue: () => new Array(0) } ]); @@ -22405,17 +24747,17 @@ function requireEvents () { { key: 'wasClean', converter: webidl.converters.boolean, - defaultValue: false + defaultValue: () => false }, { key: 'code', converter: webidl.converters['unsigned short'], - defaultValue: 0 + defaultValue: () => 0 }, { key: 'reason', converter: webidl.converters.USVString, - defaultValue: '' + defaultValue: () => '' } ]); @@ -22424,22 +24766,22 @@ function requireEvents () { { key: 'message', converter: webidl.converters.DOMString, - defaultValue: '' + defaultValue: () => '' }, { key: 'filename', converter: webidl.converters.USVString, - defaultValue: '' + defaultValue: () => '' }, { key: 'lineno', converter: webidl.converters['unsigned long'], - defaultValue: 0 + defaultValue: () => 0 }, { key: 'colno', converter: webidl.converters['unsigned long'], - defaultValue: 0 + defaultValue: () => 0 }, { key: 'error', @@ -22450,26 +24792,134 @@ function requireEvents () { events = { MessageEvent, CloseEvent, - ErrorEvent + ErrorEvent, + createFastMessageEvent }; return events; } -var util$1; -var hasRequiredUtil$1; +var constants; +var hasRequiredConstants; -function requireUtil$1 () { - if (hasRequiredUtil$1) return util$1; - hasRequiredUtil$1 = 1; +function requireConstants () { + if (hasRequiredConstants) return constants; + hasRequiredConstants = 1; + + // This is a Globally Unique Identifier unique used + // to validate that the endpoint accepts websocket + // connections. + // See https://www.rfc-editor.org/rfc/rfc6455.html#section-1.3 + const uid = '258EAFA5-E914-47DA-95CA-C5AB0DC85B11'; + + /** @type {PropertyDescriptor} */ + const staticPropertyDescriptors = { + enumerable: true, + writable: false, + configurable: false + }; + + const states = { + CONNECTING: 0, + OPEN: 1, + CLOSING: 2, + CLOSED: 3 + }; + + const sentCloseFrameState = { + NOT_SENT: 0, + PROCESSING: 1, + SENT: 2 + }; + + const opcodes = { + CONTINUATION: 0x0, + TEXT: 0x1, + BINARY: 0x2, + CLOSE: 0x8, + PING: 0x9, + PONG: 0xA + }; + + const maxUnsigned16Bit = 2 ** 16 - 1; // 65535 + + const parserStates = { + INFO: 0, + PAYLOADLENGTH_16: 2, + PAYLOADLENGTH_64: 3, + READ_DATA: 4 + }; + + const emptyBuffer = Buffer.allocUnsafe(0); + + const sendHints = { + string: 1, + typedArray: 2, + arrayBuffer: 3, + blob: 4 + }; + + constants = { + uid, + sentCloseFrameState, + staticPropertyDescriptors, + states, + opcodes, + maxUnsigned16Bit, + parserStates, + emptyBuffer, + sendHints + }; + return constants; +} + +var symbols; +var hasRequiredSymbols; + +function requireSymbols () { + if (hasRequiredSymbols) return symbols; + hasRequiredSymbols = 1; + + symbols = { + kWebSocketURL: Symbol('url'), + kReadyState: Symbol('ready state'), + kController: Symbol('controller'), + kResponse: Symbol('response'), + kBinaryType: Symbol('binary type'), + kSentClose: Symbol('sent close'), + kReceivedClose: Symbol('received close'), + kByteParser: Symbol('byte parser') + }; + return symbols; +} + +var util$2; +var hasRequiredUtil$2; + +function requireUtil$2 () { + if (hasRequiredUtil$2) return util$2; + hasRequiredUtil$2 = 1; const { kReadyState, kController, kResponse, kBinaryType, kWebSocketURL } = requireSymbols(); const { states, opcodes } = requireConstants(); - const { MessageEvent, ErrorEvent } = requireEvents(); + const { ErrorEvent, createFastMessageEvent } = requireEvents(); + const { isUtf8 } = require$$0$2; + const { collectASequenceOfCodePointsFast, removeHTTPWhitespace } = requireDataUrl(); /* globals Blob */ /** * @param {import('./websocket').WebSocket} ws + * @returns {boolean} + */ + function isConnecting (ws) { + // If the WebSocket connection is not yet established, and the connection + // is not yet closed, then the WebSocket connection is in the CONNECTING state. + return ws[kReadyState] === states.CONNECTING + } + + /** + * @param {import('./websocket').WebSocket} ws + * @returns {boolean} */ function isEstablished (ws) { // If the server's response is validated as provided for above, it is @@ -22480,6 +24930,7 @@ function requireUtil$1 () { /** * @param {import('./websocket').WebSocket} ws + * @returns {boolean} */ function isClosing (ws) { // Upon either sending or receiving a Close control frame, it is said @@ -22490,6 +24941,7 @@ function requireUtil$1 () { /** * @param {import('./websocket').WebSocket} ws + * @returns {boolean} */ function isClosed (ws) { return ws[kReadyState] === states.CLOSED @@ -22499,15 +24951,16 @@ function requireUtil$1 () { * @see https://dom.spec.whatwg.org/#concept-event-fire * @param {string} e * @param {EventTarget} target + * @param {(...args: ConstructorParameters) => Event} eventFactory * @param {EventInit | undefined} eventInitDict */ - function fireEvent (e, target, eventConstructor = Event, eventInitDict) { + function fireEvent (e, target, eventFactory = (type, init) => new Event(type, init), eventInitDict = {}) { // 1. If eventConstructor is not given, then let eventConstructor be Event. // 2. Let event be the result of creating an event given eventConstructor, // in the relevant realm of target. // 3. Initialize event’s type attribute to e. - const event = new eventConstructor(e, eventInitDict); // eslint-disable-line new-cap + const event = eventFactory(e, eventInitDict); // 4. Initialize any other IDL attributes of event as described in the // invocation of this algorithm. @@ -22536,7 +24989,7 @@ function requireUtil$1 () { // -> type indicates that the data is Text // a new DOMString containing data try { - dataForEvent = new TextDecoder('utf-8', { fatal: true }).decode(data); + dataForEvent = utf8Decode(data); } catch { failWebsocketConnection(ws, 'Received invalid UTF-8 in text frame.'); return @@ -22551,19 +25004,26 @@ function requireUtil$1 () { // -> type indicates that the data is Binary and binary type is "arraybuffer" // a new ArrayBuffer object, created in the relevant Realm of the // WebSocket object, whose contents are data - dataForEvent = new Uint8Array(data).buffer; + dataForEvent = toArrayBuffer(data); } } // 3. Fire an event named message at the WebSocket object, using MessageEvent, // with the origin attribute initialized to the serialization of the WebSocket // object’s url's origin, and the data attribute initialized to dataForEvent. - fireEvent('message', ws, MessageEvent, { + 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) + } + /** * @see https://datatracker.ietf.org/doc/html/rfc6455 * @see https://datatracker.ietf.org/doc/html/rfc2616 @@ -22581,31 +25041,29 @@ function requireUtil$1 () { return false } - for (const char of protocol) { - const code = char.charCodeAt(0); + for (let i = 0; i < protocol.length; ++i) { + const code = protocol.charCodeAt(i); if ( - code < 0x21 || + code < 0x21 || // CTL, contains SP (0x20) and HT (0x09) code > 0x7E || - char === '(' || - char === ')' || - char === '<' || - char === '>' || - char === '@' || - char === ',' || - char === ';' || - char === ':' || - char === '\\' || - char === '"' || - char === '/' || - char === '[' || - char === ']' || - char === '?' || - char === '=' || - char === '{' || - char === '}' || - code === 32 || // SP - code === 9 // HT + code === 0x22 || // " + code === 0x28 || // ( + code === 0x29 || // ) + code === 0x2C || // , + code === 0x2F || // / + code === 0x3A || // : + code === 0x3B || // ; + code === 0x3C || // < + code === 0x3D || // = + code === 0x3E || // > + code === 0x3F || // ? + code === 0x40 || // @ + code === 0x5B || // [ + code === 0x5C || // \ + code === 0x5D || // ] + code === 0x7B || // { + code === 0x7D // } ) { return false } @@ -22644,13 +25102,107 @@ function requireUtil$1 () { } if (reason) { - fireEvent('error', ws, ErrorEvent, { - error: new Error(reason) + // TODO: process.nextTick + fireEvent('error', ws, (type, init) => new ErrorEvent(type, init), { + error: new Error(reason), + message: reason }); } } - util$1 = { + /** + * @see https://datatracker.ietf.org/doc/html/rfc6455#section-5.5 + * @param {number} opcode + */ + 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) + } + + /** + * Parses a Sec-WebSocket-Extensions header value. + * @param {string} extensions + * @returns {Map} + */ + // TODO(@Uzlopak, @KhafraDev): make compliant https://datatracker.ietf.org/doc/html/rfc6455#section-9.1 + function parseExtensions (extensions) { + const position = { position: 0 }; + const extensionList = 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 + } + + /** + * @see https://www.rfc-editor.org/rfc/rfc7692#section-7.1.2.2 + * @description "client-max-window-bits = 1*DIGIT" + * @param {string} value + */ + function isValidClientWindowBits (value) { + // Must have at least one character + if (value.length === 0) { + return false + } + + // Check all characters are ASCII digits + for (let i = 0; i < value.length; i++) { + const byte = value.charCodeAt(i); + + if (byte < 0x30 || byte > 0x39) { + return false + } + } + + // Check numeric range: zlib requires windowBits in range 8-15 + const num = Number.parseInt(value, 10); + return num >= 8 && num <= 15 + } + + // https://nodejs.org/api/intl.html#detecting-internationalization-support + const hasIntl = typeof process.versions.icu === 'string'; + const fatalDecoder = hasIntl ? new TextDecoder('utf-8', { fatal: true }) : undefined; + + /** + * Converts a Buffer to utf-8, even on platforms without icu. + * @param {Buffer} buffer + */ + const utf8Decode = hasIntl + ? fatalDecoder.decode.bind(fatalDecoder) + : function (buffer) { + if (isUtf8(buffer)) { + return buffer.toString('utf-8') + } + throw new TypeError('Invalid utf-8 received.') + }; + + util$2 = { + isConnecting, isEstablished, isClosing, isClosed, @@ -22658,9 +25210,120 @@ function requireUtil$1 () { isValidSubprotocol, isValidStatusCode, failWebsocketConnection, - websocketMessageReceived + websocketMessageReceived, + utf8Decode, + isControlFrame, + isContinuationFrame, + isTextBinaryFrame, + isValidOpcode, + parseExtensions, + isValidClientWindowBits }; - return util$1; + return util$2; +} + +var frame; +var hasRequiredFrame; + +function requireFrame () { + if (hasRequiredFrame) return frame; + hasRequiredFrame = 1; + + const { maxUnsigned16Bit } = requireConstants(); + + const BUFFER_SIZE = 16386; + + /** @type {import('crypto')} */ + let crypto; + let buffer = null; + let bufIdx = BUFFER_SIZE; + + try { + crypto = require('node:crypto'); + /* c8 ignore next 3 */ + } catch { + crypto = { + // not full compatibility, but minimum. + randomFillSync: function randomFillSync (buffer, _offset, _size) { + for (let i = 0; i < buffer.length; ++i) { + buffer[i] = Math.random() * 255 | 0; + } + return buffer + } + }; + } + + function generateMask () { + if (bufIdx === BUFFER_SIZE) { + bufIdx = 0; + crypto.randomFillSync((buffer ??= Buffer.allocUnsafe(BUFFER_SIZE)), 0, BUFFER_SIZE); + } + return [buffer[bufIdx++], buffer[bufIdx++], buffer[bufIdx++], buffer[bufIdx++]] + } + + class WebsocketFrameSend { + /** + * @param {Buffer|undefined} data + */ + constructor (data) { + this.frameData = data; + } + + createFrame (opcode) { + const frameData = this.frameData; + const maskKey = generateMask(); + const bodyLength = frameData?.byteLength ?? 0; + + /** @type {number} */ + let payloadLength = bodyLength; // 0-125 + let offset = 6; + + if (bodyLength > maxUnsigned16Bit) { + offset += 8; // payload length is next 8 bytes + payloadLength = 127; + } else if (bodyLength > 125) { + offset += 2; // payload length is next 2 bytes + payloadLength = 126; + } + + const buffer = Buffer.allocUnsafe(bodyLength + offset); + + // Clear first 2 bytes, everything else is overwritten + buffer[0] = buffer[1] = 0; + buffer[0] |= 0x80; // FIN + buffer[0] = (buffer[0] & 0xF0) + opcode; // opcode + + /*! ws. MIT License. Einar Otto Stangvik */ + buffer[offset - 4] = maskKey[0]; + buffer[offset - 3] = maskKey[1]; + buffer[offset - 2] = maskKey[2]; + buffer[offset - 1] = maskKey[3]; + + buffer[1] = payloadLength; + + if (payloadLength === 126) { + buffer.writeUInt16BE(bodyLength, 2); + } else if (payloadLength === 127) { + // Clear extended payload length + buffer[2] = buffer[3] = 0; + buffer.writeUIntBE(bodyLength, 4, 6); + } + + buffer[1] |= 0x80; // MASK + + // mask body + for (let i = 0; i < bodyLength; ++i) { + buffer[offset + i] = frameData[i] ^ maskKey[i & 3]; + } + + return buffer + } + } + + frame = { + WebsocketFrameSend + }; + return frame; } var connection; @@ -22670,31 +25333,28 @@ function requireConnection () { if (hasRequiredConnection) return connection; hasRequiredConnection = 1; - const diagnosticsChannel = require$$0$9; - const { uid, states } = requireConstants(); + const { uid, states, sentCloseFrameState, emptyBuffer, opcodes } = requireConstants(); const { kReadyState, kSentClose, kByteParser, - kReceivedClose + kReceivedClose, + kResponse } = requireSymbols(); - const { fireEvent, failWebsocketConnection } = requireUtil$1(); + const { fireEvent, failWebsocketConnection, isClosing, isClosed, isEstablished, parseExtensions } = requireUtil$2(); + const { channels } = requireDiagnostics(); const { CloseEvent } = requireEvents(); const { makeRequest } = requireRequest(); const { fetching } = requireFetch(); - const { Headers } = requireHeaders(); - const { getGlobalDispatcher } = requireGlobal(); - const { kHeadersList } = requireSymbols$4(); - - const channels = {}; - channels.open = diagnosticsChannel.channel('undici:websocket:open'); - channels.close = diagnosticsChannel.channel('undici:websocket:close'); - channels.socketError = diagnosticsChannel.channel('undici:websocket:socket_error'); + const { Headers, getHeadersList } = requireHeaders(); + const { getDecodeSplit } = requireUtil$7(); + const { WebsocketFrameSend } = requireFrame(); /** @type {import('crypto')} */ let crypto; try { - crypto = require('crypto'); + crypto = require('node:crypto'); + /* c8 ignore next 3 */ } catch { } @@ -22704,10 +25364,10 @@ function requireConnection () { * @param {URL} url * @param {string|string[]} protocols * @param {import('./websocket').WebSocket} ws - * @param {(response: any) => void} onEstablish + * @param {(response: any, extensions: string[] | undefined) => void} onEstablish * @param {Partial} options */ - function establishWebSocketConnection (url, protocols, ws, onEstablish, options) { + function establishWebSocketConnection (url, protocols, client, ws, onEstablish, options) { // 1. Let requestURL be a copy of url, with its scheme set to "http", if url’s // scheme is "ws", and to "https" otherwise. const requestURL = url; @@ -22720,6 +25380,7 @@ function requireConnection () { // and redirect mode is "error". const request = makeRequest({ urlList: [requestURL], + client, serviceWorkers: 'none', referrer: 'no-referrer', mode: 'websocket', @@ -22730,7 +25391,7 @@ function requireConnection () { // Note: undici extension, allow setting custom headers. if (options.headers) { - const headersList = new Headers(options.headers)[kHeadersList]; + const headersList = getHeadersList(new Headers(options.headers)); request.headersList = headersList; } @@ -22763,19 +25424,18 @@ function requireConnection () { // 9. Let permessageDeflate be a user-agent defined // "permessage-deflate" extension header value. // https://github.com/mozilla/gecko-dev/blob/ce78234f5e653a5d3916813ff990f053510227bc/netwerk/protocol/websocket/WebSocketChannel.cpp#L2673 - // TODO: enable once permessage-deflate is supported - const permessageDeflate = ''; // 'permessage-deflate; 15' + const permessageDeflate = 'permessage-deflate; client_max_window_bits'; // 10. Append (`Sec-WebSocket-Extensions`, permessageDeflate) to // request’s header list. - // request.headersList.append('sec-websocket-extensions', permessageDeflate) + request.headersList.append('sec-websocket-extensions', permessageDeflate); // 11. Fetch request with useParallelQueue set to true, and // processResponse given response being these steps: const controller = fetching({ request, useParallelQueue: true, - dispatcher: options.dispatcher ?? getGlobalDispatcher(), + dispatcher: options.dispatcher, processResponse (response) { // 1. If response is a network error or its status is not 101, // fail the WebSocket connection. @@ -22839,10 +25499,15 @@ function requireConnection () { // header field to determine which extensions are requested is // discussed in Section 9.1.) const secExtension = response.headersList.get('Sec-WebSocket-Extensions'); + let extensions; - if (secExtension !== null && secExtension !== permessageDeflate) { - failWebsocketConnection(ws, 'Received different permessage-deflate than the one set.'); - return + if (secExtension !== null) { + extensions = parseExtensions(secExtension); + + if (!extensions.has('permessage-deflate')) { + failWebsocketConnection(ws, 'Sec-WebSocket-Extensions header does not match.'); + return + } } // 6. If the response includes a |Sec-WebSocket-Protocol| header field @@ -22852,9 +25517,18 @@ function requireConnection () { // the WebSocket Connection_. const secProtocol = response.headersList.get('Sec-WebSocket-Protocol'); - if (secProtocol !== null && secProtocol !== request.headersList.get('Sec-WebSocket-Protocol')) { - failWebsocketConnection(ws, 'Protocol was not set in the opening handshake.'); - return + if (secProtocol !== null) { + const requestProtocols = getDecodeSplit('sec-websocket-protocol', request.headersList); + + // The client can request that the server use a specific subprotocol by + // including the |Sec-WebSocket-Protocol| field in its handshake. If it + // is specified, the server needs to include the same field and one of + // the selected subprotocol values in its response for the connection to + // be established. + if (!requestProtocols.includes(secProtocol)) { + failWebsocketConnection(ws, 'Protocol was not set in the opening handshake.'); + return + } } response.socket.on('data', onSocketData); @@ -22869,13 +25543,72 @@ function requireConnection () { }); } - onEstablish(response); + onEstablish(response, extensions); } }); return controller } + function closeWebSocketConnection (ws, code, reason, reasonByteLength) { + if (isClosing(ws) || isClosed(ws)) ; else if (!isEstablished(ws)) { + // If the WebSocket connection is not yet established + // Fail the WebSocket connection and set this's ready state + // to CLOSING (2). + failWebsocketConnection(ws, 'Connection was closed before it was established.'); + ws[kReadyState] = states.CLOSING; + } else if (ws[kSentClose] === sentCloseFrameState.NOT_SENT) { + // If the WebSocket closing handshake has not yet been started + // Start the WebSocket closing handshake and set this's ready + // state to CLOSING (2). + // - If neither code nor reason is present, the WebSocket Close + // message must not have a body. + // - If code is present, then the status code to use in the + // WebSocket Close message must be the integer given by code. + // - If reason is also present, then reasonBytes must be + // provided in the Close message after the status code. + + ws[kSentClose] = sentCloseFrameState.PROCESSING; + + const frame = new WebsocketFrameSend(); + + // If neither code nor reason is present, the WebSocket Close + // message must not have a body. + + // If code is present, then the status code to use in the + // WebSocket Close message must be the integer given by code. + if (code !== undefined && reason === undefined) { + frame.frameData = Buffer.allocUnsafe(2); + frame.frameData.writeUInt16BE(code, 0); + } else if (code !== undefined && reason !== undefined) { + // If reason is also present, then reasonBytes must be + // provided in the Close message after the status code. + frame.frameData = Buffer.allocUnsafe(2 + reasonByteLength); + frame.frameData.writeUInt16BE(code, 0); + // the body MAY contain UTF-8-encoded data with value /reason/ + frame.frameData.write(reason, 2, 'utf-8'); + } else { + frame.frameData = emptyBuffer; + } + + /** @type {import('stream').Duplex} */ + const socket = ws[kResponse].socket; + + socket.write(frame.createFrame(opcodes.CLOSE)); + + ws[kSentClose] = sentCloseFrameState.SENT; + + // Upon either sending or receiving a Close control frame, it is said + // that _The WebSocket Closing Handshake is Started_ and that the + // WebSocket connection is in the CLOSING state. + ws[kReadyState] = states.CLOSING; + } else { + // Otherwise + // Set this's ready state to CLOSING (2). + ws[kReadyState] = states.CLOSING; + } + } + /** * @param {Buffer} chunk */ @@ -22891,21 +25624,26 @@ function requireConnection () { */ function onSocketClose () { const { ws } = this; + const { [kResponse]: response } = ws; + + response.socket.off('data', onSocketData); + response.socket.off('close', onSocketClose); + response.socket.off('error', onSocketError); // If the TCP connection was closed after the // WebSocket closing handshake was completed, the WebSocket connection // is said to have been closed _cleanly_. - const wasClean = ws[kSentClose] && ws[kReceivedClose]; + const wasClean = ws[kSentClose] === sentCloseFrameState.SENT && ws[kReceivedClose]; let code = 1005; let reason = ''; const result = ws[kByteParser].closingInfo; - if (result) { + if (result && !result.error) { code = result.code ?? 1005; reason = result.reason; - } else if (!ws[kSentClose]) { + } else if (!ws[kReceivedClose]) { // If _The WebSocket // Connection is Closed_ and no Close control frame was received by the // endpoint (such as could occur if the underlying transport connection @@ -22931,7 +25669,8 @@ function requireConnection () { // attribute initialized to the result of applying UTF-8 // decode without BOM to the WebSocket connection close // reason. - fireEvent('close', ws, CloseEvent, { + // TODO: process.nextTick + fireEvent('close', ws, (type, init) => new CloseEvent(type, init), { wasClean, code, reason }); @@ -22957,90 +25696,136 @@ function requireConnection () { } connection = { - establishWebSocketConnection + establishWebSocketConnection, + closeWebSocketConnection }; return connection; } -var frame; -var hasRequiredFrame; +var permessageDeflate; +var hasRequiredPermessageDeflate; -function requireFrame () { - if (hasRequiredFrame) return frame; - hasRequiredFrame = 1; +function requirePermessageDeflate () { + if (hasRequiredPermessageDeflate) return permessageDeflate; + hasRequiredPermessageDeflate = 1; - const { maxUnsigned16Bit } = requireConstants(); + const { createInflateRaw, Z_DEFAULT_WINDOWBITS } = require$$1$2; + const { isValidClientWindowBits } = requireUtil$2(); + const { MessageSizeExceededError } = requireErrors(); - /** @type {import('crypto')} */ - let crypto; - try { - crypto = require('crypto'); - } catch { + const tail = Buffer.from([0x00, 0x00, 0xff, 0xff]); + const kBuffer = Symbol('kBuffer'); + const kLength = Symbol('kLength'); - } + // Default maximum decompressed message size: 4 MB + const kDefaultMaxDecompressedSize = 4 * 1024 * 1024; + + class PerMessageDeflate { + /** @type {import('node:zlib').InflateRaw} */ + #inflate + + #options = {} + + /** @type {boolean} */ + #aborted = false + + /** @type {Function|null} */ + #currentCallback = null - class WebsocketFrameSend { /** - * @param {Buffer|undefined} data + * @param {Map} extensions */ - constructor (data) { - this.frameData = data; - this.maskKey = crypto.randomBytes(4); + constructor (extensions) { + this.#options.serverNoContextTakeover = extensions.has('server_no_context_takeover'); + this.#options.serverMaxWindowBits = extensions.get('server_max_window_bits'); } - createFrame (opcode) { - const bodyLength = this.frameData?.byteLength ?? 0; - - /** @type {number} */ - let payloadLength = bodyLength; // 0-125 - let offset = 6; + decompress (chunk, fin, callback) { + // An endpoint uses the following algorithm to decompress a message. + // 1. Append 4 octets of 0x00 0x00 0xff 0xff to the tail end of the + // payload of the message. + // 2. Decompress the resulting data using DEFLATE. - if (bodyLength > maxUnsigned16Bit) { - offset += 8; // payload length is next 8 bytes - payloadLength = 127; - } else if (bodyLength > 125) { - offset += 2; // payload length is next 2 bytes - payloadLength = 126; + if (this.#aborted) { + callback(new MessageSizeExceededError()); + return } - const buffer = Buffer.allocUnsafe(bodyLength + offset); + if (!this.#inflate) { + let windowBits = Z_DEFAULT_WINDOWBITS; - // Clear first 2 bytes, everything else is overwritten - buffer[0] = buffer[1] = 0; - buffer[0] |= 0x80; // FIN - buffer[0] = (buffer[0] & 0xF0) + opcode; // opcode + if (this.#options.serverMaxWindowBits) { // empty values default to Z_DEFAULT_WINDOWBITS + if (!isValidClientWindowBits(this.#options.serverMaxWindowBits)) { + callback(new Error('Invalid server_max_window_bits')); + return + } - /*! ws. MIT License. Einar Otto Stangvik */ - buffer[offset - 4] = this.maskKey[0]; - buffer[offset - 3] = this.maskKey[1]; - buffer[offset - 2] = this.maskKey[2]; - buffer[offset - 1] = this.maskKey[3]; + windowBits = Number.parseInt(this.#options.serverMaxWindowBits); + } - buffer[1] = payloadLength; + try { + this.#inflate = createInflateRaw({ windowBits }); + } catch (err) { + callback(err); + return + } + this.#inflate[kBuffer] = []; + this.#inflate[kLength] = 0; - if (payloadLength === 126) { - buffer.writeUInt16BE(bodyLength, 2); - } else if (payloadLength === 127) { - // Clear extended payload length - buffer[2] = buffer[3] = 0; - buffer.writeUIntBE(bodyLength, 4, 6); - } + this.#inflate.on('data', (data) => { + if (this.#aborted) { + return + } - buffer[1] |= 0x80; // MASK + this.#inflate[kLength] += data.length; - // mask body - for (let i = 0; i < bodyLength; i++) { - buffer[offset + i] = this.frameData[i] ^ this.maskKey[i % 4]; + if (this.#inflate[kLength] > kDefaultMaxDecompressedSize) { + this.#aborted = true; + this.#inflate.removeAllListeners(); + this.#inflate.destroy(); + this.#inflate = null; + + if (this.#currentCallback) { + const cb = this.#currentCallback; + this.#currentCallback = null; + cb(new MessageSizeExceededError()); + } + return + } + + this.#inflate[kBuffer].push(data); + }); + + this.#inflate.on('error', (err) => { + this.#inflate = null; + callback(err); + }); } - return buffer + this.#currentCallback = callback; + this.#inflate.write(chunk); + if (fin) { + this.#inflate.write(tail); + } + + this.#inflate.flush(() => { + if (this.#aborted || !this.#inflate) { + return + } + + const full = Buffer.concat(this.#inflate[kBuffer], this.#inflate[kLength]); + + this.#inflate[kBuffer].length = 0; + this.#inflate[kLength] = 0; + this.#currentCallback = null; + + callback(null, full); + }); } } - frame = { - WebsocketFrameSend - }; - return frame; + permessageDeflate = { PerMessageDeflate }; + return permessageDeflate; } var receiver; @@ -23050,35 +25835,56 @@ function requireReceiver () { if (hasRequiredReceiver) return receiver; hasRequiredReceiver = 1; - const { Writable } = require$$0$5; - const diagnosticsChannel = require$$0$9; - const { parserStates, opcodes, states, emptyBuffer } = requireConstants(); + const { Writable } = require$$0$4; + const assert = require$$0$3; + const { parserStates, opcodes, states, emptyBuffer, sentCloseFrameState } = requireConstants(); const { kReadyState, kSentClose, kResponse, kReceivedClose } = requireSymbols(); - const { isValidStatusCode, failWebsocketConnection, websocketMessageReceived } = requireUtil$1(); + const { channels } = requireDiagnostics(); + const { + isValidStatusCode, + isValidOpcode, + failWebsocketConnection, + websocketMessageReceived, + utf8Decode, + isControlFrame, + isTextBinaryFrame, + isContinuationFrame + } = requireUtil$2(); const { WebsocketFrameSend } = requireFrame(); + const { closeWebSocketConnection } = requireConnection(); + const { PerMessageDeflate } = requirePermessageDeflate(); // This code was influenced by ws released under the MIT license. // Copyright (c) 2011 Einar Otto Stangvik // Copyright (c) 2013 Arnout Kazemier and contributors // Copyright (c) 2016 Luigi Pinca and contributors - const channels = {}; - channels.ping = diagnosticsChannel.channel('undici:websocket:ping'); - channels.pong = diagnosticsChannel.channel('undici:websocket:pong'); - class ByteParser extends Writable { #buffers = [] #byteOffset = 0 + #loop = false #state = parserStates.INFO #info = {} #fragments = [] - constructor (ws) { + /** @type {Map} */ + #extensions + + /** + * @param {import('./websocket').WebSocket} ws + * @param {Map|null} extensions + */ + constructor (ws, extensions) { super(); this.ws = ws; + this.#extensions = extensions == null ? new Map() : extensions; + + if (this.#extensions.has('permessage-deflate')) { + this.#extensions.set('permessage-deflate', new PerMessageDeflate(extensions)); + } } /** @@ -23088,6 +25894,7 @@ function requireReceiver () { _write (chunk, _, callback) { this.#buffers.push(chunk); this.#byteOffset += chunk.length; + this.#loop = true; this.run(callback); } @@ -23098,7 +25905,7 @@ function requireReceiver () { * or not enough bytes are buffered to parse. */ run (callback) { - while (true) { + while (this.#loop) { if (this.#state === parserStates.INFO) { // If there aren't enough bytes to parse the payload length, etc. if (this.#byteOffset < 2) { @@ -23106,132 +25913,95 @@ function requireReceiver () { } const buffer = this.consume(2); + const fin = (buffer[0] & 0x80) !== 0; + const opcode = buffer[0] & 0x0F; + const masked = (buffer[1] & 0x80) === 0x80; + + const fragmented = !fin && opcode !== opcodes.CONTINUATION; + const payloadLength = buffer[1] & 0x7F; + + const rsv1 = buffer[0] & 0x40; + const rsv2 = buffer[0] & 0x20; + const rsv3 = buffer[0] & 0x10; + + if (!isValidOpcode(opcode)) { + failWebsocketConnection(this.ws, 'Invalid opcode received'); + return callback() + } - this.#info.fin = (buffer[0] & 0x80) !== 0; - this.#info.opcode = buffer[0] & 0x0F; + if (masked) { + failWebsocketConnection(this.ws, 'Frame cannot be masked'); + return callback() + } - // If we receive a fragmented message, we use the type of the first - // frame to parse the full message as binary/text, when it's terminated - this.#info.originalOpcode ??= this.#info.opcode; + // MUST be 0 unless an extension is negotiated that defines meanings + // for non-zero values. If a nonzero value is received and none of + // the negotiated extensions defines the meaning of such a nonzero + // value, the receiving endpoint MUST _Fail the WebSocket + // Connection_. + // This document allocates the RSV1 bit of the WebSocket header for + // PMCEs and calls the bit the "Per-Message Compressed" bit. On a + // WebSocket connection where a PMCE is in use, this bit indicates + // whether a message is compressed or not. + if (rsv1 !== 0 && !this.#extensions.has('permessage-deflate')) { + failWebsocketConnection(this.ws, 'Expected RSV1 to be clear.'); + return + } - this.#info.fragmented = !this.#info.fin && this.#info.opcode !== opcodes.CONTINUATION; + if (rsv2 !== 0 || rsv3 !== 0) { + failWebsocketConnection(this.ws, 'RSV1, RSV2, RSV3 must be clear'); + return + } - if (this.#info.fragmented && this.#info.opcode !== opcodes.BINARY && this.#info.opcode !== opcodes.TEXT) { + if (fragmented && !isTextBinaryFrame(opcode)) { // Only text and binary frames can be fragmented failWebsocketConnection(this.ws, 'Invalid frame type was fragmented.'); return } - const payloadLength = buffer[1] & 0x7F; - - if (payloadLength <= 125) { - this.#info.payloadLength = payloadLength; - this.#state = parserStates.READ_DATA; - } else if (payloadLength === 126) { - this.#state = parserStates.PAYLOADLENGTH_16; - } else if (payloadLength === 127) { - this.#state = parserStates.PAYLOADLENGTH_64; + // If we are already parsing a text/binary frame and do not receive either + // a continuation frame or close frame, fail the connection. + if (isTextBinaryFrame(opcode) && this.#fragments.length > 0) { + failWebsocketConnection(this.ws, 'Expected continuation frame'); + return } - if (this.#info.fragmented && payloadLength > 125) { + if (this.#info.fragmented && fragmented) { // A fragmented frame can't be fragmented itself failWebsocketConnection(this.ws, 'Fragmented frame exceeded 125 bytes.'); return - } else if ( - (this.#info.opcode === opcodes.PING || - this.#info.opcode === opcodes.PONG || - this.#info.opcode === opcodes.CLOSE) && - payloadLength > 125 - ) { - // Control frames can have a payload length of 125 bytes MAX - failWebsocketConnection(this.ws, 'Payload length for control frame exceeded 125 bytes.'); - return - } else if (this.#info.opcode === opcodes.CLOSE) { - if (payloadLength === 1) { - failWebsocketConnection(this.ws, 'Received close frame with a 1-byte body.'); - return - } - - const body = this.consume(payloadLength); - - this.#info.closeInfo = this.parseCloseBody(false, body); - - if (!this.ws[kSentClose]) { - // If an endpoint receives a Close frame and did not previously send a - // Close frame, the endpoint MUST send a Close frame in response. (When - // sending a Close frame in response, the endpoint typically echos the - // status code it received.) - const body = Buffer.allocUnsafe(2); - body.writeUInt16BE(this.#info.closeInfo.code, 0); - const closeFrame = new WebsocketFrameSend(body); - - this.ws[kResponse].socket.write( - closeFrame.createFrame(opcodes.CLOSE), - (err) => { - if (!err) { - this.ws[kSentClose] = true; - } - } - ); - } - - // Upon either sending or receiving a Close control frame, it is said - // that _The WebSocket Closing Handshake is Started_ and that the - // WebSocket connection is in the CLOSING state. - this.ws[kReadyState] = states.CLOSING; - this.ws[kReceivedClose] = true; - - this.end(); + } + // "All control frames MUST have a payload length of 125 bytes or less + // and MUST NOT be fragmented." + if ((payloadLength > 125 || fragmented) && isControlFrame(opcode)) { + failWebsocketConnection(this.ws, 'Control frame either too large or fragmented'); return - } else if (this.#info.opcode === opcodes.PING) { - // Upon receipt of a Ping frame, an endpoint MUST send a Pong frame in - // response, unless it already received a Close frame. - // A Pong frame sent in response to a Ping frame must have identical - // "Application data" - - const body = this.consume(payloadLength); - - 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 - }); - } - } - - this.#state = parserStates.INFO; - - if (this.#byteOffset > 0) { - continue - } else { - callback(); - return - } - } else if (this.#info.opcode === opcodes.PONG) { - // A Pong frame MAY be sent unsolicited. This serves as a - // unidirectional heartbeat. A response to an unsolicited Pong frame is - // not expected. + } - const body = this.consume(payloadLength); + if (isContinuationFrame(opcode) && this.#fragments.length === 0 && !this.#info.compressed) { + failWebsocketConnection(this.ws, 'Unexpected continuation frame'); + return + } - if (channels.pong.hasSubscribers) { - channels.pong.publish({ - payload: body - }); - } + if (payloadLength <= 125) { + this.#info.payloadLength = payloadLength; + this.#state = parserStates.READ_DATA; + } else if (payloadLength === 126) { + this.#state = parserStates.PAYLOADLENGTH_16; + } else if (payloadLength === 127) { + this.#state = parserStates.PAYLOADLENGTH_64; + } - if (this.#byteOffset > 0) { - continue - } else { - callback(); - return - } + 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() @@ -23248,53 +26018,74 @@ function requireReceiver () { const buffer = this.consume(8); const upper = buffer.readUInt32BE(0); + const lower = buffer.readUInt32BE(4); - // 2^31 is the maxinimum bytes an arraybuffer can contain + // 2^31 is the maximum bytes an arraybuffer can contain // on 32-bit systems. Although, on 64-bit systems, this is // 2^53-1 bytes. // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Errors/Invalid_array_length // https://source.chromium.org/chromium/chromium/src/+/main:v8/src/common/globals.h;drc=1946212ac0100668f14eb9e2843bdd846e510a1e;bpv=1;bpt=1;l=1275 // https://source.chromium.org/chromium/chromium/src/+/main:v8/src/objects/js-array-buffer.h;l=34;drc=1946212ac0100668f14eb9e2843bdd846e510a1e - if (upper > 2 ** 31 - 1) { + if (upper !== 0 || lower > 2 ** 31 - 1) { failWebsocketConnection(this.ws, 'Received payload length > 2^31 bytes.'); return } - const lower = buffer.readUInt32BE(4); - - this.#info.payloadLength = (upper << 8) + lower; + this.#info.payloadLength = lower; this.#state = parserStates.READ_DATA; } else if (this.#state === parserStates.READ_DATA) { if (this.#byteOffset < this.#info.payloadLength) { - // If there is still more data in this chunk that needs to be read return callback() - } else if (this.#byteOffset >= this.#info.payloadLength) { - // If the server sent multiple frames in a single chunk + } - const body = this.consume(this.#info.payloadLength); + const body = this.consume(this.#info.payloadLength); - this.#fragments.push(body); + if (isControlFrame(this.#info.opcode)) { + this.#loop = this.parseControlFrame(body); + this.#state = parserStates.INFO; + } else { + if (!this.#info.compressed) { + this.#fragments.push(body); + + // If the frame is not fragmented, a message has been received. + // If the frame is fragmented, it will terminate with a fin bit set + // and an opcode of 0 (continuation), therefore we handle that when + // parsing continuation frames, not here. + if (!this.#info.fragmented && this.#info.fin) { + const fullMessage = Buffer.concat(this.#fragments); + websocketMessageReceived(this.ws, this.#info.binaryType, fullMessage); + this.#fragments.length = 0; + } - // If the frame is unfragmented, or a fragmented frame was terminated, - // a message was received - if (!this.#info.fragmented || (this.#info.fin && this.#info.opcode === opcodes.CONTINUATION)) { - const fullMessage = Buffer.concat(this.#fragments); + 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 + } - websocketMessageReceived(this.ws, this.#info.originalOpcode, fullMessage); + this.#fragments.push(data); - this.#info = {}; - this.#fragments.length = 0; - } + if (!this.#info.fin) { + this.#state = parserStates.INFO; + this.#loop = true; + this.run(callback); + return + } - this.#state = parserStates.INFO; - } - } + websocketMessageReceived(this.ws, this.#info.binaryType, Buffer.concat(this.#fragments)); - if (this.#byteOffset > 0) { - continue - } else { - callback(); - break + this.#loop = true; + this.#state = parserStates.INFO; + this.#fragments.length = 0; + this.run(callback); + }); + + this.#loop = false; + break + } + } } } } @@ -23302,11 +26093,11 @@ function requireReceiver () { /** * Take n bytes from the buffered Buffers * @param {number} n - * @returns {Buffer|null} + * @returns {Buffer} */ consume (n) { if (n > this.#byteOffset) { - return null + throw new Error('Called consume() before buffers satiated.') } else if (n === 0) { return emptyBuffer } @@ -23341,7 +26132,9 @@ function requireReceiver () { return buffer } - parseCloseBody (onlyCode, data) { + parseCloseBody (data) { + assert(data.length !== 1); + // https://datatracker.ietf.org/doc/html/rfc6455#section-7.1.5 /** @type {number|undefined} */ let code; @@ -23353,12 +26146,8 @@ function requireReceiver () { code = data.readUInt16BE(0); } - if (onlyCode) { - if (!isValidStatusCode(code)) { - return null - } - - return { code } + if (code !== undefined && !isValidStatusCode(code)) { + return { code: 1002, reason: 'Invalid status code', error: true } } // https://datatracker.ietf.org/doc/html/rfc6455#section-7.1.6 @@ -23370,18 +26159,97 @@ function requireReceiver () { reason = reason.subarray(3); } - if (code !== undefined && !isValidStatusCode(code)) { - return null - } - try { - // TODO: optimize this - reason = new TextDecoder('utf-8', { fatal: true }).decode(reason); + reason = utf8Decode(reason); } catch { - return null + return { code: 1007, reason: 'Invalid UTF-8', error: true } } - return { code, reason } + 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) { + // If an endpoint receives a Close frame and did not previously send a + // Close frame, the endpoint MUST send a Close frame in response. (When + // sending a Close frame in response, the endpoint typically echos the + // status code it received.) + let body = emptyBuffer; + if (this.#info.closeInfo.code) { + body = Buffer.allocUnsafe(2); + body.writeUInt16BE(this.#info.closeInfo.code, 0); + } + const closeFrame = new WebsocketFrameSend(body); + + this.ws[kResponse].socket.write( + closeFrame.createFrame(opcodes.CLOSE), + (err) => { + if (!err) { + this.ws[kSentClose] = sentCloseFrameState.SENT; + } + } + ); + } + + // Upon either sending or receiving a Close control frame, it is said + // that _The WebSocket Closing Handshake is Started_ and that the + // WebSocket connection is in the CLOSING state. + this.ws[kReadyState] = states.CLOSING; + this.ws[kReceivedClose] = true; + + return false + } else if (opcode === opcodes.PING) { + // Upon receipt of a Ping frame, an endpoint MUST send a Pong frame in + // response, unless it already received a Close frame. + // A Pong frame sent in response to a Ping frame must have identical + // "Application data" + + 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) { + // A Pong frame MAY be sent unsolicited. This serves as a + // unidirectional heartbeat. A response to an unsolicited Pong frame is + // not expected. + + if (channels.pong.hasSubscribers) { + channels.pong.publish({ + payload: body + }); + } + } + + return true } get closingInfo () { @@ -23395,6 +26263,118 @@ function requireReceiver () { return receiver; } +var sender; +var hasRequiredSender; + +function requireSender () { + if (hasRequiredSender) return sender; + hasRequiredSender = 1; + + const { WebsocketFrameSend } = requireFrame(); + const { opcodes, sendHints } = requireConstants(); + const FixedQueue = requireFixedQueue(); + + /** @type {typeof Uint8Array} */ + const FastBuffer = Buffer[Symbol.species]; + + /** + * @typedef {object} SendQueueNode + * @property {Promise | null} promise + * @property {((...args: any[]) => any)} callback + * @property {Buffer | null} frame + */ + + class SendQueue { + /** + * @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) { + // fast-path + this.#socket.write(frame, cb); + } else { + /** @type {SendQueueNode} */ + const node = { + promise: null, + callback: cb, + frame + }; + this.#queue.push(node); + } + return + } + + /** @type {SendQueueNode} */ + 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(); + // wait pending promise + if (node.promise !== null) { + await node.promise; + } + // write + this.#socket.write(node.frame, node.callback); + // cleanup + 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) + } + } + + sender = { SendQueue }; + return sender; +} + var websocket; var hasRequiredWebsocket; @@ -23403,10 +26383,9 @@ function requireWebsocket () { hasRequiredWebsocket = 1; const { webidl } = requireWebidl(); - const { DOMException } = requireConstants$3(); - const { URLSerializer } = requireDataURL(); - const { getGlobalOrigin } = requireGlobal$1(); - const { staticPropertyDescriptors, states, opcodes, emptyBuffer } = requireConstants(); + const { URLSerializer } = requireDataUrl(); + const { environmentSettingsObject } = requireUtil$7(); + const { staticPropertyDescriptors, states, sentCloseFrameState, sendHints } = requireConstants(); const { kWebSocketURL, kReadyState, @@ -23416,15 +26395,20 @@ function requireWebsocket () { kSentClose, kByteParser } = requireSymbols(); - const { isEstablished, isClosing, isValidSubprotocol, failWebsocketConnection, fireEvent } = requireUtil$1(); - const { establishWebSocketConnection } = requireConnection(); - const { WebsocketFrameSend } = requireFrame(); + const { + isConnecting, + isEstablished, + isClosing, + isValidSubprotocol, + fireEvent + } = requireUtil$2(); + const { establishWebSocketConnection, closeWebSocketConnection } = requireConnection(); const { ByteParser } = requireReceiver(); - const { kEnumerableProperty, isBlobLike } = requireUtil$7(); + const { kEnumerableProperty, isBlobLike } = requireUtil$8(); const { getGlobalDispatcher } = requireGlobal(); - const { types } = require$$0$2; - - let experimentalWarned = false; + const { types } = require$$0$6; + const { ErrorEvent, CloseEvent } = requireEvents(); + const { SendQueue } = requireSender(); // https://websockets.spec.whatwg.org/#interface-definition class WebSocket extends EventTarget { @@ -23439,6 +26423,9 @@ function requireWebsocket () { #protocol = '' #extensions = '' + /** @type {SendQueue} */ + #sendQueue + /** * @param {string} url * @param {string|string[]} protocols @@ -23446,22 +26433,18 @@ function requireWebsocket () { constructor (url, protocols = []) { super(); - webidl.argumentLengthCheck(arguments, 1, { header: 'WebSocket constructor' }); + webidl.util.markAsUncloneable(this); - if (!experimentalWarned) { - experimentalWarned = true; - process.emitWarning('WebSockets are experimental, expect them to change at any time.', { - code: 'UNDICI-WS' - }); - } + const prefix = 'WebSocket constructor'; + webidl.argumentLengthCheck(arguments, 1, prefix); - const options = webidl.converters['DOMString or sequence or WebSocketInit'](protocols); + const options = webidl.converters['DOMString or sequence or WebSocketInit'](protocols, prefix, 'options'); - url = webidl.converters.USVString(url); + url = webidl.converters.USVString(url, prefix, 'url'); protocols = options.protocols; // 1. Let baseURL be this's relevant settings object's API base URL. - const baseURL = getGlobalOrigin(); + const baseURL = environmentSettingsObject.settingsObject.baseUrl; // 1. Let urlRecord be the result of applying the URL parser to url with baseURL. let urlRecord; @@ -23517,6 +26500,7 @@ function requireWebsocket () { this[kWebSocketURL] = new URL(urlRecord.href); // 11. Let client be this's relevant settings object. + const client = environmentSettingsObject.settingsObject; // 12. Run this step in parallel: @@ -23525,8 +26509,9 @@ function requireWebsocket () { this[kController] = establishWebSocketConnection( urlRecord, protocols, + client, this, - (response) => this.#onConnectionEstablished(response), + (response, extensions) => this.#onConnectionEstablished(response, extensions), options ); @@ -23535,6 +26520,8 @@ function requireWebsocket () { // be CONNECTING (0). this[kReadyState] = WebSocket.CONNECTING; + this[kSentClose] = sentCloseFrameState.NOT_SENT; + // The extensions attribute must initially return the empty string. // The protocol attribute must initially return the empty string. @@ -23552,12 +26539,14 @@ function requireWebsocket () { close (code = undefined, reason = undefined) { webidl.brandCheck(this, WebSocket); + const prefix = 'WebSocket.close'; + if (code !== undefined) { - code = webidl.converters['unsigned short'](code, { clamp: true }); + code = webidl.converters['unsigned short'](code, prefix, 'code', { clamp: true }); } if (reason !== undefined) { - reason = webidl.converters.USVString(reason); + reason = webidl.converters.USVString(reason, prefix, 'reason'); } // 1. If code is present, but is neither an integer equal to 1000 nor an @@ -23587,62 +26576,7 @@ function requireWebsocket () { } // 3. Run the first matching steps from the following list: - if (this[kReadyState] === WebSocket.CLOSING || this[kReadyState] === WebSocket.CLOSED) ; else if (!isEstablished(this)) { - // If the WebSocket connection is not yet established - // Fail the WebSocket connection and set this's ready state - // to CLOSING (2). - failWebsocketConnection(this, 'Connection was closed before it was established.'); - this[kReadyState] = WebSocket.CLOSING; - } else if (!isClosing(this)) { - // If the WebSocket closing handshake has not yet been started - // Start the WebSocket closing handshake and set this's ready - // state to CLOSING (2). - // - If neither code nor reason is present, the WebSocket Close - // message must not have a body. - // - If code is present, then the status code to use in the - // WebSocket Close message must be the integer given by code. - // - If reason is also present, then reasonBytes must be - // provided in the Close message after the status code. - - const frame = new WebsocketFrameSend(); - - // If neither code nor reason is present, the WebSocket Close - // message must not have a body. - - // If code is present, then the status code to use in the - // WebSocket Close message must be the integer given by code. - if (code !== undefined && reason === undefined) { - frame.frameData = Buffer.allocUnsafe(2); - frame.frameData.writeUInt16BE(code, 0); - } else if (code !== undefined && reason !== undefined) { - // If reason is also present, then reasonBytes must be - // provided in the Close message after the status code. - frame.frameData = Buffer.allocUnsafe(2 + reasonByteLength); - frame.frameData.writeUInt16BE(code, 0); - // the body MAY contain UTF-8-encoded data with value /reason/ - frame.frameData.write(reason, 2, 'utf-8'); - } else { - frame.frameData = emptyBuffer; - } - - /** @type {import('stream').Duplex} */ - const socket = this[kResponse].socket; - - socket.write(frame.createFrame(opcodes.CLOSE), (err) => { - if (!err) { - this[kSentClose] = true; - } - }); - - // Upon either sending or receiving a Close control frame, it is said - // that _The WebSocket Closing Handshake is Started_ and that the - // WebSocket connection is in the CLOSING state. - this[kReadyState] = states.CLOSING; - } else { - // Otherwise - // Set this's ready state to CLOSING (2). - this[kReadyState] = WebSocket.CLOSING; - } + closeWebSocketConnection(this, code, reason, reasonByteLength); } /** @@ -23652,13 +26586,14 @@ function requireWebsocket () { send (data) { webidl.brandCheck(this, WebSocket); - webidl.argumentLengthCheck(arguments, 1, { header: 'WebSocket.send' }); + const prefix = 'WebSocket.send'; + webidl.argumentLengthCheck(arguments, 1, prefix); - data = webidl.converters.WebSocketSendData(data); + data = webidl.converters.WebSocketSendData(data, prefix, 'data'); // 1. If this's ready state is CONNECTING, then throw an // "InvalidStateError" DOMException. - if (this[kReadyState] === WebSocket.CONNECTING) { + if (isConnecting(this)) { throw new DOMException('Sent before connected.', 'InvalidStateError') } @@ -23670,9 +26605,6 @@ function requireWebsocket () { return } - /** @type {import('stream').Duplex} */ - const socket = this[kResponse].socket; - // If data is a string if (typeof data === 'string') { // If the WebSocket connection is established and the WebSocket @@ -23686,14 +26618,12 @@ function requireWebsocket () { // the bufferedAmount attribute by the number of bytes needed to // express the argument as UTF-8. - const value = Buffer.from(data); - const frame = new WebsocketFrameSend(value); - const buffer = frame.createFrame(opcodes.TEXT); + const length = Buffer.byteLength(data); - this.#bufferedAmount += value.byteLength; - socket.write(buffer, () => { - this.#bufferedAmount -= value.byteLength; - }); + this.#bufferedAmount += length; + this.#sendQueue.add(data, () => { + this.#bufferedAmount -= length; + }, sendHints.string); } else if (types.isArrayBuffer(data)) { // If the WebSocket connection is established, and the WebSocket // closing handshake has not yet started, then the user agent must @@ -23707,14 +26637,10 @@ function requireWebsocket () { // increase the bufferedAmount attribute by the length of the // ArrayBuffer in bytes. - const value = Buffer.from(data); - const frame = new WebsocketFrameSend(value); - const buffer = frame.createFrame(opcodes.BINARY); - - this.#bufferedAmount += value.byteLength; - socket.write(buffer, () => { - this.#bufferedAmount -= value.byteLength; - }); + this.#bufferedAmount += data.byteLength; + this.#sendQueue.add(data, () => { + this.#bufferedAmount -= data.byteLength; + }, sendHints.arrayBuffer); } else if (ArrayBuffer.isView(data)) { // If the WebSocket connection is established, and the WebSocket // closing handshake has not yet started, then the user agent must @@ -23728,15 +26654,10 @@ function requireWebsocket () { // not throw an exception must increase the bufferedAmount attribute // by the length of data’s buffer in bytes. - const ab = Buffer.from(data, data.byteOffset, data.byteLength); - - const frame = new WebsocketFrameSend(ab); - const buffer = frame.createFrame(opcodes.BINARY); - - this.#bufferedAmount += ab.byteLength; - socket.write(buffer, () => { - this.#bufferedAmount -= ab.byteLength; - }); + this.#bufferedAmount += data.byteLength; + this.#sendQueue.add(data, () => { + this.#bufferedAmount -= data.byteLength; + }, sendHints.typedArray); } else if (isBlobLike(data)) { // If the WebSocket connection is established, and the WebSocket // closing handshake has not yet started, then the user agent must @@ -23749,18 +26670,10 @@ function requireWebsocket () { // an exception must increase the bufferedAmount attribute by the size // of the Blob object’s raw data, in bytes. - const frame = new WebsocketFrameSend(); - - data.arrayBuffer().then((ab) => { - const value = Buffer.from(ab); - frame.frameData = value; - const buffer = frame.createFrame(opcodes.BINARY); - - this.#bufferedAmount += value.byteLength; - socket.write(buffer, () => { - this.#bufferedAmount -= value.byteLength; - }); - }); + this.#bufferedAmount += data.size; + this.#sendQueue.add(data, () => { + this.#bufferedAmount -= data.size; + }, sendHints.blob); } } @@ -23899,19 +26812,20 @@ function requireWebsocket () { /** * @see https://websockets.spec.whatwg.org/#feedback-from-the-protocol */ - #onConnectionEstablished (response) { - // processResponse is called when the "response’s header list has been received and initialized." + #onConnectionEstablished (response, parsedExtensions) { + // processResponse is called when the "response's header list has been received and initialized." // once this happens, the connection is open this[kResponse] = response; - const parser = new ByteParser(this); - parser.on('drain', function onParserDrain () { - this.ws[kResponse].socket.resume(); - }); + const parser = new ByteParser(this, parsedExtensions); + parser.on('drain', onParserDrain); + parser.on('error', onParserError.bind(this)); response.socket.ws = this; this[kByteParser] = parser; + this.#sendQueue = new SendQueue(response.socket); + // 1. Change the ready state to OPEN (1). this[kReadyState] = states.OPEN; @@ -23983,29 +26897,25 @@ function requireWebsocket () { webidl.converters.DOMString ); - webidl.converters['DOMString or sequence'] = function (V) { + 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) + return webidl.converters.DOMString(V, prefix, argument) }; - // This implements the propsal made in https://github.com/whatwg/websockets/issues/42 + // This implements the proposal made in https://github.com/whatwg/websockets/issues/42 webidl.converters.WebSocketInit = webidl.dictionaryConverter([ { key: 'protocols', converter: webidl.converters['DOMString or sequence'], - get defaultValue () { - return [] - } + defaultValue: () => new Array(0) }, { key: 'dispatcher', - converter: (V) => V, - get defaultValue () { - return getGlobalDispatcher() - } + converter: webidl.converters.any, + defaultValue: () => getGlobalDispatcher() }, { key: 'headers', @@ -24027,7 +26937,7 @@ function requireWebsocket () { return webidl.converters.Blob(V, { strict: false }) } - if (ArrayBuffer.isView(V) || types.isAnyArrayBuffer(V)) { + if (ArrayBuffer.isView(V) || types.isArrayBuffer(V)) { return webidl.converters.BufferSource(V) } } @@ -24035,12 +26945,971 @@ function requireWebsocket () { 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); + } + websocket = { WebSocket }; return websocket; } +var util$1; +var hasRequiredUtil$1; + +function requireUtil$1 () { + if (hasRequiredUtil$1) return util$1; + hasRequiredUtil$1 = 1; + + /** + * Checks if the given value is a valid LastEventId. + * @param {string} value + * @returns {boolean} + */ + function isValidLastEventId (value) { + // LastEventId should not contain U+0000 NULL + return value.indexOf('\u0000') === -1 + } + + /** + * Checks if the given value is a base 10 digit. + * @param {string} value + * @returns {boolean} + */ + function isASCIINumber (value) { + if (value.length === 0) return false + for (let i = 0; i < value.length; i++) { + if (value.charCodeAt(i) < 0x30 || value.charCodeAt(i) > 0x39) return false + } + return true + } + + // https://github.com/nodejs/undici/issues/2664 + function delay (ms) { + return new Promise((resolve) => { + setTimeout(resolve, ms).unref(); + }) + } + + util$1 = { + isValidLastEventId, + isASCIINumber, + delay + }; + return util$1; +} + +var eventsourceStream; +var hasRequiredEventsourceStream; + +function requireEventsourceStream () { + if (hasRequiredEventsourceStream) return eventsourceStream; + hasRequiredEventsourceStream = 1; + const { Transform } = require$$0$4; + const { isASCIINumber, isValidLastEventId } = requireUtil$1(); + + /** + * @type {number[]} BOM + */ + const BOM = [0xEF, 0xBB, 0xBF]; + /** + * @type {10} LF + */ + const LF = 0x0A; + /** + * @type {13} CR + */ + const CR = 0x0D; + /** + * @type {58} COLON + */ + const COLON = 0x3A; + /** + * @type {32} SPACE + */ + const SPACE = 0x20; + + /** + * @typedef {object} EventSourceStreamEvent + * @type {object} + * @property {string} [event] The event type. + * @property {string} [data] The data of the message. + * @property {string} [id] A unique ID for the event. + * @property {string} [retry] The reconnection time, in milliseconds. + */ + + /** + * @typedef eventSourceSettings + * @type {object} + * @property {string} lastEventId The last event ID received from the server. + * @property {string} origin The origin of the event source. + * @property {number} reconnectionTime The reconnection time, in milliseconds. + */ + + class EventSourceStream 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: undefined, + event: undefined, + id: undefined, + retry: undefined + } + + /** + * @param {object} options + * @param {eventSourceSettings} options.eventSourceSettings + * @param {Function} [options.push] + */ + constructor (options = {}) { + // Enable object mode as EventSourceStream emits objects of shape + // EventSourceStreamEvent + 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 + } + + // Cache the chunk in the buffer, as the data might not be complete while + // processing it + // TODO: Investigate if there is a more performant way to handle + // incoming chunks + // see: https://github.com/nodejs/undici/issues/2630 + if (this.buffer) { + this.buffer = Buffer.concat([this.buffer, chunk]); + } else { + this.buffer = chunk; + } + + // Strip leading byte-order-mark if we opened the stream and started + // the processing of the incoming data + if (this.checkBOM) { + switch (this.buffer.length) { + case 1: + // Check if the first byte is the same as the first byte of the BOM + if (this.buffer[0] === BOM[0]) { + // If it is, we need to wait for more data + callback(); + return + } + // Set the checkBOM flag to false as we don't need to check for the + // BOM anymore + this.checkBOM = false; + + // The buffer only contains one byte so we need to wait for more data + callback(); + return + case 2: + // Check if the first two bytes are the same as the first two bytes + // of the BOM + if ( + this.buffer[0] === BOM[0] && + this.buffer[1] === BOM[1] + ) { + // If it is, we need to wait for more data, because the third byte + // is needed to determine if it is the BOM or not + callback(); + return + } + + // Set the checkBOM flag to false as we don't need to check for the + // BOM anymore + this.checkBOM = false; + break + case 3: + // Check if the first three bytes are the same as the first three + // bytes of the BOM + if ( + this.buffer[0] === BOM[0] && + this.buffer[1] === BOM[1] && + this.buffer[2] === BOM[2] + ) { + // If it is, we can drop the buffered data, as it is only the BOM + this.buffer = Buffer.alloc(0); + // Set the checkBOM flag to false as we don't need to check for the + // BOM anymore + this.checkBOM = false; + + // Await more data + callback(); + return + } + // If it is not the BOM, we can start processing the data + this.checkBOM = false; + break + default: + // The buffer is longer than 3 bytes, so we can drop the BOM if it is + // present + if ( + this.buffer[0] === BOM[0] && + this.buffer[1] === BOM[1] && + this.buffer[2] === BOM[2] + ) { + // Remove the BOM from the buffer + this.buffer = this.buffer.subarray(3); + } + + // Set the checkBOM flag to false as we don't need to check for the + this.checkBOM = false; + break + } + } + + while (this.pos < this.buffer.length) { + // If the previous line ended with an end-of-line, we need to check + // if the next character is also an end-of-line. + if (this.eventEndCheck) { + // If the the current character is an end-of-line, then the event + // is finished and we can process it + + // If the previous line ended with a carriage return, we need to + // check if the current character is a line feed and remove it + // from the buffer. + if (this.crlfCheck) { + // If the current character is a line feed, we can remove it + // from the buffer and reset the crlfCheck flag + if (this.buffer[this.pos] === LF) { + this.buffer = this.buffer.subarray(this.pos + 1); + this.pos = 0; + this.crlfCheck = false; + + // It is possible that the line feed is not the end of the + // event. We need to check if the next character is an + // end-of-line character to determine if the event is + // finished. We simply continue the loop to check the next + // character. + + // As we removed the line feed from the buffer and set the + // crlfCheck flag to false, we basically don't make any + // distinction between a line feed and a carriage return. + continue + } + this.crlfCheck = false; + } + + if (this.buffer[this.pos] === LF || this.buffer[this.pos] === CR) { + // If the current character is a carriage return, we need to + // set the crlfCheck flag to true, as we need to check if the + // next character is a line feed so we can remove it from the + // buffer + if (this.buffer[this.pos] === CR) { + this.crlfCheck = true; + } + + this.buffer = this.buffer.subarray(this.pos + 1); + this.pos = 0; + if ( + this.event.data !== undefined || this.event.event || this.event.id || this.event.retry) { + this.processEvent(this.event); + } + this.clearEvent(); + continue + } + // If the current character is not an end-of-line, then the event + // is not finished and we have to reset the eventEndCheck flag + this.eventEndCheck = false; + continue + } + + // If the current character is an end-of-line, we can process the + // line + if (this.buffer[this.pos] === LF || this.buffer[this.pos] === CR) { + // If the current character is a carriage return, we need to + // set the crlfCheck flag to true, as we need to check if the + // next character is a line feed + if (this.buffer[this.pos] === CR) { + this.crlfCheck = true; + } + + // In any case, we can process the line as we reached an + // end-of-line character + this.parseLine(this.buffer.subarray(0, this.pos), this.event); + + // Remove the processed line from the buffer + this.buffer = this.buffer.subarray(this.pos + 1); + // Reset the position as we removed the processed line from the buffer + this.pos = 0; + // A line was processed and this could be the end of the event. We need + // to check if the next line is empty to determine if the event is + // finished. + this.eventEndCheck = true; + continue + } + + this.pos++; + } + + callback(); + } + + /** + * @param {Buffer} line + * @param {EventStreamEvent} event + */ + parseLine (line, event) { + // If the line is empty (a blank line) + // Dispatch the event, as defined below. + // This will be handled in the _transform method + if (line.length === 0) { + return + } + + // If the line starts with a U+003A COLON character (:) + // Ignore the line. + const colonPosition = line.indexOf(COLON); + if (colonPosition === 0) { + return + } + + let field = ''; + let value = ''; + + // If the line contains a U+003A COLON character (:) + if (colonPosition !== -1) { + // Collect the characters on the line before the first U+003A COLON + // character (:), and let field be that string. + // TODO: Investigate if there is a more performant way to extract the + // field + // see: https://github.com/nodejs/undici/issues/2630 + field = line.subarray(0, colonPosition).toString('utf8'); + + // Collect the characters on the line after the first U+003A COLON + // character (:), and let value be that string. + // If value starts with a U+0020 SPACE character, remove it from value. + let valueStart = colonPosition + 1; + if (line[valueStart] === SPACE) { + ++valueStart; + } + // TODO: Investigate if there is a more performant way to extract the + // value + // see: https://github.com/nodejs/undici/issues/2630 + value = line.subarray(valueStart).toString('utf8'); + + // Otherwise, the string is not empty but does not contain a U+003A COLON + // character (:) + } else { + // Process the field using the steps described below, using the whole + // line as the field name, and the empty string as the field value. + field = line.toString('utf8'); + value = ''; + } + + // Modify the event with the field name and value. The value is also + // decoded as UTF-8 + switch (field) { + case 'data': + if (event[field] === undefined) { + event[field] = value; + } else { + event[field] += `\n${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; + } + + // only dispatch event, when data is provided + if (event.data !== undefined) { + this.push({ + type: event.event || 'message', + options: { + data: event.data, + lastEventId: this.state.lastEventId, + origin: this.state.origin + } + }); + } + } + + clearEvent () { + this.event = { + data: undefined, + event: undefined, + id: undefined, + retry: undefined + }; + } + } + + eventsourceStream = { + EventSourceStream + }; + return eventsourceStream; +} + +var eventsource; +var hasRequiredEventsource; + +function requireEventsource () { + if (hasRequiredEventsource) return eventsource; + hasRequiredEventsource = 1; + + const { pipeline } = require$$0$4; + const { fetching } = requireFetch(); + const { makeRequest } = requireRequest(); + const { webidl } = requireWebidl(); + const { EventSourceStream } = requireEventsourceStream(); + const { parseMIMEType } = requireDataUrl(); + const { createFastMessageEvent } = requireEvents(); + const { isNetworkError } = requireResponse(); + const { delay } = requireUtil$1(); + const { kEnumerableProperty } = requireUtil$8(); + const { environmentSettingsObject } = requireUtil$7(); + + let experimentalWarned = false; + + /** + * A reconnection time, in milliseconds. This must initially be an implementation-defined value, + * probably in the region of a few seconds. + * + * In Comparison: + * - Chrome uses 3000ms. + * - Deno uses 5000ms. + * + * @type {3000} + */ + const defaultReconnectionTime = 3000; + + /** + * The readyState attribute represents the state of the connection. + * @enum + * @readonly + * @see https://html.spec.whatwg.org/multipage/server-sent-events.html#dom-eventsource-readystate-dev + */ + + /** + * The connection has not yet been established, or it was closed and the user + * agent is reconnecting. + * @type {0} + */ + const CONNECTING = 0; + + /** + * The user agent has an open connection and is dispatching events as it + * receives them. + * @type {1} + */ + const OPEN = 1; + + /** + * The connection is not open, and the user agent is not trying to reconnect. + * @type {2} + */ + const CLOSED = 2; + + /** + * Requests for the element will have their mode set to "cors" and their credentials mode set to "same-origin". + * @type {'anonymous'} + */ + const ANONYMOUS = 'anonymous'; + + /** + * Requests for the element will have their mode set to "cors" and their credentials mode set to "include". + * @type {'use-credentials'} + */ + const USE_CREDENTIALS = 'use-credentials'; + + /** + * The EventSource interface is used to receive server-sent events. It + * connects to a server over HTTP and receives events in text/event-stream + * format without closing the connection. + * @extends {EventTarget} + * @see https://html.spec.whatwg.org/multipage/server-sent-events.html#server-sent-events + * @api public + */ + 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 = {}) { + // 1. Let ev be a new EventSource object. + 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 + }; + + // 2. Let settings be ev's relevant settings object. + // https://html.spec.whatwg.org/multipage/webappapis.html#environment-settings-object + const settings = environmentSettingsObject; + + let urlRecord; + + try { + // 3. Let urlRecord be the result of encoding-parsing a URL given url, relative to settings. + urlRecord = new URL(url, settings.settingsObject.baseUrl); + this.#state.origin = urlRecord.origin; + } catch (e) { + // 4. If urlRecord is failure, then throw a "SyntaxError" DOMException. + throw new DOMException(e, 'SyntaxError') + } + + // 5. Set ev's url to urlRecord. + this.#url = urlRecord.href; + + // 6. Let corsAttributeState be Anonymous. + let corsAttributeState = ANONYMOUS; + + // 7. If the value of eventSourceInitDict's withCredentials member is true, + // then set corsAttributeState to Use Credentials and set ev's + // withCredentials attribute to true. + if (eventSourceInitDict.withCredentials) { + corsAttributeState = USE_CREDENTIALS; + this.#withCredentials = true; + } + + // 8. Let request be the result of creating a potential-CORS request given + // urlRecord, the empty string, and corsAttributeState. + 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' + }; + + // 9. Set request's client to settings. + initRequest.client = environmentSettingsObject.settingsObject; + + // 10. User agents may set (`Accept`, `text/event-stream`) in request's header list. + initRequest.headersList = [['accept', { name: 'accept', value: 'text/event-stream' }]]; + + // 11. Set request's cache mode to "no-store". + initRequest.cache = 'no-store'; + + // 12. Set request's initiator type to "other". + initRequest.initiator = 'other'; + + initRequest.urlList = [new URL(this.#url)]; + + // 13. Set ev's request to request. + 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 + }; + + // 14. Let processEventSourceEndOfBody given response res be the following step: if res is not a network error, then reestablish the connection. + const processEventSourceEndOfBody = (response) => { + if (isNetworkError(response)) { + this.dispatchEvent(new Event('error')); + this.close(); + } + + this.#reconnect(); + }; + + // 15. Fetch request, with processResponseEndOfBody set to processEventSourceEndOfBody... + fetchParams.processResponseEndOfBody = processEventSourceEndOfBody; + + // and processResponse set to the following steps given response res: + fetchParams.processResponse = (response) => { + // 1. If res is an aborted network error, then fail the connection. + + if (isNetworkError(response)) { + // 1. When a user agent is to fail the connection, the user agent + // must queue a task which, if the readyState attribute is set to a + // value other than CLOSED, sets the readyState attribute to CLOSED + // and fires an event named error at the EventSource object. Once the + // user agent has failed the connection, it does not attempt to + // reconnect. + if (response.aborted) { + this.close(); + this.dispatchEvent(new Event('error')); + return + // 2. Otherwise, if res is a network error, then reestablish the + // connection, unless the user agent knows that to be futile, in + // which case the user agent may fail the connection. + } else { + this.#reconnect(); + return + } + } + + // 3. Otherwise, if res's status is not 200, or if res's `Content-Type` + // is not `text/event-stream`, then fail the connection. + 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 + } + + // 4. Otherwise, announce the connection and interpret res's body + // line by line. + + // When a user agent is to announce the connection, the user agent + // must queue a task which, if the readyState attribute is set to a + // value other than CLOSED, sets the readyState attribute to OPEN + // and fires an event named open at the EventSource object. + // @see https://html.spec.whatwg.org/multipage/server-sent-events.html#sse-processing-model + this.#readyState = OPEN; + this.dispatchEvent(new Event('open')); + + // If redirected to a different origin, set the origin to the new origin. + 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 () { + // When a user agent is to reestablish the connection, the user agent must + // run the following steps. These steps are run in parallel, not as part of + // a task. (The tasks that it queues, of course, are run like normal tasks + // and not themselves in parallel.) + + // 1. Queue a task to run the following steps: + + // 1. If the readyState attribute is set to CLOSED, abort the task. + if (this.#readyState === CLOSED) return + + // 2. Set the readyState attribute to CONNECTING. + this.#readyState = CONNECTING; + + // 3. Fire an event named error at the EventSource object. + this.dispatchEvent(new Event('error')); + + // 2. Wait a delay equal to the reconnection time of the event source. + await delay(this.#state.reconnectionTime); + + // 5. Queue a task to run the following steps: + + // 1. If the EventSource object's readyState attribute is not set to + // CONNECTING, then return. + if (this.#readyState !== CONNECTING) return + + // 2. Let request be the EventSource object's request. + // 3. If the EventSource object's last event ID string is not the empty + // string, then: + // 1. Let lastEventIDValue be the EventSource object's last event ID + // string, encoded as UTF-8. + // 2. Set (`Last-Event-ID`, lastEventIDValue) in request's header + // list. + if (this.#state.lastEventId.length) { + this.#request.headersList.set('last-event-id', this.#state.lastEventId, true); + } + + // 4. Fetch request and process the response obtained in this fashion, if any, as described earlier in this section. + 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; + } + } + } + + const 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 + } + ]); + + eventsource = { + EventSource, + defaultReconnectionTime + }; + return eventsource; +} + var hasRequiredUndici; function requireUndici () { @@ -24049,11 +27918,14 @@ function requireUndici () { const Client = requireClient(); const Dispatcher = requireDispatcher(); - const errors = requireErrors(); const Pool = requirePool(); const BalancedPool = requireBalancedPool(); const Agent = requireAgent(); - const util = requireUtil$7(); + const ProxyAgent = requireProxyAgent(); + const EnvHttpProxyAgent = requireEnvHttpProxyAgent(); + const RetryAgent = requireRetryAgent(); + const errors = requireErrors(); + const util = requireUtil$8(); const { InvalidArgumentError } = errors; const api = requireApi(); const buildConnector = requireConnect(); @@ -24061,21 +27933,12 @@ function requireUndici () { const MockAgent = requireMockAgent(); const MockPool = requireMockPool(); const mockErrors = requireMockErrors(); - const ProxyAgent = requireProxyAgent(); const RetryHandler = requireRetryHandler(); const { getGlobalDispatcher, setGlobalDispatcher } = requireGlobal(); const DecoratorHandler = requireDecoratorHandler(); const RedirectHandler = requireRedirectHandler(); const createRedirectInterceptor = requireRedirectInterceptor(); - let hasCrypto; - try { - require('crypto'); - hasCrypto = true; - } catch { - hasCrypto = false; - } - Object.assign(Dispatcher.prototype, api); undici.Dispatcher = Dispatcher; @@ -24084,14 +27947,26 @@ function requireUndici () { undici.BalancedPool = BalancedPool; undici.Agent = Agent; undici.ProxyAgent = ProxyAgent; + undici.EnvHttpProxyAgent = EnvHttpProxyAgent; + undici.RetryAgent = RetryAgent; undici.RetryHandler = RetryHandler; undici.DecoratorHandler = DecoratorHandler; undici.RedirectHandler = RedirectHandler; undici.createRedirectInterceptor = createRedirectInterceptor; + undici.interceptors = { + redirect: requireRedirect(), + retry: requireRetry(), + dump: requireDump(), + dns: requireDns() + }; undici.buildConnector = buildConnector; undici.errors = errors; + undici.util = { + parseHeaders: util.parseHeaders, + headerNameToString: util.headerNameToString + }; function makeDispatcher (fn) { return (url, opts, handler) => { @@ -24145,62 +28020,54 @@ function requireUndici () { undici.setGlobalDispatcher = setGlobalDispatcher; undici.getGlobalDispatcher = getGlobalDispatcher; - if (util.nodeMajor > 16 || (util.nodeMajor === 16 && util.nodeMinor >= 8)) { - let fetchImpl = null; - undici.fetch = async function fetch (resource) { - if (!fetchImpl) { - fetchImpl = requireFetch().fetch; - } - - try { - return await fetchImpl(...arguments) - } catch (err) { - if (typeof err === 'object') { - Error.captureStackTrace(err, this); - } - - throw err + const fetchImpl = requireFetch().fetch; + undici.fetch = async function fetch (init, options = undefined) { + try { + return await fetchImpl(init, options) + } catch (err) { + if (err && typeof err === 'object') { + Error.captureStackTrace(err); } - }; - undici.Headers = requireHeaders().Headers; - undici.Response = requireResponse().Response; - undici.Request = requireRequest().Request; - undici.FormData = requireFormdata().FormData; - undici.File = requireFile().File; - undici.FileReader = requireFilereader().FileReader; - const { setGlobalOrigin, getGlobalOrigin } = requireGlobal$1(); + throw err + } + }; + undici.Headers = requireHeaders().Headers; + undici.Response = requireResponse().Response; + undici.Request = requireRequest().Request; + undici.FormData = requireFormdata().FormData; + undici.File = globalThis.File ?? require$$0$2.File; + undici.FileReader = requireFilereader().FileReader; - undici.setGlobalOrigin = setGlobalOrigin; - undici.getGlobalOrigin = getGlobalOrigin; + const { setGlobalOrigin, getGlobalOrigin } = requireGlobal$1(); - const { CacheStorage } = requireCachestorage(); - const { kConstruct } = requireSymbols$1(); + undici.setGlobalOrigin = setGlobalOrigin; + undici.getGlobalOrigin = getGlobalOrigin; - // Cache & CacheStorage are tightly coupled with fetch. Even if it may run - // in an older version of Node, it doesn't have any use without fetch. - undici.caches = new CacheStorage(kConstruct); - } + const { CacheStorage } = requireCachestorage(); + const { kConstruct } = requireSymbols$1(); - if (util.nodeMajor >= 16) { - const { deleteCookie, getCookies, getSetCookies, setCookie } = requireCookies(); + // Cache & CacheStorage are tightly coupled with fetch. Even if it may run + // in an older version of Node, it doesn't have any use without fetch. + undici.caches = new CacheStorage(kConstruct); - undici.deleteCookie = deleteCookie; - undici.getCookies = getCookies; - undici.getSetCookies = getSetCookies; - undici.setCookie = setCookie; + const { deleteCookie, getCookies, getSetCookies, setCookie } = requireCookies(); - const { parseMIMEType, serializeAMimeType } = requireDataURL(); + undici.deleteCookie = deleteCookie; + undici.getCookies = getCookies; + undici.getSetCookies = getSetCookies; + undici.setCookie = setCookie; - undici.parseMIMEType = parseMIMEType; - undici.serializeAMimeType = serializeAMimeType; - } + const { parseMIMEType, serializeAMimeType } = requireDataUrl(); - if (util.nodeMajor >= 18 && hasCrypto) { - const { WebSocket } = requireWebsocket(); + undici.parseMIMEType = parseMIMEType; + undici.serializeAMimeType = serializeAMimeType; - undici.WebSocket = WebSocket; - } + const { CloseEvent, ErrorEvent, MessageEvent } = requireEvents(); + undici.WebSocket = requireWebsocket().WebSocket; + undici.CloseEvent = CloseEvent; + undici.ErrorEvent = ErrorEvent; + undici.MessageEvent = MessageEvent; undici.request = makeDispatcher(api.request); undici.stream = makeDispatcher(api.stream); @@ -24212,16 +28079,20 @@ function requireUndici () { undici.MockPool = MockPool; undici.MockAgent = MockAgent; undici.mockErrors = mockErrors; + + const { EventSource } = requireEventsource(); + + undici.EventSource = EventSource; return undici; } -var hasRequiredLib$2; +var hasRequiredLib$1; -function requireLib$2 () { - if (hasRequiredLib$2) return lib$2; - hasRequiredLib$2 = 1; +function requireLib$1 () { + if (hasRequiredLib$1) return lib$1; + hasRequiredLib$1 = 1; /* eslint-disable @typescript-eslint/no-explicit-any */ - var __createBinding = (lib$2 && lib$2.__createBinding) || (Object.create ? (function(o, m, k, k2) { + var __createBinding = (lib$1 && lib$1.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { @@ -24232,12 +28103,12 @@ function requireLib$2 () { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); - var __setModuleDefault = (lib$2 && lib$2.__setModuleDefault) || (Object.create ? (function(o, v) { + var __setModuleDefault = (lib$1 && lib$1.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); - var __importStar = (lib$2 && lib$2.__importStar) || (function () { + var __importStar = (lib$1 && lib$1.__importStar) || (function () { var ownKeys = function(o) { ownKeys = Object.getOwnPropertyNames || function (o) { var ar = []; @@ -24254,7 +28125,7 @@ function requireLib$2 () { return result; }; })(); - var __awaiter = (lib$2 && lib$2.__awaiter) || function (thisArg, _arguments, P, generator) { + var __awaiter = (lib$1 && lib$1.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } @@ -24263,13 +28134,13 @@ function requireLib$2 () { step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; - Object.defineProperty(lib$2, "__esModule", { value: true }); - lib$2.HttpClient = lib$2.HttpClientResponse = lib$2.HttpClientError = lib$2.MediaTypes = lib$2.Headers = lib$2.HttpCodes = void 0; - lib$2.getProxyUrl = getProxyUrl; - lib$2.isHttps = isHttps; - const http = __importStar(require$$2$1); - const https = __importStar(require$$1); - const pm = __importStar(requireProxy$1()); + Object.defineProperty(lib$1, "__esModule", { value: true }); + lib$1.HttpClient = lib$1.HttpClientResponse = lib$1.HttpClientError = lib$1.MediaTypes = lib$1.Headers = lib$1.HttpCodes = void 0; + lib$1.getProxyUrl = getProxyUrl; + lib$1.isHttps = isHttps; + const http = __importStar(require$$2); + const https = __importStar(require$$3); + const pm = __importStar(requireProxy()); const tunnel = __importStar(requireTunnel()); const undici_1 = requireUndici(); var HttpCodes; @@ -24301,16 +28172,16 @@ function requireLib$2 () { HttpCodes[HttpCodes["BadGateway"] = 502] = "BadGateway"; HttpCodes[HttpCodes["ServiceUnavailable"] = 503] = "ServiceUnavailable"; HttpCodes[HttpCodes["GatewayTimeout"] = 504] = "GatewayTimeout"; - })(HttpCodes || (lib$2.HttpCodes = HttpCodes = {})); + })(HttpCodes || (lib$1.HttpCodes = HttpCodes = {})); var Headers; (function (Headers) { Headers["Accept"] = "accept"; Headers["ContentType"] = "content-type"; - })(Headers || (lib$2.Headers = Headers = {})); + })(Headers || (lib$1.Headers = Headers = {})); var MediaTypes; (function (MediaTypes) { MediaTypes["ApplicationJson"] = "application/json"; - })(MediaTypes || (lib$2.MediaTypes = MediaTypes = {})); + })(MediaTypes || (lib$1.MediaTypes = MediaTypes = {})); /** * Returns the proxy URL, depending upon the supplied url and proxy environment variables. * @param serverUrl The server URL where the request will be sent. For example, https://api.github.com @@ -24342,7 +28213,7 @@ function requireLib$2 () { Object.setPrototypeOf(this, HttpClientError.prototype); } } - lib$2.HttpClientError = HttpClientError; + lib$1.HttpClientError = HttpClientError; class HttpClientResponse { constructor(message) { this.message = message; @@ -24374,7 +28245,7 @@ function requireLib$2 () { }); } } - lib$2.HttpClientResponse = HttpClientResponse; + lib$1.HttpClientResponse = HttpClientResponse; function isHttps(requestUrl) { const parsedUrl = new URL(requestUrl); return parsedUrl.protocol === 'https:'; @@ -24953,20 +28824,20 @@ function requireLib$2 () { }); } } - lib$2.HttpClient = HttpClient; + lib$1.HttpClient = HttpClient; const lowercaseKeys = (obj) => Object.keys(obj).reduce((c, k) => ((c[k.toLowerCase()] = obj[k]), c), {}); - return lib$2; + return lib$1; } -var auth$2 = {}; +var auth$1 = {}; var hasRequiredAuth; function requireAuth () { - if (hasRequiredAuth) return auth$2; + if (hasRequiredAuth) return auth$1; hasRequiredAuth = 1; - var __awaiter = (auth$2 && auth$2.__awaiter) || function (thisArg, _arguments, P, generator) { + var __awaiter = (auth$1 && auth$1.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } @@ -24975,8 +28846,8 @@ function requireAuth () { step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; - Object.defineProperty(auth$2, "__esModule", { value: true }); - auth$2.PersonalAccessTokenCredentialHandler = auth$2.BearerCredentialHandler = auth$2.BasicCredentialHandler = void 0; + Object.defineProperty(auth$1, "__esModule", { value: true }); + auth$1.PersonalAccessTokenCredentialHandler = auth$1.BearerCredentialHandler = auth$1.BasicCredentialHandler = void 0; class BasicCredentialHandler { constructor(username, password) { this.username = username; @@ -24998,7 +28869,7 @@ function requireAuth () { }); } } - auth$2.BasicCredentialHandler = BasicCredentialHandler; + auth$1.BasicCredentialHandler = BasicCredentialHandler; class BearerCredentialHandler { constructor(token) { this.token = token; @@ -25021,7 +28892,7 @@ function requireAuth () { }); } } - auth$2.BearerCredentialHandler = BearerCredentialHandler; + auth$1.BearerCredentialHandler = BearerCredentialHandler; class PersonalAccessTokenCredentialHandler { constructor(token) { this.token = token; @@ -25044,9 +28915,9 @@ function requireAuth () { }); } } - auth$2.PersonalAccessTokenCredentialHandler = PersonalAccessTokenCredentialHandler; + auth$1.PersonalAccessTokenCredentialHandler = PersonalAccessTokenCredentialHandler; - return auth$2; + return auth$1; } var hasRequiredOidcUtils; @@ -25065,7 +28936,7 @@ function requireOidcUtils () { }; Object.defineProperty(oidcUtils, "__esModule", { value: true }); oidcUtils.OidcClient = void 0; - const http_client_1 = requireLib$2(); + const http_client_1 = requireLib$1(); const auth_1 = requireAuth(); const core_1 = requireCore(); class OidcClient { @@ -25471,7 +29342,7 @@ function requirePathUtils () { pathUtils.toPosixPath = toPosixPath; pathUtils.toWin32Path = toWin32Path; pathUtils.toPlatformPath = toPlatformPath; - const path = __importStar(require$$1$5); + const path = __importStar(require$$1$6); /** * toPosixPath converts the given path to the posix form. On Windows, \\ will be * replaced with /. @@ -25575,7 +29446,7 @@ function requireIoUtil () { exports$1.tryGetExecutablePath = tryGetExecutablePath; exports$1.getCmdPath = getCmdPath; const fs$1 = __importStar(fs); - const path = __importStar(require$$1$5); + const path = __importStar(require$$1$6); _a = fs$1.promises // export const {open} = 'fs' , exports$1.chmod = _a.chmod, exports$1.copyFile = _a.copyFile, exports$1.lstat = _a.lstat, exports$1.mkdir = _a.mkdir, exports$1.open = _a.open, exports$1.readdir = _a.readdir, exports$1.rename = _a.rename, exports$1.rm = _a.rm, exports$1.rmdir = _a.rmdir, exports$1.stat = _a.stat, exports$1.symlink = _a.symlink, exports$1.unlink = _a.unlink; @@ -25804,8 +29675,8 @@ function requireIo () { io.mkdirP = mkdirP; io.which = which; io.findInPath = findInPath; - const assert_1 = require$$0$3; - const path = __importStar(require$$1$5); + const assert_1 = require$$5$4; + const path = __importStar(require$$1$6); const ioUtil = __importStar(requireIoUtil()); /** * Copies a file or folder. @@ -26120,9 +29991,9 @@ function requireToolrunner () { toolrunner.ToolRunner = void 0; toolrunner.argStringToArray = argStringToArray; const os = __importStar(require$$0); - const events = __importStar(require$$4$1); - const child = __importStar(require$$2$3); - const path = __importStar(require$$1$5); + const events = __importStar(require$$4); + const child = __importStar(require$$2$2); + const path = __importStar(require$$1$6); const io = __importStar(requireIo()); const ioUtil = __importStar(requireIoUtil()); const timers_1 = require$$6$1; @@ -26751,7 +30622,7 @@ function requireExec () { Object.defineProperty(exec, "__esModule", { value: true }); exec.exec = exec$1; exec.getExecOutput = getExecOutput; - const string_decoder_1 = require$$6; + const string_decoder_1 = require$$5$3; const tr = __importStar(requireToolrunner()); /** * Exec a command. @@ -27010,9 +30881,9 @@ function requireCore () { exports$1.getIDToken = getIDToken; const command_1 = requireCommand(); const file_command_1 = requireFileCommand(); - const utils_1 = requireUtils$4(); + const utils_1 = requireUtils$2(); const os = __importStar(require$$0); - const path = __importStar(require$$1$5); + const path = __importStar(require$$1$6); const oidc_utils_1 = requireOidcUtils(); /** * The code to exit an action @@ -27201,5026 +31072,282 @@ function requireCore () { (0, command_1.issueCommand)('debug', {}, message); } /** - * Adds an error issue - * @param message error issue message. Errors will be converted to string via toString() - * @param properties optional properties to add to the annotation. - */ - function error(message, properties = {}) { - (0, command_1.issueCommand)('error', (0, utils_1.toCommandProperties)(properties), message instanceof Error ? message.toString() : message); - } - /** - * Adds a warning issue - * @param message warning issue message. Errors will be converted to string via toString() - * @param properties optional properties to add to the annotation. - */ - function warning(message, properties = {}) { - (0, command_1.issueCommand)('warning', (0, utils_1.toCommandProperties)(properties), message instanceof Error ? message.toString() : message); - } - /** - * Adds a notice issue - * @param message notice issue message. Errors will be converted to string via toString() - * @param properties optional properties to add to the annotation. - */ - function notice(message, properties = {}) { - (0, command_1.issueCommand)('notice', (0, utils_1.toCommandProperties)(properties), message instanceof Error ? message.toString() : message); - } - /** - * Writes info to log with console.log. - * @param message info message - */ - function info(message) { - process.stdout.write(message + os.EOL); - } - /** - * Begin an output group. - * - * Output until the next `groupEnd` will be foldable in this group - * - * @param name The name of the output group - */ - function startGroup(name) { - (0, command_1.issue)('group', name); - } - /** - * End an output group. - */ - function endGroup() { - (0, command_1.issue)('endgroup'); - } - /** - * Wrap an asynchronous function call in a group. - * - * Returns the same type as the function itself. - * - * @param name The name of the group - * @param fn The function to wrap in the group - */ - function group(name, fn) { - return __awaiter(this, void 0, void 0, function* () { - startGroup(name); - let result; - try { - result = yield fn(); - } - finally { - endGroup(); - } - return result; - }); - } - //----------------------------------------------------------------------- - // Wrapper action state - //----------------------------------------------------------------------- - /** - * Saves state for current action, the state can only be retrieved by this action's post job execution. - * - * @param name name of the state to store - * @param value value to store. Non-string values will be converted to a string via JSON.stringify - */ - // eslint-disable-next-line @typescript-eslint/no-explicit-any - function saveState(name, value) { - const filePath = process.env['GITHUB_STATE'] || ''; - if (filePath) { - return (0, file_command_1.issueFileCommand)('STATE', (0, file_command_1.prepareKeyValueMessage)(name, value)); - } - (0, command_1.issueCommand)('save-state', { name }, (0, utils_1.toCommandValue)(value)); - } - /** - * Gets the value of an state set by this action's main execution. - * - * @param name name of the state to get - * @returns string - */ - function getState(name) { - return process.env[`STATE_${name}`] || ''; - } - function getIDToken(aud) { - return __awaiter(this, void 0, void 0, function* () { - return yield oidc_utils_1.OidcClient.getIDToken(aud); - }); - } - /** - * Summary exports - */ - var summary_1 = requireSummary(); - Object.defineProperty(exports$1, "summary", { enumerable: true, get: function () { return summary_1.summary; } }); - /** - * @deprecated use core.summary - */ - var summary_2 = requireSummary(); - Object.defineProperty(exports$1, "markdownSummary", { enumerable: true, get: function () { return summary_2.markdownSummary; } }); - /** - * Path exports - */ - var path_utils_1 = requirePathUtils(); - Object.defineProperty(exports$1, "toPosixPath", { enumerable: true, get: function () { return path_utils_1.toPosixPath; } }); - Object.defineProperty(exports$1, "toWin32Path", { enumerable: true, get: function () { return path_utils_1.toWin32Path; } }); - Object.defineProperty(exports$1, "toPlatformPath", { enumerable: true, get: function () { return path_utils_1.toPlatformPath; } }); - /** - * Platform utilities exports - */ - exports$1.platform = __importStar(requirePlatform()); - - } (core)); - return core; -} - -var coreExports = requireCore(); - -function getUserAgent$1() { - if (typeof navigator === "object" && "userAgent" in navigator) { - return navigator.userAgent; - } - - if (typeof process === "object" && process.version !== undefined) { - return `Node.js/${process.version.substr(1)} (${process.platform}; ${ - process.arch - })`; - } - - return ""; -} - -// @ts-check - -function register(state, name, method, options) { - if (typeof method !== "function") { - throw new Error("method for before hook must be a function"); - } - - if (!options) { - options = {}; - } - - if (Array.isArray(name)) { - return name.reverse().reduce((callback, name) => { - return register.bind(null, state, name, callback, options); - }, method)(); - } - - return Promise.resolve().then(() => { - if (!state.registry[name]) { - return method(options); - } - - return state.registry[name].reduce((method, registered) => { - return registered.hook.bind(null, method, options); - }, method)(); - }); -} - -// @ts-check - -function addHook(state, kind, name, hook) { - const orig = hook; - if (!state.registry[name]) { - state.registry[name] = []; - } - - if (kind === "before") { - hook = (method, options) => { - return Promise.resolve() - .then(orig.bind(null, options)) - .then(method.bind(null, options)); - }; - } - - if (kind === "after") { - hook = (method, options) => { - let result; - return Promise.resolve() - .then(method.bind(null, options)) - .then((result_) => { - result = result_; - return orig(result, options); - }) - .then(() => { - return result; - }); - }; - } - - if (kind === "error") { - hook = (method, options) => { - return Promise.resolve() - .then(method.bind(null, options)) - .catch((error) => { - return orig(error, options); - }); - }; - } - - state.registry[name].push({ - hook: hook, - orig: orig, - }); -} - -// @ts-check - -function removeHook(state, name, method) { - if (!state.registry[name]) { - return; - } - - const index = state.registry[name] - .map((registered) => { - return registered.orig; - }) - .indexOf(method); - - if (index === -1) { - return; - } - - state.registry[name].splice(index, 1); -} - -// @ts-check - - -// bind with array of arguments: https://stackoverflow.com/a/21792913 -const bind = Function.bind; -const bindable = bind.bind(bind); - -function bindApi(hook, state, name) { - const removeHookRef = bindable(removeHook, null).apply( - null, - [state] - ); - hook.api = { remove: removeHookRef }; - hook.remove = removeHookRef; - ["before", "error", "after", "wrap"].forEach((kind) => { - const args = [state, kind]; - hook[kind] = hook.api[kind] = bindable(addHook, null).apply(null, args); - }); -} - -function Collection$1() { - const state = { - registry: {}, - }; - - const hook = register.bind(null, state); - bindApi(hook, state); - - return hook; -} - -var Hook = { Collection: Collection$1 }; - -// pkg/dist-src/defaults.js - -// pkg/dist-src/version.js -var VERSION$d = "0.0.0-development"; - -// pkg/dist-src/defaults.js -var userAgent$1 = `octokit-endpoint.js/${VERSION$d} ${getUserAgent$1()}`; -var DEFAULTS$1 = { - method: "GET", - baseUrl: "https://api.github.com", - headers: { - accept: "application/vnd.github.v3+json", - "user-agent": userAgent$1 - }, - mediaType: { - format: "" - } -}; - -// pkg/dist-src/util/lowercase-keys.js -function lowercaseKeys$1(object) { - if (!object) { - return {}; - } - return Object.keys(object).reduce((newObj, key) => { - newObj[key.toLowerCase()] = object[key]; - return newObj; - }, {}); -} - -// pkg/dist-src/util/is-plain-object.js -function isPlainObject$3(value) { - if (typeof value !== "object" || value === null) return false; - if (Object.prototype.toString.call(value) !== "[object Object]") return false; - const proto = Object.getPrototypeOf(value); - if (proto === null) return true; - const Ctor = Object.prototype.hasOwnProperty.call(proto, "constructor") && proto.constructor; - return typeof Ctor === "function" && Ctor instanceof Ctor && Function.prototype.call(Ctor) === Function.prototype.call(value); -} - -// pkg/dist-src/util/merge-deep.js -function mergeDeep$1(defaults, options) { - const result = Object.assign({}, defaults); - Object.keys(options).forEach((key) => { - if (isPlainObject$3(options[key])) { - if (!(key in defaults)) Object.assign(result, { [key]: options[key] }); - else result[key] = mergeDeep$1(defaults[key], options[key]); - } else { - Object.assign(result, { [key]: options[key] }); - } - }); - return result; -} - -// pkg/dist-src/util/remove-undefined-properties.js -function removeUndefinedProperties$1(obj) { - for (const key in obj) { - if (obj[key] === void 0) { - delete obj[key]; - } - } - return obj; -} - -// pkg/dist-src/merge.js -function merge$2(defaults, route, options) { - if (typeof route === "string") { - let [method, url] = route.split(" "); - options = Object.assign(url ? { method, url } : { url: method }, options); - } else { - options = Object.assign({}, route); - } - options.headers = lowercaseKeys$1(options.headers); - removeUndefinedProperties$1(options); - removeUndefinedProperties$1(options.headers); - const mergedOptions = mergeDeep$1(defaults || {}, options); - if (options.url === "/graphql") { - if (defaults && defaults.mediaType.previews?.length) { - mergedOptions.mediaType.previews = defaults.mediaType.previews.filter( - (preview) => !mergedOptions.mediaType.previews.includes(preview) - ).concat(mergedOptions.mediaType.previews); - } - mergedOptions.mediaType.previews = (mergedOptions.mediaType.previews || []).map((preview) => preview.replace(/-preview/, "")); - } - return mergedOptions; -} - -// pkg/dist-src/util/add-query-parameters.js -function addQueryParameters$1(url, parameters) { - const separator = /\?/.test(url) ? "&" : "?"; - const names = Object.keys(parameters); - if (names.length === 0) { - return url; - } - return url + separator + names.map((name) => { - if (name === "q") { - return "q=" + parameters.q.split("+").map(encodeURIComponent).join("+"); - } - return `${name}=${encodeURIComponent(parameters[name])}`; - }).join("&"); -} - -// pkg/dist-src/util/extract-url-variable-names.js -var urlVariableRegex$1 = /\{[^{}}]+\}/g; -function removeNonChars$1(variableName) { - return variableName.replace(/(?:^\W+)|(?:(? a.concat(b), []); -} - -// pkg/dist-src/util/omit.js -function omit$1(object, keysToOmit) { - const result = { __proto__: null }; - for (const key of Object.keys(object)) { - if (keysToOmit.indexOf(key) === -1) { - result[key] = object[key]; - } - } - return result; -} - -// pkg/dist-src/util/url-template.js -function encodeReserved$1(str) { - return str.split(/(%[0-9A-Fa-f]{2})/g).map(function(part) { - if (!/%[0-9A-Fa-f]/.test(part)) { - part = encodeURI(part).replace(/%5B/g, "[").replace(/%5D/g, "]"); - } - return part; - }).join(""); -} -function encodeUnreserved$1(str) { - return encodeURIComponent(str).replace(/[!'()*]/g, function(c) { - return "%" + c.charCodeAt(0).toString(16).toUpperCase(); - }); -} -function encodeValue$1(operator, value, key) { - value = operator === "+" || operator === "#" ? encodeReserved$1(value) : encodeUnreserved$1(value); - if (key) { - return encodeUnreserved$1(key) + "=" + value; - } else { - return value; - } -} -function isDefined$1(value) { - return value !== void 0 && value !== null; -} -function isKeyOperator$1(operator) { - return operator === ";" || operator === "&" || operator === "?"; -} -function getValues$1(context, operator, key, modifier) { - var value = context[key], result = []; - if (isDefined$1(value) && value !== "") { - if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") { - value = value.toString(); - if (modifier && modifier !== "*") { - value = value.substring(0, parseInt(modifier, 10)); - } - result.push( - encodeValue$1(operator, value, isKeyOperator$1(operator) ? key : "") - ); - } else { - if (modifier === "*") { - if (Array.isArray(value)) { - value.filter(isDefined$1).forEach(function(value2) { - result.push( - encodeValue$1(operator, value2, isKeyOperator$1(operator) ? key : "") - ); - }); - } else { - Object.keys(value).forEach(function(k) { - if (isDefined$1(value[k])) { - result.push(encodeValue$1(operator, value[k], k)); - } - }); - } - } else { - const tmp = []; - if (Array.isArray(value)) { - value.filter(isDefined$1).forEach(function(value2) { - tmp.push(encodeValue$1(operator, value2)); - }); - } else { - Object.keys(value).forEach(function(k) { - if (isDefined$1(value[k])) { - tmp.push(encodeUnreserved$1(k)); - tmp.push(encodeValue$1(operator, value[k].toString())); - } - }); - } - if (isKeyOperator$1(operator)) { - result.push(encodeUnreserved$1(key) + "=" + tmp.join(",")); - } else if (tmp.length !== 0) { - result.push(tmp.join(",")); - } - } - } - } else { - if (operator === ";") { - if (isDefined$1(value)) { - result.push(encodeUnreserved$1(key)); - } - } else if (value === "" && (operator === "&" || operator === "?")) { - result.push(encodeUnreserved$1(key) + "="); - } else if (value === "") { - result.push(""); - } - } - return result; -} -function parseUrl$1(template) { - return { - expand: expand$1.bind(null, template) - }; -} -function expand$1(template, context) { - var operators = ["+", "#", ".", "/", ";", "?", "&"]; - template = template.replace( - /\{([^\{\}]+)\}|([^\{\}]+)/g, - function(_, expression, literal) { - if (expression) { - let operator = ""; - const values = []; - if (operators.indexOf(expression.charAt(0)) !== -1) { - operator = expression.charAt(0); - expression = expression.substr(1); - } - expression.split(/,/g).forEach(function(variable) { - var tmp = /([^:\*]*)(?::(\d+)|(\*))?/.exec(variable); - values.push(getValues$1(context, operator, tmp[1], tmp[2] || tmp[3])); - }); - if (operator && operator !== "+") { - var separator = ","; - if (operator === "?") { - separator = "&"; - } else if (operator !== "#") { - separator = operator; - } - return (values.length !== 0 ? operator : "") + values.join(separator); - } else { - return values.join(","); - } - } else { - return encodeReserved$1(literal); - } - } - ); - if (template === "/") { - return template; - } else { - return template.replace(/\/$/, ""); - } -} - -// pkg/dist-src/parse.js -function parse$2(options) { - let method = options.method.toUpperCase(); - let url = (options.url || "/").replace(/:([a-z]\w+)/g, "{$1}"); - let headers = Object.assign({}, options.headers); - let body; - let parameters = omit$1(options, [ - "method", - "baseUrl", - "url", - "headers", - "request", - "mediaType" - ]); - const urlVariableNames = extractUrlVariableNames$1(url); - url = parseUrl$1(url).expand(parameters); - if (!/^http/.test(url)) { - url = options.baseUrl + url; - } - const omittedParameters = Object.keys(options).filter((option) => urlVariableNames.includes(option)).concat("baseUrl"); - const remainingParameters = omit$1(parameters, omittedParameters); - const isBinaryRequest = /application\/octet-stream/i.test(headers.accept); - if (!isBinaryRequest) { - if (options.mediaType.format) { - headers.accept = headers.accept.split(/,/).map( - (format) => format.replace( - /application\/vnd(\.\w+)(\.v3)?(\.\w+)?(\+json)?$/, - `application/vnd$1$2.${options.mediaType.format}` - ) - ).join(","); - } - if (url.endsWith("/graphql")) { - if (options.mediaType.previews?.length) { - const previewsFromAcceptHeader = headers.accept.match(/(? { - const format = options.mediaType.format ? `.${options.mediaType.format}` : "+json"; - return `application/vnd.github.${preview}-preview${format}`; - }).join(","); - } - } - } - if (["GET", "HEAD"].includes(method)) { - url = addQueryParameters$1(url, remainingParameters); - } else { - if ("data" in remainingParameters) { - body = remainingParameters.data; - } else { - if (Object.keys(remainingParameters).length) { - body = remainingParameters; - } - } - } - if (!headers["content-type"] && typeof body !== "undefined") { - headers["content-type"] = "application/json; charset=utf-8"; - } - if (["PATCH", "PUT"].includes(method) && typeof body === "undefined") { - body = ""; - } - return Object.assign( - { method, url, headers }, - typeof body !== "undefined" ? { body } : null, - options.request ? { request: options.request } : null - ); -} - -// pkg/dist-src/endpoint-with-defaults.js -function endpointWithDefaults$1(defaults, route, options) { - return parse$2(merge$2(defaults, route, options)); -} - -// pkg/dist-src/with-defaults.js -function withDefaults$5(oldDefaults, newDefaults) { - const DEFAULTS2 = merge$2(oldDefaults, newDefaults); - const endpoint2 = endpointWithDefaults$1.bind(null, DEFAULTS2); - return Object.assign(endpoint2, { - DEFAULTS: DEFAULTS2, - defaults: withDefaults$5.bind(null, DEFAULTS2), - merge: merge$2.bind(null, DEFAULTS2), - parse: parse$2 - }); -} - -// pkg/dist-src/index.js -var endpoint$1 = withDefaults$5(null, DEFAULTS$1); - -var fastContentTypeParse = {}; - -var hasRequiredFastContentTypeParse; - -function requireFastContentTypeParse () { - if (hasRequiredFastContentTypeParse) return fastContentTypeParse; - hasRequiredFastContentTypeParse = 1; - - const NullObject = function NullObject () { }; - NullObject.prototype = Object.create(null); - - /** - * RegExp to match *( ";" parameter ) in RFC 7231 sec 3.1.1.1 - * - * parameter = token "=" ( token / quoted-string ) - * token = 1*tchar - * tchar = "!" / "#" / "$" / "%" / "&" / "'" / "*" - * / "+" / "-" / "." / "^" / "_" / "`" / "|" / "~" - * / DIGIT / ALPHA - * ; any VCHAR, except delimiters - * quoted-string = DQUOTE *( qdtext / quoted-pair ) DQUOTE - * qdtext = HTAB / SP / %x21 / %x23-5B / %x5D-7E / obs-text - * obs-text = %x80-FF - * quoted-pair = "\" ( HTAB / SP / VCHAR / obs-text ) - */ - const paramRE = /; *([!#$%&'*+.^\w`|~-]+)=("(?:[\v\u0020\u0021\u0023-\u005b\u005d-\u007e\u0080-\u00ff]|\\[\v\u0020-\u00ff])*"|[!#$%&'*+.^\w`|~-]+) */gu; - - /** - * RegExp to match quoted-pair in RFC 7230 sec 3.2.6 - * - * quoted-pair = "\" ( HTAB / SP / VCHAR / obs-text ) - * obs-text = %x80-FF - */ - const quotedPairRE = /\\([\v\u0020-\u00ff])/gu; - - /** - * RegExp to match type in RFC 7231 sec 3.1.1.1 - * - * media-type = type "/" subtype - * type = token - * subtype = token - */ - const mediaTypeRE = /^[!#$%&'*+.^\w|~-]+\/[!#$%&'*+.^\w|~-]+$/u; - - // default ContentType to prevent repeated object creation - const defaultContentType = { type: '', parameters: new NullObject() }; - Object.freeze(defaultContentType.parameters); - Object.freeze(defaultContentType); - - /** - * Parse media type to object. - * - * @param {string|object} header - * @return {Object} - * @public - */ - - function parse (header) { - if (typeof header !== 'string') { - throw new TypeError('argument header is required and must be a string') - } - - let index = header.indexOf(';'); - const type = index !== -1 - ? header.slice(0, index).trim() - : header.trim(); - - if (mediaTypeRE.test(type) === false) { - throw new TypeError('invalid media type') - } - - const result = { - type: type.toLowerCase(), - parameters: new NullObject() - }; - - // parse parameters - if (index === -1) { - return result - } - - let key; - let match; - let value; - - paramRE.lastIndex = index; - - while ((match = paramRE.exec(header))) { - if (match.index !== index) { - throw new TypeError('invalid parameter format') - } - - index += match[0].length; - key = match[1].toLowerCase(); - value = match[2]; - - if (value[0] === '"') { - // remove quotes and escapes - value = value - .slice(1, value.length - 1); - - quotedPairRE.test(value) && (value = value.replace(quotedPairRE, '$1')); - } - - result.parameters[key] = value; - } - - if (index !== header.length) { - throw new TypeError('invalid parameter format') - } - - return result - } - - function safeParse (header) { - if (typeof header !== 'string') { - return defaultContentType - } - - let index = header.indexOf(';'); - const type = index !== -1 - ? header.slice(0, index).trim() - : header.trim(); - - if (mediaTypeRE.test(type) === false) { - return defaultContentType - } - - const result = { - type: type.toLowerCase(), - parameters: new NullObject() - }; - - // parse parameters - if (index === -1) { - return result - } - - let key; - let match; - let value; - - paramRE.lastIndex = index; - - while ((match = paramRE.exec(header))) { - if (match.index !== index) { - return defaultContentType - } - - index += match[0].length; - key = match[1].toLowerCase(); - value = match[2]; - - if (value[0] === '"') { - // remove quotes and escapes - value = value - .slice(1, value.length - 1); - - quotedPairRE.test(value) && (value = value.replace(quotedPairRE, '$1')); - } - - result.parameters[key] = value; - } - - if (index !== header.length) { - return defaultContentType - } - - return result - } - - fastContentTypeParse.default = { parse, safeParse }; - fastContentTypeParse.parse = parse; - fastContentTypeParse.safeParse = safeParse; - fastContentTypeParse.defaultContentType = defaultContentType; - return fastContentTypeParse; -} - -var fastContentTypeParseExports = requireFastContentTypeParse(); - -let RequestError$1 = class RequestError extends Error { - name; - /** - * http status code - */ - status; - /** - * Request options that lead to the error. - */ - request; - /** - * Response object if a response was received - */ - response; - constructor(message, statusCode, options) { - super(message); - this.name = "HttpError"; - this.status = Number.parseInt(statusCode); - if (Number.isNaN(this.status)) { - this.status = 0; - } - if ("response" in options) { - this.response = options.response; - } - const requestCopy = Object.assign({}, options.request); - if (options.request.headers.authorization) { - requestCopy.headers = Object.assign({}, options.request.headers, { - authorization: options.request.headers.authorization.replace( - /(? [ - name, - String(value) - ]) - ); - let fetchResponse; - try { - fetchResponse = await fetch(requestOptions.url, { - method: requestOptions.method, - body, - redirect: requestOptions.request?.redirect, - headers: requestHeaders, - signal: requestOptions.request?.signal, - // duplex must be set if request.body is ReadableStream or Async Iterables. - // See https://fetch.spec.whatwg.org/#dom-requestinit-duplex. - ...requestOptions.body && { duplex: "half" } - }); - } catch (error) { - let message = "Unknown Error"; - if (error instanceof Error) { - if (error.name === "AbortError") { - error.status = 500; - throw error; - } - message = error.message; - if (error.name === "TypeError" && "cause" in error) { - if (error.cause instanceof Error) { - message = error.cause.message; - } else if (typeof error.cause === "string") { - message = error.cause; - } - } - } - const requestError = new RequestError$1(message, 500, { - request: requestOptions - }); - requestError.cause = error; - throw requestError; - } - const status = fetchResponse.status; - const url = fetchResponse.url; - const responseHeaders = {}; - for (const [key, value] of fetchResponse.headers) { - responseHeaders[key] = value; - } - const octokitResponse = { - url, - status, - headers: responseHeaders, - data: "" - }; - if ("deprecation" in responseHeaders) { - const matches = responseHeaders.link && responseHeaders.link.match(/<([^<>]+)>; rel="deprecation"/); - const deprecationLink = matches && matches.pop(); - log.warn( - `[@octokit/request] "${requestOptions.method} ${requestOptions.url}" is deprecated. It is scheduled to be removed on ${responseHeaders.sunset}${deprecationLink ? `. See ${deprecationLink}` : ""}` - ); - } - if (status === 204 || status === 205) { - return octokitResponse; - } - if (requestOptions.method === "HEAD") { - if (status < 400) { - return octokitResponse; - } - throw new RequestError$1(fetchResponse.statusText, status, { - response: octokitResponse, - request: requestOptions - }); - } - if (status === 304) { - octokitResponse.data = await getResponseData$1(fetchResponse); - throw new RequestError$1("Not modified", status, { - response: octokitResponse, - request: requestOptions - }); - } - if (status >= 400) { - octokitResponse.data = await getResponseData$1(fetchResponse); - throw new RequestError$1(toErrorMessage$1(octokitResponse.data), status, { - response: octokitResponse, - request: requestOptions - }); - } - octokitResponse.data = parseSuccessResponseBody ? await getResponseData$1(fetchResponse) : fetchResponse.body; - return octokitResponse; -} -async function getResponseData$1(response) { - const contentType = response.headers.get("content-type"); - if (!contentType) { - return response.text().catch(() => ""); - } - const mimetype = fastContentTypeParseExports.safeParse(contentType); - if (isJSONResponse(mimetype)) { - let text = ""; - try { - text = await response.text(); - return JSON.parse(text); - } catch (err) { - return text; - } - } else if (mimetype.type.startsWith("text/") || mimetype.parameters.charset?.toLowerCase() === "utf-8") { - return response.text().catch(() => ""); - } else { - return response.arrayBuffer().catch(() => new ArrayBuffer(0)); - } -} -function isJSONResponse(mimetype) { - return mimetype.type === "application/json" || mimetype.type === "application/scim+json"; -} -function toErrorMessage$1(data) { - if (typeof data === "string") { - return data; - } - if (data instanceof ArrayBuffer) { - return "Unknown error"; - } - if ("message" in data) { - const suffix = "documentation_url" in data ? ` - ${data.documentation_url}` : ""; - return Array.isArray(data.errors) ? `${data.message}: ${data.errors.map((v) => JSON.stringify(v)).join(", ")}${suffix}` : `${data.message}${suffix}`; - } - return `Unknown error: ${JSON.stringify(data)}`; -} - -// pkg/dist-src/with-defaults.js -function withDefaults$4(oldEndpoint, newDefaults) { - const endpoint2 = oldEndpoint.defaults(newDefaults); - const newApi = function(route, parameters) { - const endpointOptions = endpoint2.merge(route, parameters); - if (!endpointOptions.request || !endpointOptions.request.hook) { - return fetchWrapper$1(endpoint2.parse(endpointOptions)); - } - const request2 = (route2, parameters2) => { - return fetchWrapper$1( - endpoint2.parse(endpoint2.merge(route2, parameters2)) - ); - }; - Object.assign(request2, { - endpoint: endpoint2, - defaults: withDefaults$4.bind(null, endpoint2) - }); - return endpointOptions.request.hook(request2, endpointOptions); - }; - return Object.assign(newApi, { - endpoint: endpoint2, - defaults: withDefaults$4.bind(null, endpoint2) - }); -} - -// pkg/dist-src/index.js -var request$1 = withDefaults$4(endpoint$1, defaults_default); - -// pkg/dist-src/index.js - -// pkg/dist-src/version.js -var VERSION$b = "0.0.0-development"; - -// pkg/dist-src/error.js -function _buildMessageForResponseErrors$1(data) { - return `Request failed due to following response errors: -` + data.errors.map((e) => ` - ${e.message}`).join("\n"); -} -var GraphqlResponseError$1 = class GraphqlResponseError extends Error { - constructor(request2, headers, response) { - super(_buildMessageForResponseErrors$1(response)); - this.request = request2; - this.headers = headers; - this.response = response; - this.errors = response.errors; - this.data = response.data; - if (Error.captureStackTrace) { - Error.captureStackTrace(this, this.constructor); - } - } - name = "GraphqlResponseError"; - errors; - data; -}; - -// pkg/dist-src/graphql.js -var NON_VARIABLE_OPTIONS$1 = [ - "method", - "baseUrl", - "url", - "headers", - "request", - "query", - "mediaType", - "operationName" -]; -var FORBIDDEN_VARIABLE_OPTIONS$1 = ["query", "method", "url"]; -var GHES_V3_SUFFIX_REGEX$1 = /\/api\/v3\/?$/; -function graphql$1(request2, query, options) { - if (options) { - if (typeof query === "string" && "query" in options) { - return Promise.reject( - new Error(`[@octokit/graphql] "query" cannot be used as variable name`) - ); - } - for (const key in options) { - if (!FORBIDDEN_VARIABLE_OPTIONS$1.includes(key)) continue; - return Promise.reject( - new Error( - `[@octokit/graphql] "${key}" cannot be used as variable name` - ) - ); - } - } - const parsedOptions = typeof query === "string" ? Object.assign({ query }, options) : query; - const requestOptions = Object.keys( - parsedOptions - ).reduce((result, key) => { - if (NON_VARIABLE_OPTIONS$1.includes(key)) { - result[key] = parsedOptions[key]; - return result; - } - if (!result.variables) { - result.variables = {}; - } - result.variables[key] = parsedOptions[key]; - return result; - }, {}); - const baseUrl = parsedOptions.baseUrl || request2.endpoint.DEFAULTS.baseUrl; - if (GHES_V3_SUFFIX_REGEX$1.test(baseUrl)) { - requestOptions.url = baseUrl.replace(GHES_V3_SUFFIX_REGEX$1, "/api/graphql"); - } - return request2(requestOptions).then((response) => { - if (response.data.errors) { - const headers = {}; - for (const key of Object.keys(response.headers)) { - headers[key] = response.headers[key]; - } - throw new GraphqlResponseError$1( - requestOptions, - headers, - response.data - ); - } - return response.data.data; - }); -} - -// pkg/dist-src/with-defaults.js -function withDefaults$3(request2, newDefaults) { - const newRequest = request2.defaults(newDefaults); - const newApi = (query, options) => { - return graphql$1(newRequest, query, options); - }; - return Object.assign(newApi, { - defaults: withDefaults$3.bind(null, newRequest), - endpoint: newRequest.endpoint - }); -} - -// pkg/dist-src/index.js -withDefaults$3(request$1, { - headers: { - "user-agent": `octokit-graphql.js/${VERSION$b} ${getUserAgent$1()}` - }, - method: "POST", - url: "/graphql" -}); -function withCustomRequest$1(customRequest) { - return withDefaults$3(customRequest, { - method: "POST", - url: "/graphql" - }); -} - -// pkg/dist-src/is-jwt.js -var b64url = "(?:[a-zA-Z0-9_-]+)"; -var sep = "\\."; -var jwtRE = new RegExp(`^${b64url}${sep}${b64url}${sep}${b64url}$`); -var isJWT = jwtRE.test.bind(jwtRE); - -// pkg/dist-src/auth.js -async function auth$1(token) { - const isApp = isJWT(token); - const isInstallation = token.startsWith("v1.") || token.startsWith("ghs_"); - const isUserToServer = token.startsWith("ghu_"); - const tokenType = isApp ? "app" : isInstallation ? "installation" : isUserToServer ? "user-to-server" : "oauth"; - return { - type: "token", - token, - tokenType - }; -} - -// pkg/dist-src/with-authorization-prefix.js -function withAuthorizationPrefix$1(token) { - if (token.split(/\./).length === 3) { - return `bearer ${token}`; - } - return `token ${token}`; -} - -// pkg/dist-src/hook.js -async function hook$1(token, request, route, parameters) { - const endpoint = request.endpoint.merge( - route, - parameters - ); - endpoint.headers.authorization = withAuthorizationPrefix$1(token); - return request(endpoint); -} - -// pkg/dist-src/index.js -var createTokenAuth$1 = function createTokenAuth2(token) { - if (!token) { - throw new Error("[@octokit/auth-token] No token passed to createTokenAuth"); - } - if (typeof token !== "string") { - throw new Error( - "[@octokit/auth-token] Token passed to createTokenAuth is not a string" - ); - } - token = token.replace(/^(token|bearer) +/i, ""); - return Object.assign(auth$1.bind(null, token), { - hook: hook$1.bind(null, token) - }); -}; - -const VERSION$a = "7.0.6"; - -const noop$1 = () => { -}; -const consoleWarn$1 = console.warn.bind(console); -const consoleError$1 = console.error.bind(console); -function createLogger(logger = {}) { - if (typeof logger.debug !== "function") { - logger.debug = noop$1; - } - if (typeof logger.info !== "function") { - logger.info = noop$1; - } - if (typeof logger.warn !== "function") { - logger.warn = consoleWarn$1; - } - if (typeof logger.error !== "function") { - logger.error = consoleError$1; - } - return logger; -} -const userAgentTrail$1 = `octokit-core.js/${VERSION$a} ${getUserAgent$1()}`; -let Octokit$2 = class Octokit { - static VERSION = VERSION$a; - static defaults(defaults) { - const OctokitWithDefaults = class extends this { - constructor(...args) { - const options = args[0] || {}; - if (typeof defaults === "function") { - super(defaults(options)); - return; - } - super( - Object.assign( - {}, - defaults, - options, - options.userAgent && defaults.userAgent ? { - userAgent: `${options.userAgent} ${defaults.userAgent}` - } : null - ) - ); - } - }; - return OctokitWithDefaults; - } - static plugins = []; - /** - * Attach a plugin (or many) to your Octokit instance. - * - * @example - * const API = Octokit.plugin(plugin1, plugin2, plugin3, ...) - */ - static plugin(...newPlugins) { - const currentPlugins = this.plugins; - const NewOctokit = class extends this { - static plugins = currentPlugins.concat( - newPlugins.filter((plugin) => !currentPlugins.includes(plugin)) - ); - }; - return NewOctokit; - } - constructor(options = {}) { - const hook = new Hook.Collection(); - const requestDefaults = { - baseUrl: request$1.endpoint.DEFAULTS.baseUrl, - headers: {}, - request: Object.assign({}, options.request, { - // @ts-ignore internal usage only, no need to type - hook: hook.bind(null, "request") - }), - mediaType: { - previews: [], - format: "" - } - }; - requestDefaults.headers["user-agent"] = options.userAgent ? `${options.userAgent} ${userAgentTrail$1}` : userAgentTrail$1; - if (options.baseUrl) { - requestDefaults.baseUrl = options.baseUrl; - } - if (options.previews) { - requestDefaults.mediaType.previews = options.previews; - } - if (options.timeZone) { - requestDefaults.headers["time-zone"] = options.timeZone; - } - this.request = request$1.defaults(requestDefaults); - this.graphql = withCustomRequest$1(this.request).defaults(requestDefaults); - this.log = createLogger(options.log); - this.hook = hook; - if (!options.authStrategy) { - if (!options.auth) { - this.auth = async () => ({ - type: "unauthenticated" - }); - } else { - const auth = createTokenAuth$1(options.auth); - hook.wrap("request", auth.hook); - this.auth = auth; - } - } else { - const { authStrategy, ...otherOptions } = options; - const auth = authStrategy( - Object.assign( - { - request: this.request, - log: this.log, - // we pass the current octokit instance as well as its constructor options - // to allow for authentication strategies that return a new octokit instance - // that shares the same internal state as the current one. The original - // requirement for this was the "event-octokit" authentication strategy - // of https://github.com/probot/octokit-auth-probot. - octokit: this, - octokitOptions: otherOptions - }, - options.auth - ) - ); - hook.wrap("request", auth.hook); - this.auth = auth; - } - const classConstructor = this.constructor; - for (let i = 0; i < classConstructor.plugins.length; ++i) { - Object.assign(this, classConstructor.plugins[i](this, options)); - } - } - // assigned during constructor - request; - graphql; - log; - hook; - // TODO: type `octokit.auth` based on passed options.authStrategy - auth; -}; - -const VERSION$9 = "6.0.0"; - -function requestLog(octokit) { - octokit.hook.wrap("request", (request, options) => { - octokit.log.debug("request", options); - const start = Date.now(); - const requestOptions = octokit.request.endpoint.parse(options); - const path = requestOptions.url.replace(options.baseUrl, ""); - return request(options).then((response) => { - const requestId = response.headers["x-github-request-id"]; - octokit.log.info( - `${requestOptions.method} ${path} - ${response.status} with id ${requestId} in ${Date.now() - start}ms` - ); - return response; - }).catch((error) => { - const requestId = error.response?.headers["x-github-request-id"] || "UNKNOWN"; - octokit.log.error( - `${requestOptions.method} ${path} - ${error.status} with id ${requestId} in ${Date.now() - start}ms` - ); - throw error; - }); - }); -} -requestLog.VERSION = VERSION$9; - -// pkg/dist-src/version.js -var VERSION$8 = "0.0.0-development"; - -// pkg/dist-src/normalize-paginated-list-response.js -function normalizePaginatedListResponse$1(response) { - if (!response.data) { - return { - ...response, - data: [] - }; - } - const responseNeedsNormalization = ("total_count" in response.data || "total_commits" in response.data) && !("url" in response.data); - if (!responseNeedsNormalization) return response; - const incompleteResults = response.data.incomplete_results; - const repositorySelection = response.data.repository_selection; - const totalCount = response.data.total_count; - const totalCommits = response.data.total_commits; - delete response.data.incomplete_results; - delete response.data.repository_selection; - delete response.data.total_count; - delete response.data.total_commits; - const namespaceKey = Object.keys(response.data)[0]; - const data = response.data[namespaceKey]; - response.data = data; - if (typeof incompleteResults !== "undefined") { - response.data.incomplete_results = incompleteResults; - } - if (typeof repositorySelection !== "undefined") { - response.data.repository_selection = repositorySelection; - } - response.data.total_count = totalCount; - response.data.total_commits = totalCommits; - return response; -} - -// pkg/dist-src/iterator.js -function iterator$1(octokit, route, parameters) { - const options = typeof route === "function" ? route.endpoint(parameters) : octokit.request.endpoint(route, parameters); - const requestMethod = typeof route === "function" ? route : octokit.request; - const method = options.method; - const headers = options.headers; - let url = options.url; - return { - [Symbol.asyncIterator]: () => ({ - async next() { - if (!url) return { done: true }; - try { - const response = await requestMethod({ method, url, headers }); - const normalizedResponse = normalizePaginatedListResponse$1(response); - url = ((normalizedResponse.headers.link || "").match( - /<([^<>]+)>;\s*rel="next"/ - ) || [])[1]; - if (!url && "total_commits" in normalizedResponse.data) { - const parsedUrl = new URL(normalizedResponse.url); - const params = parsedUrl.searchParams; - const page = parseInt(params.get("page") || "1", 10); - const per_page = parseInt(params.get("per_page") || "250", 10); - if (page * per_page < normalizedResponse.data.total_commits) { - params.set("page", String(page + 1)); - url = parsedUrl.toString(); - } - } - return { value: normalizedResponse }; - } catch (error) { - if (error.status !== 409) throw error; - url = ""; - return { - value: { - status: 200, - headers: {}, - data: [] - } - }; - } - } - }) - }; -} - -// pkg/dist-src/paginate.js -function paginate$1(octokit, route, parameters, mapFn) { - if (typeof parameters === "function") { - mapFn = parameters; - parameters = void 0; - } - return gather$1( - octokit, - [], - iterator$1(octokit, route, parameters)[Symbol.asyncIterator](), - mapFn - ); -} -function gather$1(octokit, results, iterator2, mapFn) { - return iterator2.next().then((result) => { - if (result.done) { - return results; - } - let earlyExit = false; - function done() { - earlyExit = true; - } - results = results.concat( - mapFn ? mapFn(result.value, done) : result.value.data - ); - if (earlyExit) { - return results; - } - return gather$1(octokit, results, iterator2, mapFn); - }); -} - -// pkg/dist-src/compose-paginate.js -Object.assign(paginate$1, { - iterator: iterator$1 -}); - -// pkg/dist-src/index.js -function paginateRest$1(octokit) { - return { - paginate: Object.assign(paginate$1.bind(null, octokit), { - iterator: iterator$1.bind(null, octokit) - }) - }; -} -paginateRest$1.VERSION = VERSION$8; - -const VERSION$7 = "17.0.0"; - -const Endpoints$1 = { - actions: { - addCustomLabelsToSelfHostedRunnerForOrg: [ - "POST /orgs/{org}/actions/runners/{runner_id}/labels" - ], - addCustomLabelsToSelfHostedRunnerForRepo: [ - "POST /repos/{owner}/{repo}/actions/runners/{runner_id}/labels" - ], - addRepoAccessToSelfHostedRunnerGroupInOrg: [ - "PUT /orgs/{org}/actions/runner-groups/{runner_group_id}/repositories/{repository_id}" - ], - addSelectedRepoToOrgSecret: [ - "PUT /orgs/{org}/actions/secrets/{secret_name}/repositories/{repository_id}" - ], - addSelectedRepoToOrgVariable: [ - "PUT /orgs/{org}/actions/variables/{name}/repositories/{repository_id}" - ], - approveWorkflowRun: [ - "POST /repos/{owner}/{repo}/actions/runs/{run_id}/approve" - ], - cancelWorkflowRun: [ - "POST /repos/{owner}/{repo}/actions/runs/{run_id}/cancel" - ], - createEnvironmentVariable: [ - "POST /repos/{owner}/{repo}/environments/{environment_name}/variables" - ], - createHostedRunnerForOrg: ["POST /orgs/{org}/actions/hosted-runners"], - createOrUpdateEnvironmentSecret: [ - "PUT /repos/{owner}/{repo}/environments/{environment_name}/secrets/{secret_name}" - ], - createOrUpdateOrgSecret: ["PUT /orgs/{org}/actions/secrets/{secret_name}"], - createOrUpdateRepoSecret: [ - "PUT /repos/{owner}/{repo}/actions/secrets/{secret_name}" - ], - createOrgVariable: ["POST /orgs/{org}/actions/variables"], - createRegistrationTokenForOrg: [ - "POST /orgs/{org}/actions/runners/registration-token" - ], - createRegistrationTokenForRepo: [ - "POST /repos/{owner}/{repo}/actions/runners/registration-token" - ], - createRemoveTokenForOrg: ["POST /orgs/{org}/actions/runners/remove-token"], - createRemoveTokenForRepo: [ - "POST /repos/{owner}/{repo}/actions/runners/remove-token" - ], - createRepoVariable: ["POST /repos/{owner}/{repo}/actions/variables"], - createWorkflowDispatch: [ - "POST /repos/{owner}/{repo}/actions/workflows/{workflow_id}/dispatches" - ], - deleteActionsCacheById: [ - "DELETE /repos/{owner}/{repo}/actions/caches/{cache_id}" - ], - deleteActionsCacheByKey: [ - "DELETE /repos/{owner}/{repo}/actions/caches{?key,ref}" - ], - deleteArtifact: [ - "DELETE /repos/{owner}/{repo}/actions/artifacts/{artifact_id}" - ], - deleteCustomImageFromOrg: [ - "DELETE /orgs/{org}/actions/hosted-runners/images/custom/{image_definition_id}" - ], - deleteCustomImageVersionFromOrg: [ - "DELETE /orgs/{org}/actions/hosted-runners/images/custom/{image_definition_id}/versions/{version}" - ], - deleteEnvironmentSecret: [ - "DELETE /repos/{owner}/{repo}/environments/{environment_name}/secrets/{secret_name}" - ], - deleteEnvironmentVariable: [ - "DELETE /repos/{owner}/{repo}/environments/{environment_name}/variables/{name}" - ], - deleteHostedRunnerForOrg: [ - "DELETE /orgs/{org}/actions/hosted-runners/{hosted_runner_id}" - ], - deleteOrgSecret: ["DELETE /orgs/{org}/actions/secrets/{secret_name}"], - deleteOrgVariable: ["DELETE /orgs/{org}/actions/variables/{name}"], - deleteRepoSecret: [ - "DELETE /repos/{owner}/{repo}/actions/secrets/{secret_name}" - ], - deleteRepoVariable: [ - "DELETE /repos/{owner}/{repo}/actions/variables/{name}" - ], - deleteSelfHostedRunnerFromOrg: [ - "DELETE /orgs/{org}/actions/runners/{runner_id}" - ], - deleteSelfHostedRunnerFromRepo: [ - "DELETE /repos/{owner}/{repo}/actions/runners/{runner_id}" - ], - deleteWorkflowRun: ["DELETE /repos/{owner}/{repo}/actions/runs/{run_id}"], - deleteWorkflowRunLogs: [ - "DELETE /repos/{owner}/{repo}/actions/runs/{run_id}/logs" - ], - disableSelectedRepositoryGithubActionsOrganization: [ - "DELETE /orgs/{org}/actions/permissions/repositories/{repository_id}" - ], - disableWorkflow: [ - "PUT /repos/{owner}/{repo}/actions/workflows/{workflow_id}/disable" - ], - downloadArtifact: [ - "GET /repos/{owner}/{repo}/actions/artifacts/{artifact_id}/{archive_format}" - ], - downloadJobLogsForWorkflowRun: [ - "GET /repos/{owner}/{repo}/actions/jobs/{job_id}/logs" - ], - downloadWorkflowRunAttemptLogs: [ - "GET /repos/{owner}/{repo}/actions/runs/{run_id}/attempts/{attempt_number}/logs" - ], - downloadWorkflowRunLogs: [ - "GET /repos/{owner}/{repo}/actions/runs/{run_id}/logs" - ], - enableSelectedRepositoryGithubActionsOrganization: [ - "PUT /orgs/{org}/actions/permissions/repositories/{repository_id}" - ], - enableWorkflow: [ - "PUT /repos/{owner}/{repo}/actions/workflows/{workflow_id}/enable" - ], - forceCancelWorkflowRun: [ - "POST /repos/{owner}/{repo}/actions/runs/{run_id}/force-cancel" - ], - generateRunnerJitconfigForOrg: [ - "POST /orgs/{org}/actions/runners/generate-jitconfig" - ], - generateRunnerJitconfigForRepo: [ - "POST /repos/{owner}/{repo}/actions/runners/generate-jitconfig" - ], - getActionsCacheList: ["GET /repos/{owner}/{repo}/actions/caches"], - getActionsCacheUsage: ["GET /repos/{owner}/{repo}/actions/cache/usage"], - getActionsCacheUsageByRepoForOrg: [ - "GET /orgs/{org}/actions/cache/usage-by-repository" - ], - getActionsCacheUsageForOrg: ["GET /orgs/{org}/actions/cache/usage"], - getAllowedActionsOrganization: [ - "GET /orgs/{org}/actions/permissions/selected-actions" - ], - getAllowedActionsRepository: [ - "GET /repos/{owner}/{repo}/actions/permissions/selected-actions" - ], - getArtifact: ["GET /repos/{owner}/{repo}/actions/artifacts/{artifact_id}"], - getCustomImageForOrg: [ - "GET /orgs/{org}/actions/hosted-runners/images/custom/{image_definition_id}" - ], - getCustomImageVersionForOrg: [ - "GET /orgs/{org}/actions/hosted-runners/images/custom/{image_definition_id}/versions/{version}" - ], - getCustomOidcSubClaimForRepo: [ - "GET /repos/{owner}/{repo}/actions/oidc/customization/sub" - ], - getEnvironmentPublicKey: [ - "GET /repos/{owner}/{repo}/environments/{environment_name}/secrets/public-key" - ], - getEnvironmentSecret: [ - "GET /repos/{owner}/{repo}/environments/{environment_name}/secrets/{secret_name}" - ], - getEnvironmentVariable: [ - "GET /repos/{owner}/{repo}/environments/{environment_name}/variables/{name}" - ], - getGithubActionsDefaultWorkflowPermissionsOrganization: [ - "GET /orgs/{org}/actions/permissions/workflow" - ], - getGithubActionsDefaultWorkflowPermissionsRepository: [ - "GET /repos/{owner}/{repo}/actions/permissions/workflow" - ], - getGithubActionsPermissionsOrganization: [ - "GET /orgs/{org}/actions/permissions" - ], - getGithubActionsPermissionsRepository: [ - "GET /repos/{owner}/{repo}/actions/permissions" - ], - getHostedRunnerForOrg: [ - "GET /orgs/{org}/actions/hosted-runners/{hosted_runner_id}" - ], - getHostedRunnersGithubOwnedImagesForOrg: [ - "GET /orgs/{org}/actions/hosted-runners/images/github-owned" - ], - getHostedRunnersLimitsForOrg: [ - "GET /orgs/{org}/actions/hosted-runners/limits" - ], - getHostedRunnersMachineSpecsForOrg: [ - "GET /orgs/{org}/actions/hosted-runners/machine-sizes" - ], - getHostedRunnersPartnerImagesForOrg: [ - "GET /orgs/{org}/actions/hosted-runners/images/partner" - ], - getHostedRunnersPlatformsForOrg: [ - "GET /orgs/{org}/actions/hosted-runners/platforms" - ], - getJobForWorkflowRun: ["GET /repos/{owner}/{repo}/actions/jobs/{job_id}"], - getOrgPublicKey: ["GET /orgs/{org}/actions/secrets/public-key"], - getOrgSecret: ["GET /orgs/{org}/actions/secrets/{secret_name}"], - getOrgVariable: ["GET /orgs/{org}/actions/variables/{name}"], - getPendingDeploymentsForRun: [ - "GET /repos/{owner}/{repo}/actions/runs/{run_id}/pending_deployments" - ], - getRepoPermissions: [ - "GET /repos/{owner}/{repo}/actions/permissions", - {}, - { renamed: ["actions", "getGithubActionsPermissionsRepository"] } - ], - getRepoPublicKey: ["GET /repos/{owner}/{repo}/actions/secrets/public-key"], - getRepoSecret: ["GET /repos/{owner}/{repo}/actions/secrets/{secret_name}"], - getRepoVariable: ["GET /repos/{owner}/{repo}/actions/variables/{name}"], - getReviewsForRun: [ - "GET /repos/{owner}/{repo}/actions/runs/{run_id}/approvals" - ], - getSelfHostedRunnerForOrg: ["GET /orgs/{org}/actions/runners/{runner_id}"], - getSelfHostedRunnerForRepo: [ - "GET /repos/{owner}/{repo}/actions/runners/{runner_id}" - ], - getWorkflow: ["GET /repos/{owner}/{repo}/actions/workflows/{workflow_id}"], - getWorkflowAccessToRepository: [ - "GET /repos/{owner}/{repo}/actions/permissions/access" - ], - getWorkflowRun: ["GET /repos/{owner}/{repo}/actions/runs/{run_id}"], - getWorkflowRunAttempt: [ - "GET /repos/{owner}/{repo}/actions/runs/{run_id}/attempts/{attempt_number}" - ], - getWorkflowRunUsage: [ - "GET /repos/{owner}/{repo}/actions/runs/{run_id}/timing" - ], - getWorkflowUsage: [ - "GET /repos/{owner}/{repo}/actions/workflows/{workflow_id}/timing" - ], - listArtifactsForRepo: ["GET /repos/{owner}/{repo}/actions/artifacts"], - listCustomImageVersionsForOrg: [ - "GET /orgs/{org}/actions/hosted-runners/images/custom/{image_definition_id}/versions" - ], - listCustomImagesForOrg: [ - "GET /orgs/{org}/actions/hosted-runners/images/custom" - ], - listEnvironmentSecrets: [ - "GET /repos/{owner}/{repo}/environments/{environment_name}/secrets" - ], - listEnvironmentVariables: [ - "GET /repos/{owner}/{repo}/environments/{environment_name}/variables" - ], - listGithubHostedRunnersInGroupForOrg: [ - "GET /orgs/{org}/actions/runner-groups/{runner_group_id}/hosted-runners" - ], - listHostedRunnersForOrg: ["GET /orgs/{org}/actions/hosted-runners"], - listJobsForWorkflowRun: [ - "GET /repos/{owner}/{repo}/actions/runs/{run_id}/jobs" - ], - listJobsForWorkflowRunAttempt: [ - "GET /repos/{owner}/{repo}/actions/runs/{run_id}/attempts/{attempt_number}/jobs" - ], - listLabelsForSelfHostedRunnerForOrg: [ - "GET /orgs/{org}/actions/runners/{runner_id}/labels" - ], - listLabelsForSelfHostedRunnerForRepo: [ - "GET /repos/{owner}/{repo}/actions/runners/{runner_id}/labels" - ], - listOrgSecrets: ["GET /orgs/{org}/actions/secrets"], - listOrgVariables: ["GET /orgs/{org}/actions/variables"], - listRepoOrganizationSecrets: [ - "GET /repos/{owner}/{repo}/actions/organization-secrets" - ], - listRepoOrganizationVariables: [ - "GET /repos/{owner}/{repo}/actions/organization-variables" - ], - listRepoSecrets: ["GET /repos/{owner}/{repo}/actions/secrets"], - listRepoVariables: ["GET /repos/{owner}/{repo}/actions/variables"], - listRepoWorkflows: ["GET /repos/{owner}/{repo}/actions/workflows"], - listRunnerApplicationsForOrg: ["GET /orgs/{org}/actions/runners/downloads"], - listRunnerApplicationsForRepo: [ - "GET /repos/{owner}/{repo}/actions/runners/downloads" - ], - listSelectedReposForOrgSecret: [ - "GET /orgs/{org}/actions/secrets/{secret_name}/repositories" - ], - listSelectedReposForOrgVariable: [ - "GET /orgs/{org}/actions/variables/{name}/repositories" - ], - listSelectedRepositoriesEnabledGithubActionsOrganization: [ - "GET /orgs/{org}/actions/permissions/repositories" - ], - listSelfHostedRunnersForOrg: ["GET /orgs/{org}/actions/runners"], - listSelfHostedRunnersForRepo: ["GET /repos/{owner}/{repo}/actions/runners"], - listWorkflowRunArtifacts: [ - "GET /repos/{owner}/{repo}/actions/runs/{run_id}/artifacts" - ], - listWorkflowRuns: [ - "GET /repos/{owner}/{repo}/actions/workflows/{workflow_id}/runs" - ], - listWorkflowRunsForRepo: ["GET /repos/{owner}/{repo}/actions/runs"], - reRunJobForWorkflowRun: [ - "POST /repos/{owner}/{repo}/actions/jobs/{job_id}/rerun" - ], - reRunWorkflow: ["POST /repos/{owner}/{repo}/actions/runs/{run_id}/rerun"], - reRunWorkflowFailedJobs: [ - "POST /repos/{owner}/{repo}/actions/runs/{run_id}/rerun-failed-jobs" - ], - removeAllCustomLabelsFromSelfHostedRunnerForOrg: [ - "DELETE /orgs/{org}/actions/runners/{runner_id}/labels" - ], - removeAllCustomLabelsFromSelfHostedRunnerForRepo: [ - "DELETE /repos/{owner}/{repo}/actions/runners/{runner_id}/labels" - ], - removeCustomLabelFromSelfHostedRunnerForOrg: [ - "DELETE /orgs/{org}/actions/runners/{runner_id}/labels/{name}" - ], - removeCustomLabelFromSelfHostedRunnerForRepo: [ - "DELETE /repos/{owner}/{repo}/actions/runners/{runner_id}/labels/{name}" - ], - removeSelectedRepoFromOrgSecret: [ - "DELETE /orgs/{org}/actions/secrets/{secret_name}/repositories/{repository_id}" - ], - removeSelectedRepoFromOrgVariable: [ - "DELETE /orgs/{org}/actions/variables/{name}/repositories/{repository_id}" - ], - reviewCustomGatesForRun: [ - "POST /repos/{owner}/{repo}/actions/runs/{run_id}/deployment_protection_rule" - ], - reviewPendingDeploymentsForRun: [ - "POST /repos/{owner}/{repo}/actions/runs/{run_id}/pending_deployments" - ], - setAllowedActionsOrganization: [ - "PUT /orgs/{org}/actions/permissions/selected-actions" - ], - setAllowedActionsRepository: [ - "PUT /repos/{owner}/{repo}/actions/permissions/selected-actions" - ], - setCustomLabelsForSelfHostedRunnerForOrg: [ - "PUT /orgs/{org}/actions/runners/{runner_id}/labels" - ], - setCustomLabelsForSelfHostedRunnerForRepo: [ - "PUT /repos/{owner}/{repo}/actions/runners/{runner_id}/labels" - ], - setCustomOidcSubClaimForRepo: [ - "PUT /repos/{owner}/{repo}/actions/oidc/customization/sub" - ], - setGithubActionsDefaultWorkflowPermissionsOrganization: [ - "PUT /orgs/{org}/actions/permissions/workflow" - ], - setGithubActionsDefaultWorkflowPermissionsRepository: [ - "PUT /repos/{owner}/{repo}/actions/permissions/workflow" - ], - setGithubActionsPermissionsOrganization: [ - "PUT /orgs/{org}/actions/permissions" - ], - setGithubActionsPermissionsRepository: [ - "PUT /repos/{owner}/{repo}/actions/permissions" - ], - setSelectedReposForOrgSecret: [ - "PUT /orgs/{org}/actions/secrets/{secret_name}/repositories" - ], - setSelectedReposForOrgVariable: [ - "PUT /orgs/{org}/actions/variables/{name}/repositories" - ], - setSelectedRepositoriesEnabledGithubActionsOrganization: [ - "PUT /orgs/{org}/actions/permissions/repositories" - ], - setWorkflowAccessToRepository: [ - "PUT /repos/{owner}/{repo}/actions/permissions/access" - ], - updateEnvironmentVariable: [ - "PATCH /repos/{owner}/{repo}/environments/{environment_name}/variables/{name}" - ], - updateHostedRunnerForOrg: [ - "PATCH /orgs/{org}/actions/hosted-runners/{hosted_runner_id}" - ], - updateOrgVariable: ["PATCH /orgs/{org}/actions/variables/{name}"], - updateRepoVariable: [ - "PATCH /repos/{owner}/{repo}/actions/variables/{name}" - ] - }, - activity: { - checkRepoIsStarredByAuthenticatedUser: ["GET /user/starred/{owner}/{repo}"], - deleteRepoSubscription: ["DELETE /repos/{owner}/{repo}/subscription"], - deleteThreadSubscription: [ - "DELETE /notifications/threads/{thread_id}/subscription" - ], - getFeeds: ["GET /feeds"], - getRepoSubscription: ["GET /repos/{owner}/{repo}/subscription"], - getThread: ["GET /notifications/threads/{thread_id}"], - getThreadSubscriptionForAuthenticatedUser: [ - "GET /notifications/threads/{thread_id}/subscription" - ], - listEventsForAuthenticatedUser: ["GET /users/{username}/events"], - listNotificationsForAuthenticatedUser: ["GET /notifications"], - listOrgEventsForAuthenticatedUser: [ - "GET /users/{username}/events/orgs/{org}" - ], - listPublicEvents: ["GET /events"], - listPublicEventsForRepoNetwork: ["GET /networks/{owner}/{repo}/events"], - listPublicEventsForUser: ["GET /users/{username}/events/public"], - listPublicOrgEvents: ["GET /orgs/{org}/events"], - listReceivedEventsForUser: ["GET /users/{username}/received_events"], - listReceivedPublicEventsForUser: [ - "GET /users/{username}/received_events/public" - ], - listRepoEvents: ["GET /repos/{owner}/{repo}/events"], - listRepoNotificationsForAuthenticatedUser: [ - "GET /repos/{owner}/{repo}/notifications" - ], - listReposStarredByAuthenticatedUser: ["GET /user/starred"], - listReposStarredByUser: ["GET /users/{username}/starred"], - listReposWatchedByUser: ["GET /users/{username}/subscriptions"], - listStargazersForRepo: ["GET /repos/{owner}/{repo}/stargazers"], - listWatchedReposForAuthenticatedUser: ["GET /user/subscriptions"], - listWatchersForRepo: ["GET /repos/{owner}/{repo}/subscribers"], - markNotificationsAsRead: ["PUT /notifications"], - markRepoNotificationsAsRead: ["PUT /repos/{owner}/{repo}/notifications"], - markThreadAsDone: ["DELETE /notifications/threads/{thread_id}"], - markThreadAsRead: ["PATCH /notifications/threads/{thread_id}"], - setRepoSubscription: ["PUT /repos/{owner}/{repo}/subscription"], - setThreadSubscription: [ - "PUT /notifications/threads/{thread_id}/subscription" - ], - starRepoForAuthenticatedUser: ["PUT /user/starred/{owner}/{repo}"], - unstarRepoForAuthenticatedUser: ["DELETE /user/starred/{owner}/{repo}"] - }, - apps: { - addRepoToInstallation: [ - "PUT /user/installations/{installation_id}/repositories/{repository_id}", - {}, - { renamed: ["apps", "addRepoToInstallationForAuthenticatedUser"] } - ], - addRepoToInstallationForAuthenticatedUser: [ - "PUT /user/installations/{installation_id}/repositories/{repository_id}" - ], - checkToken: ["POST /applications/{client_id}/token"], - createFromManifest: ["POST /app-manifests/{code}/conversions"], - createInstallationAccessToken: [ - "POST /app/installations/{installation_id}/access_tokens" - ], - deleteAuthorization: ["DELETE /applications/{client_id}/grant"], - deleteInstallation: ["DELETE /app/installations/{installation_id}"], - deleteToken: ["DELETE /applications/{client_id}/token"], - getAuthenticated: ["GET /app"], - getBySlug: ["GET /apps/{app_slug}"], - getInstallation: ["GET /app/installations/{installation_id}"], - getOrgInstallation: ["GET /orgs/{org}/installation"], - getRepoInstallation: ["GET /repos/{owner}/{repo}/installation"], - getSubscriptionPlanForAccount: [ - "GET /marketplace_listing/accounts/{account_id}" - ], - getSubscriptionPlanForAccountStubbed: [ - "GET /marketplace_listing/stubbed/accounts/{account_id}" - ], - getUserInstallation: ["GET /users/{username}/installation"], - getWebhookConfigForApp: ["GET /app/hook/config"], - getWebhookDelivery: ["GET /app/hook/deliveries/{delivery_id}"], - listAccountsForPlan: ["GET /marketplace_listing/plans/{plan_id}/accounts"], - listAccountsForPlanStubbed: [ - "GET /marketplace_listing/stubbed/plans/{plan_id}/accounts" - ], - listInstallationReposForAuthenticatedUser: [ - "GET /user/installations/{installation_id}/repositories" - ], - listInstallationRequestsForAuthenticatedApp: [ - "GET /app/installation-requests" - ], - listInstallations: ["GET /app/installations"], - listInstallationsForAuthenticatedUser: ["GET /user/installations"], - listPlans: ["GET /marketplace_listing/plans"], - listPlansStubbed: ["GET /marketplace_listing/stubbed/plans"], - listReposAccessibleToInstallation: ["GET /installation/repositories"], - listSubscriptionsForAuthenticatedUser: ["GET /user/marketplace_purchases"], - listSubscriptionsForAuthenticatedUserStubbed: [ - "GET /user/marketplace_purchases/stubbed" - ], - listWebhookDeliveries: ["GET /app/hook/deliveries"], - redeliverWebhookDelivery: [ - "POST /app/hook/deliveries/{delivery_id}/attempts" - ], - removeRepoFromInstallation: [ - "DELETE /user/installations/{installation_id}/repositories/{repository_id}", - {}, - { renamed: ["apps", "removeRepoFromInstallationForAuthenticatedUser"] } - ], - removeRepoFromInstallationForAuthenticatedUser: [ - "DELETE /user/installations/{installation_id}/repositories/{repository_id}" - ], - resetToken: ["PATCH /applications/{client_id}/token"], - revokeInstallationAccessToken: ["DELETE /installation/token"], - scopeToken: ["POST /applications/{client_id}/token/scoped"], - suspendInstallation: ["PUT /app/installations/{installation_id}/suspended"], - unsuspendInstallation: [ - "DELETE /app/installations/{installation_id}/suspended" - ], - updateWebhookConfigForApp: ["PATCH /app/hook/config"] - }, - billing: { - getGithubActionsBillingOrg: ["GET /orgs/{org}/settings/billing/actions"], - getGithubActionsBillingUser: [ - "GET /users/{username}/settings/billing/actions" - ], - getGithubBillingPremiumRequestUsageReportOrg: [ - "GET /organizations/{org}/settings/billing/premium_request/usage" - ], - getGithubBillingPremiumRequestUsageReportUser: [ - "GET /users/{username}/settings/billing/premium_request/usage" - ], - getGithubBillingUsageReportOrg: [ - "GET /organizations/{org}/settings/billing/usage" - ], - getGithubBillingUsageReportUser: [ - "GET /users/{username}/settings/billing/usage" - ], - getGithubPackagesBillingOrg: ["GET /orgs/{org}/settings/billing/packages"], - getGithubPackagesBillingUser: [ - "GET /users/{username}/settings/billing/packages" - ], - getSharedStorageBillingOrg: [ - "GET /orgs/{org}/settings/billing/shared-storage" - ], - getSharedStorageBillingUser: [ - "GET /users/{username}/settings/billing/shared-storage" - ] - }, - campaigns: { - createCampaign: ["POST /orgs/{org}/campaigns"], - deleteCampaign: ["DELETE /orgs/{org}/campaigns/{campaign_number}"], - getCampaignSummary: ["GET /orgs/{org}/campaigns/{campaign_number}"], - listOrgCampaigns: ["GET /orgs/{org}/campaigns"], - updateCampaign: ["PATCH /orgs/{org}/campaigns/{campaign_number}"] - }, - checks: { - create: ["POST /repos/{owner}/{repo}/check-runs"], - createSuite: ["POST /repos/{owner}/{repo}/check-suites"], - get: ["GET /repos/{owner}/{repo}/check-runs/{check_run_id}"], - getSuite: ["GET /repos/{owner}/{repo}/check-suites/{check_suite_id}"], - listAnnotations: [ - "GET /repos/{owner}/{repo}/check-runs/{check_run_id}/annotations" - ], - listForRef: ["GET /repos/{owner}/{repo}/commits/{ref}/check-runs"], - listForSuite: [ - "GET /repos/{owner}/{repo}/check-suites/{check_suite_id}/check-runs" - ], - listSuitesForRef: ["GET /repos/{owner}/{repo}/commits/{ref}/check-suites"], - rerequestRun: [ - "POST /repos/{owner}/{repo}/check-runs/{check_run_id}/rerequest" - ], - rerequestSuite: [ - "POST /repos/{owner}/{repo}/check-suites/{check_suite_id}/rerequest" - ], - setSuitesPreferences: [ - "PATCH /repos/{owner}/{repo}/check-suites/preferences" - ], - update: ["PATCH /repos/{owner}/{repo}/check-runs/{check_run_id}"] - }, - codeScanning: { - commitAutofix: [ - "POST /repos/{owner}/{repo}/code-scanning/alerts/{alert_number}/autofix/commits" - ], - createAutofix: [ - "POST /repos/{owner}/{repo}/code-scanning/alerts/{alert_number}/autofix" - ], - createVariantAnalysis: [ - "POST /repos/{owner}/{repo}/code-scanning/codeql/variant-analyses" - ], - deleteAnalysis: [ - "DELETE /repos/{owner}/{repo}/code-scanning/analyses/{analysis_id}{?confirm_delete}" - ], - deleteCodeqlDatabase: [ - "DELETE /repos/{owner}/{repo}/code-scanning/codeql/databases/{language}" - ], - getAlert: [ - "GET /repos/{owner}/{repo}/code-scanning/alerts/{alert_number}", - {}, - { renamedParameters: { alert_id: "alert_number" } } - ], - getAnalysis: [ - "GET /repos/{owner}/{repo}/code-scanning/analyses/{analysis_id}" - ], - getAutofix: [ - "GET /repos/{owner}/{repo}/code-scanning/alerts/{alert_number}/autofix" - ], - getCodeqlDatabase: [ - "GET /repos/{owner}/{repo}/code-scanning/codeql/databases/{language}" - ], - getDefaultSetup: ["GET /repos/{owner}/{repo}/code-scanning/default-setup"], - getSarif: ["GET /repos/{owner}/{repo}/code-scanning/sarifs/{sarif_id}"], - getVariantAnalysis: [ - "GET /repos/{owner}/{repo}/code-scanning/codeql/variant-analyses/{codeql_variant_analysis_id}" - ], - getVariantAnalysisRepoTask: [ - "GET /repos/{owner}/{repo}/code-scanning/codeql/variant-analyses/{codeql_variant_analysis_id}/repos/{repo_owner}/{repo_name}" - ], - listAlertInstances: [ - "GET /repos/{owner}/{repo}/code-scanning/alerts/{alert_number}/instances" - ], - listAlertsForOrg: ["GET /orgs/{org}/code-scanning/alerts"], - listAlertsForRepo: ["GET /repos/{owner}/{repo}/code-scanning/alerts"], - listAlertsInstances: [ - "GET /repos/{owner}/{repo}/code-scanning/alerts/{alert_number}/instances", - {}, - { renamed: ["codeScanning", "listAlertInstances"] } - ], - listCodeqlDatabases: [ - "GET /repos/{owner}/{repo}/code-scanning/codeql/databases" - ], - listRecentAnalyses: ["GET /repos/{owner}/{repo}/code-scanning/analyses"], - updateAlert: [ - "PATCH /repos/{owner}/{repo}/code-scanning/alerts/{alert_number}" - ], - updateDefaultSetup: [ - "PATCH /repos/{owner}/{repo}/code-scanning/default-setup" - ], - uploadSarif: ["POST /repos/{owner}/{repo}/code-scanning/sarifs"] - }, - codeSecurity: { - attachConfiguration: [ - "POST /orgs/{org}/code-security/configurations/{configuration_id}/attach" - ], - attachEnterpriseConfiguration: [ - "POST /enterprises/{enterprise}/code-security/configurations/{configuration_id}/attach" - ], - createConfiguration: ["POST /orgs/{org}/code-security/configurations"], - createConfigurationForEnterprise: [ - "POST /enterprises/{enterprise}/code-security/configurations" - ], - deleteConfiguration: [ - "DELETE /orgs/{org}/code-security/configurations/{configuration_id}" - ], - deleteConfigurationForEnterprise: [ - "DELETE /enterprises/{enterprise}/code-security/configurations/{configuration_id}" - ], - detachConfiguration: [ - "DELETE /orgs/{org}/code-security/configurations/detach" - ], - getConfiguration: [ - "GET /orgs/{org}/code-security/configurations/{configuration_id}" - ], - getConfigurationForRepository: [ - "GET /repos/{owner}/{repo}/code-security-configuration" - ], - getConfigurationsForEnterprise: [ - "GET /enterprises/{enterprise}/code-security/configurations" - ], - getConfigurationsForOrg: ["GET /orgs/{org}/code-security/configurations"], - getDefaultConfigurations: [ - "GET /orgs/{org}/code-security/configurations/defaults" - ], - getDefaultConfigurationsForEnterprise: [ - "GET /enterprises/{enterprise}/code-security/configurations/defaults" - ], - getRepositoriesForConfiguration: [ - "GET /orgs/{org}/code-security/configurations/{configuration_id}/repositories" - ], - getRepositoriesForEnterpriseConfiguration: [ - "GET /enterprises/{enterprise}/code-security/configurations/{configuration_id}/repositories" - ], - getSingleConfigurationForEnterprise: [ - "GET /enterprises/{enterprise}/code-security/configurations/{configuration_id}" - ], - setConfigurationAsDefault: [ - "PUT /orgs/{org}/code-security/configurations/{configuration_id}/defaults" - ], - setConfigurationAsDefaultForEnterprise: [ - "PUT /enterprises/{enterprise}/code-security/configurations/{configuration_id}/defaults" - ], - updateConfiguration: [ - "PATCH /orgs/{org}/code-security/configurations/{configuration_id}" - ], - updateEnterpriseConfiguration: [ - "PATCH /enterprises/{enterprise}/code-security/configurations/{configuration_id}" - ] - }, - codesOfConduct: { - getAllCodesOfConduct: ["GET /codes_of_conduct"], - getConductCode: ["GET /codes_of_conduct/{key}"] - }, - codespaces: { - addRepositoryForSecretForAuthenticatedUser: [ - "PUT /user/codespaces/secrets/{secret_name}/repositories/{repository_id}" - ], - addSelectedRepoToOrgSecret: [ - "PUT /orgs/{org}/codespaces/secrets/{secret_name}/repositories/{repository_id}" - ], - checkPermissionsForDevcontainer: [ - "GET /repos/{owner}/{repo}/codespaces/permissions_check" - ], - codespaceMachinesForAuthenticatedUser: [ - "GET /user/codespaces/{codespace_name}/machines" - ], - createForAuthenticatedUser: ["POST /user/codespaces"], - createOrUpdateOrgSecret: [ - "PUT /orgs/{org}/codespaces/secrets/{secret_name}" - ], - createOrUpdateRepoSecret: [ - "PUT /repos/{owner}/{repo}/codespaces/secrets/{secret_name}" - ], - createOrUpdateSecretForAuthenticatedUser: [ - "PUT /user/codespaces/secrets/{secret_name}" - ], - createWithPrForAuthenticatedUser: [ - "POST /repos/{owner}/{repo}/pulls/{pull_number}/codespaces" - ], - createWithRepoForAuthenticatedUser: [ - "POST /repos/{owner}/{repo}/codespaces" - ], - deleteForAuthenticatedUser: ["DELETE /user/codespaces/{codespace_name}"], - deleteFromOrganization: [ - "DELETE /orgs/{org}/members/{username}/codespaces/{codespace_name}" - ], - deleteOrgSecret: ["DELETE /orgs/{org}/codespaces/secrets/{secret_name}"], - deleteRepoSecret: [ - "DELETE /repos/{owner}/{repo}/codespaces/secrets/{secret_name}" - ], - deleteSecretForAuthenticatedUser: [ - "DELETE /user/codespaces/secrets/{secret_name}" - ], - exportForAuthenticatedUser: [ - "POST /user/codespaces/{codespace_name}/exports" - ], - getCodespacesForUserInOrg: [ - "GET /orgs/{org}/members/{username}/codespaces" - ], - getExportDetailsForAuthenticatedUser: [ - "GET /user/codespaces/{codespace_name}/exports/{export_id}" - ], - getForAuthenticatedUser: ["GET /user/codespaces/{codespace_name}"], - getOrgPublicKey: ["GET /orgs/{org}/codespaces/secrets/public-key"], - getOrgSecret: ["GET /orgs/{org}/codespaces/secrets/{secret_name}"], - getPublicKeyForAuthenticatedUser: [ - "GET /user/codespaces/secrets/public-key" - ], - getRepoPublicKey: [ - "GET /repos/{owner}/{repo}/codespaces/secrets/public-key" - ], - getRepoSecret: [ - "GET /repos/{owner}/{repo}/codespaces/secrets/{secret_name}" - ], - getSecretForAuthenticatedUser: [ - "GET /user/codespaces/secrets/{secret_name}" - ], - listDevcontainersInRepositoryForAuthenticatedUser: [ - "GET /repos/{owner}/{repo}/codespaces/devcontainers" - ], - listForAuthenticatedUser: ["GET /user/codespaces"], - listInOrganization: [ - "GET /orgs/{org}/codespaces", - {}, - { renamedParameters: { org_id: "org" } } - ], - listInRepositoryForAuthenticatedUser: [ - "GET /repos/{owner}/{repo}/codespaces" - ], - listOrgSecrets: ["GET /orgs/{org}/codespaces/secrets"], - listRepoSecrets: ["GET /repos/{owner}/{repo}/codespaces/secrets"], - listRepositoriesForSecretForAuthenticatedUser: [ - "GET /user/codespaces/secrets/{secret_name}/repositories" - ], - listSecretsForAuthenticatedUser: ["GET /user/codespaces/secrets"], - listSelectedReposForOrgSecret: [ - "GET /orgs/{org}/codespaces/secrets/{secret_name}/repositories" - ], - preFlightWithRepoForAuthenticatedUser: [ - "GET /repos/{owner}/{repo}/codespaces/new" - ], - publishForAuthenticatedUser: [ - "POST /user/codespaces/{codespace_name}/publish" - ], - removeRepositoryForSecretForAuthenticatedUser: [ - "DELETE /user/codespaces/secrets/{secret_name}/repositories/{repository_id}" - ], - removeSelectedRepoFromOrgSecret: [ - "DELETE /orgs/{org}/codespaces/secrets/{secret_name}/repositories/{repository_id}" - ], - repoMachinesForAuthenticatedUser: [ - "GET /repos/{owner}/{repo}/codespaces/machines" - ], - setRepositoriesForSecretForAuthenticatedUser: [ - "PUT /user/codespaces/secrets/{secret_name}/repositories" - ], - setSelectedReposForOrgSecret: [ - "PUT /orgs/{org}/codespaces/secrets/{secret_name}/repositories" - ], - startForAuthenticatedUser: ["POST /user/codespaces/{codespace_name}/start"], - stopForAuthenticatedUser: ["POST /user/codespaces/{codespace_name}/stop"], - stopInOrganization: [ - "POST /orgs/{org}/members/{username}/codespaces/{codespace_name}/stop" - ], - updateForAuthenticatedUser: ["PATCH /user/codespaces/{codespace_name}"] - }, - copilot: { - addCopilotSeatsForTeams: [ - "POST /orgs/{org}/copilot/billing/selected_teams" - ], - addCopilotSeatsForUsers: [ - "POST /orgs/{org}/copilot/billing/selected_users" - ], - cancelCopilotSeatAssignmentForTeams: [ - "DELETE /orgs/{org}/copilot/billing/selected_teams" - ], - cancelCopilotSeatAssignmentForUsers: [ - "DELETE /orgs/{org}/copilot/billing/selected_users" - ], - copilotMetricsForOrganization: ["GET /orgs/{org}/copilot/metrics"], - copilotMetricsForTeam: ["GET /orgs/{org}/team/{team_slug}/copilot/metrics"], - getCopilotOrganizationDetails: ["GET /orgs/{org}/copilot/billing"], - getCopilotSeatDetailsForUser: [ - "GET /orgs/{org}/members/{username}/copilot" - ], - listCopilotSeats: ["GET /orgs/{org}/copilot/billing/seats"] - }, - credentials: { revoke: ["POST /credentials/revoke"] }, - dependabot: { - addSelectedRepoToOrgSecret: [ - "PUT /orgs/{org}/dependabot/secrets/{secret_name}/repositories/{repository_id}" - ], - createOrUpdateOrgSecret: [ - "PUT /orgs/{org}/dependabot/secrets/{secret_name}" - ], - createOrUpdateRepoSecret: [ - "PUT /repos/{owner}/{repo}/dependabot/secrets/{secret_name}" - ], - deleteOrgSecret: ["DELETE /orgs/{org}/dependabot/secrets/{secret_name}"], - deleteRepoSecret: [ - "DELETE /repos/{owner}/{repo}/dependabot/secrets/{secret_name}" - ], - getAlert: ["GET /repos/{owner}/{repo}/dependabot/alerts/{alert_number}"], - getOrgPublicKey: ["GET /orgs/{org}/dependabot/secrets/public-key"], - getOrgSecret: ["GET /orgs/{org}/dependabot/secrets/{secret_name}"], - getRepoPublicKey: [ - "GET /repos/{owner}/{repo}/dependabot/secrets/public-key" - ], - getRepoSecret: [ - "GET /repos/{owner}/{repo}/dependabot/secrets/{secret_name}" - ], - listAlertsForEnterprise: [ - "GET /enterprises/{enterprise}/dependabot/alerts" - ], - listAlertsForOrg: ["GET /orgs/{org}/dependabot/alerts"], - listAlertsForRepo: ["GET /repos/{owner}/{repo}/dependabot/alerts"], - listOrgSecrets: ["GET /orgs/{org}/dependabot/secrets"], - listRepoSecrets: ["GET /repos/{owner}/{repo}/dependabot/secrets"], - listSelectedReposForOrgSecret: [ - "GET /orgs/{org}/dependabot/secrets/{secret_name}/repositories" - ], - removeSelectedRepoFromOrgSecret: [ - "DELETE /orgs/{org}/dependabot/secrets/{secret_name}/repositories/{repository_id}" - ], - repositoryAccessForOrg: [ - "GET /organizations/{org}/dependabot/repository-access" - ], - setRepositoryAccessDefaultLevel: [ - "PUT /organizations/{org}/dependabot/repository-access/default-level" - ], - setSelectedReposForOrgSecret: [ - "PUT /orgs/{org}/dependabot/secrets/{secret_name}/repositories" - ], - updateAlert: [ - "PATCH /repos/{owner}/{repo}/dependabot/alerts/{alert_number}" - ], - updateRepositoryAccessForOrg: [ - "PATCH /organizations/{org}/dependabot/repository-access" - ] - }, - dependencyGraph: { - createRepositorySnapshot: [ - "POST /repos/{owner}/{repo}/dependency-graph/snapshots" - ], - diffRange: [ - "GET /repos/{owner}/{repo}/dependency-graph/compare/{basehead}" - ], - exportSbom: ["GET /repos/{owner}/{repo}/dependency-graph/sbom"] - }, - emojis: { get: ["GET /emojis"] }, - enterpriseTeamMemberships: { - add: [ - "PUT /enterprises/{enterprise}/teams/{enterprise-team}/memberships/{username}" - ], - bulkAdd: [ - "POST /enterprises/{enterprise}/teams/{enterprise-team}/memberships/add" - ], - bulkRemove: [ - "POST /enterprises/{enterprise}/teams/{enterprise-team}/memberships/remove" - ], - get: [ - "GET /enterprises/{enterprise}/teams/{enterprise-team}/memberships/{username}" - ], - list: ["GET /enterprises/{enterprise}/teams/{enterprise-team}/memberships"], - remove: [ - "DELETE /enterprises/{enterprise}/teams/{enterprise-team}/memberships/{username}" - ] - }, - enterpriseTeamOrganizations: { - add: [ - "PUT /enterprises/{enterprise}/teams/{enterprise-team}/organizations/{org}" - ], - bulkAdd: [ - "POST /enterprises/{enterprise}/teams/{enterprise-team}/organizations/add" - ], - bulkRemove: [ - "POST /enterprises/{enterprise}/teams/{enterprise-team}/organizations/remove" - ], - delete: [ - "DELETE /enterprises/{enterprise}/teams/{enterprise-team}/organizations/{org}" - ], - getAssignment: [ - "GET /enterprises/{enterprise}/teams/{enterprise-team}/organizations/{org}" - ], - getAssignments: [ - "GET /enterprises/{enterprise}/teams/{enterprise-team}/organizations" - ] - }, - enterpriseTeams: { - create: ["POST /enterprises/{enterprise}/teams"], - delete: ["DELETE /enterprises/{enterprise}/teams/{team_slug}"], - get: ["GET /enterprises/{enterprise}/teams/{team_slug}"], - list: ["GET /enterprises/{enterprise}/teams"], - update: ["PATCH /enterprises/{enterprise}/teams/{team_slug}"] - }, - gists: { - checkIsStarred: ["GET /gists/{gist_id}/star"], - create: ["POST /gists"], - createComment: ["POST /gists/{gist_id}/comments"], - delete: ["DELETE /gists/{gist_id}"], - deleteComment: ["DELETE /gists/{gist_id}/comments/{comment_id}"], - fork: ["POST /gists/{gist_id}/forks"], - get: ["GET /gists/{gist_id}"], - getComment: ["GET /gists/{gist_id}/comments/{comment_id}"], - getRevision: ["GET /gists/{gist_id}/{sha}"], - list: ["GET /gists"], - listComments: ["GET /gists/{gist_id}/comments"], - listCommits: ["GET /gists/{gist_id}/commits"], - listForUser: ["GET /users/{username}/gists"], - listForks: ["GET /gists/{gist_id}/forks"], - listPublic: ["GET /gists/public"], - listStarred: ["GET /gists/starred"], - star: ["PUT /gists/{gist_id}/star"], - unstar: ["DELETE /gists/{gist_id}/star"], - update: ["PATCH /gists/{gist_id}"], - updateComment: ["PATCH /gists/{gist_id}/comments/{comment_id}"] - }, - git: { - createBlob: ["POST /repos/{owner}/{repo}/git/blobs"], - createCommit: ["POST /repos/{owner}/{repo}/git/commits"], - createRef: ["POST /repos/{owner}/{repo}/git/refs"], - createTag: ["POST /repos/{owner}/{repo}/git/tags"], - createTree: ["POST /repos/{owner}/{repo}/git/trees"], - deleteRef: ["DELETE /repos/{owner}/{repo}/git/refs/{ref}"], - getBlob: ["GET /repos/{owner}/{repo}/git/blobs/{file_sha}"], - getCommit: ["GET /repos/{owner}/{repo}/git/commits/{commit_sha}"], - getRef: ["GET /repos/{owner}/{repo}/git/ref/{ref}"], - getTag: ["GET /repos/{owner}/{repo}/git/tags/{tag_sha}"], - getTree: ["GET /repos/{owner}/{repo}/git/trees/{tree_sha}"], - listMatchingRefs: ["GET /repos/{owner}/{repo}/git/matching-refs/{ref}"], - updateRef: ["PATCH /repos/{owner}/{repo}/git/refs/{ref}"] - }, - gitignore: { - getAllTemplates: ["GET /gitignore/templates"], - getTemplate: ["GET /gitignore/templates/{name}"] - }, - hostedCompute: { - createNetworkConfigurationForOrg: [ - "POST /orgs/{org}/settings/network-configurations" - ], - deleteNetworkConfigurationFromOrg: [ - "DELETE /orgs/{org}/settings/network-configurations/{network_configuration_id}" - ], - getNetworkConfigurationForOrg: [ - "GET /orgs/{org}/settings/network-configurations/{network_configuration_id}" - ], - getNetworkSettingsForOrg: [ - "GET /orgs/{org}/settings/network-settings/{network_settings_id}" - ], - listNetworkConfigurationsForOrg: [ - "GET /orgs/{org}/settings/network-configurations" - ], - updateNetworkConfigurationForOrg: [ - "PATCH /orgs/{org}/settings/network-configurations/{network_configuration_id}" - ] - }, - interactions: { - getRestrictionsForAuthenticatedUser: ["GET /user/interaction-limits"], - getRestrictionsForOrg: ["GET /orgs/{org}/interaction-limits"], - getRestrictionsForRepo: ["GET /repos/{owner}/{repo}/interaction-limits"], - getRestrictionsForYourPublicRepos: [ - "GET /user/interaction-limits", - {}, - { renamed: ["interactions", "getRestrictionsForAuthenticatedUser"] } - ], - removeRestrictionsForAuthenticatedUser: ["DELETE /user/interaction-limits"], - removeRestrictionsForOrg: ["DELETE /orgs/{org}/interaction-limits"], - removeRestrictionsForRepo: [ - "DELETE /repos/{owner}/{repo}/interaction-limits" - ], - removeRestrictionsForYourPublicRepos: [ - "DELETE /user/interaction-limits", - {}, - { renamed: ["interactions", "removeRestrictionsForAuthenticatedUser"] } - ], - setRestrictionsForAuthenticatedUser: ["PUT /user/interaction-limits"], - setRestrictionsForOrg: ["PUT /orgs/{org}/interaction-limits"], - setRestrictionsForRepo: ["PUT /repos/{owner}/{repo}/interaction-limits"], - setRestrictionsForYourPublicRepos: [ - "PUT /user/interaction-limits", - {}, - { renamed: ["interactions", "setRestrictionsForAuthenticatedUser"] } - ] - }, - issues: { - addAssignees: [ - "POST /repos/{owner}/{repo}/issues/{issue_number}/assignees" - ], - addBlockedByDependency: [ - "POST /repos/{owner}/{repo}/issues/{issue_number}/dependencies/blocked_by" - ], - addLabels: ["POST /repos/{owner}/{repo}/issues/{issue_number}/labels"], - addSubIssue: [ - "POST /repos/{owner}/{repo}/issues/{issue_number}/sub_issues" - ], - checkUserCanBeAssigned: ["GET /repos/{owner}/{repo}/assignees/{assignee}"], - checkUserCanBeAssignedToIssue: [ - "GET /repos/{owner}/{repo}/issues/{issue_number}/assignees/{assignee}" - ], - create: ["POST /repos/{owner}/{repo}/issues"], - createComment: [ - "POST /repos/{owner}/{repo}/issues/{issue_number}/comments" - ], - createLabel: ["POST /repos/{owner}/{repo}/labels"], - createMilestone: ["POST /repos/{owner}/{repo}/milestones"], - deleteComment: [ - "DELETE /repos/{owner}/{repo}/issues/comments/{comment_id}" - ], - deleteLabel: ["DELETE /repos/{owner}/{repo}/labels/{name}"], - deleteMilestone: [ - "DELETE /repos/{owner}/{repo}/milestones/{milestone_number}" - ], - get: ["GET /repos/{owner}/{repo}/issues/{issue_number}"], - getComment: ["GET /repos/{owner}/{repo}/issues/comments/{comment_id}"], - getEvent: ["GET /repos/{owner}/{repo}/issues/events/{event_id}"], - getLabel: ["GET /repos/{owner}/{repo}/labels/{name}"], - getMilestone: ["GET /repos/{owner}/{repo}/milestones/{milestone_number}"], - getParent: ["GET /repos/{owner}/{repo}/issues/{issue_number}/parent"], - list: ["GET /issues"], - listAssignees: ["GET /repos/{owner}/{repo}/assignees"], - listComments: ["GET /repos/{owner}/{repo}/issues/{issue_number}/comments"], - listCommentsForRepo: ["GET /repos/{owner}/{repo}/issues/comments"], - listDependenciesBlockedBy: [ - "GET /repos/{owner}/{repo}/issues/{issue_number}/dependencies/blocked_by" - ], - listDependenciesBlocking: [ - "GET /repos/{owner}/{repo}/issues/{issue_number}/dependencies/blocking" - ], - listEvents: ["GET /repos/{owner}/{repo}/issues/{issue_number}/events"], - listEventsForRepo: ["GET /repos/{owner}/{repo}/issues/events"], - listEventsForTimeline: [ - "GET /repos/{owner}/{repo}/issues/{issue_number}/timeline" - ], - listForAuthenticatedUser: ["GET /user/issues"], - listForOrg: ["GET /orgs/{org}/issues"], - listForRepo: ["GET /repos/{owner}/{repo}/issues"], - listLabelsForMilestone: [ - "GET /repos/{owner}/{repo}/milestones/{milestone_number}/labels" - ], - listLabelsForRepo: ["GET /repos/{owner}/{repo}/labels"], - listLabelsOnIssue: [ - "GET /repos/{owner}/{repo}/issues/{issue_number}/labels" - ], - listMilestones: ["GET /repos/{owner}/{repo}/milestones"], - listSubIssues: [ - "GET /repos/{owner}/{repo}/issues/{issue_number}/sub_issues" - ], - lock: ["PUT /repos/{owner}/{repo}/issues/{issue_number}/lock"], - removeAllLabels: [ - "DELETE /repos/{owner}/{repo}/issues/{issue_number}/labels" - ], - removeAssignees: [ - "DELETE /repos/{owner}/{repo}/issues/{issue_number}/assignees" - ], - removeDependencyBlockedBy: [ - "DELETE /repos/{owner}/{repo}/issues/{issue_number}/dependencies/blocked_by/{issue_id}" - ], - removeLabel: [ - "DELETE /repos/{owner}/{repo}/issues/{issue_number}/labels/{name}" - ], - removeSubIssue: [ - "DELETE /repos/{owner}/{repo}/issues/{issue_number}/sub_issue" - ], - reprioritizeSubIssue: [ - "PATCH /repos/{owner}/{repo}/issues/{issue_number}/sub_issues/priority" - ], - setLabels: ["PUT /repos/{owner}/{repo}/issues/{issue_number}/labels"], - unlock: ["DELETE /repos/{owner}/{repo}/issues/{issue_number}/lock"], - update: ["PATCH /repos/{owner}/{repo}/issues/{issue_number}"], - updateComment: ["PATCH /repos/{owner}/{repo}/issues/comments/{comment_id}"], - updateLabel: ["PATCH /repos/{owner}/{repo}/labels/{name}"], - updateMilestone: [ - "PATCH /repos/{owner}/{repo}/milestones/{milestone_number}" - ] - }, - licenses: { - get: ["GET /licenses/{license}"], - getAllCommonlyUsed: ["GET /licenses"], - getForRepo: ["GET /repos/{owner}/{repo}/license"] - }, - markdown: { - render: ["POST /markdown"], - renderRaw: [ - "POST /markdown/raw", - { headers: { "content-type": "text/plain; charset=utf-8" } } - ] - }, - meta: { - get: ["GET /meta"], - getAllVersions: ["GET /versions"], - getOctocat: ["GET /octocat"], - getZen: ["GET /zen"], - root: ["GET /"] - }, - migrations: { - deleteArchiveForAuthenticatedUser: [ - "DELETE /user/migrations/{migration_id}/archive" - ], - deleteArchiveForOrg: [ - "DELETE /orgs/{org}/migrations/{migration_id}/archive" - ], - downloadArchiveForOrg: [ - "GET /orgs/{org}/migrations/{migration_id}/archive" - ], - getArchiveForAuthenticatedUser: [ - "GET /user/migrations/{migration_id}/archive" - ], - getStatusForAuthenticatedUser: ["GET /user/migrations/{migration_id}"], - getStatusForOrg: ["GET /orgs/{org}/migrations/{migration_id}"], - listForAuthenticatedUser: ["GET /user/migrations"], - listForOrg: ["GET /orgs/{org}/migrations"], - listReposForAuthenticatedUser: [ - "GET /user/migrations/{migration_id}/repositories" - ], - listReposForOrg: ["GET /orgs/{org}/migrations/{migration_id}/repositories"], - listReposForUser: [ - "GET /user/migrations/{migration_id}/repositories", - {}, - { renamed: ["migrations", "listReposForAuthenticatedUser"] } - ], - startForAuthenticatedUser: ["POST /user/migrations"], - startForOrg: ["POST /orgs/{org}/migrations"], - unlockRepoForAuthenticatedUser: [ - "DELETE /user/migrations/{migration_id}/repos/{repo_name}/lock" - ], - unlockRepoForOrg: [ - "DELETE /orgs/{org}/migrations/{migration_id}/repos/{repo_name}/lock" - ] - }, - oidc: { - getOidcCustomSubTemplateForOrg: [ - "GET /orgs/{org}/actions/oidc/customization/sub" - ], - updateOidcCustomSubTemplateForOrg: [ - "PUT /orgs/{org}/actions/oidc/customization/sub" - ] - }, - orgs: { - addSecurityManagerTeam: [ - "PUT /orgs/{org}/security-managers/teams/{team_slug}", - {}, - { - deprecated: "octokit.rest.orgs.addSecurityManagerTeam() is deprecated, see https://docs.github.com/rest/orgs/security-managers#add-a-security-manager-team" - } - ], - assignTeamToOrgRole: [ - "PUT /orgs/{org}/organization-roles/teams/{team_slug}/{role_id}" - ], - assignUserToOrgRole: [ - "PUT /orgs/{org}/organization-roles/users/{username}/{role_id}" - ], - blockUser: ["PUT /orgs/{org}/blocks/{username}"], - cancelInvitation: ["DELETE /orgs/{org}/invitations/{invitation_id}"], - checkBlockedUser: ["GET /orgs/{org}/blocks/{username}"], - checkMembershipForUser: ["GET /orgs/{org}/members/{username}"], - checkPublicMembershipForUser: ["GET /orgs/{org}/public_members/{username}"], - convertMemberToOutsideCollaborator: [ - "PUT /orgs/{org}/outside_collaborators/{username}" - ], - createArtifactStorageRecord: [ - "POST /orgs/{org}/artifacts/metadata/storage-record" - ], - createInvitation: ["POST /orgs/{org}/invitations"], - createIssueType: ["POST /orgs/{org}/issue-types"], - createWebhook: ["POST /orgs/{org}/hooks"], - customPropertiesForOrgsCreateOrUpdateOrganizationValues: [ - "PATCH /organizations/{org}/org-properties/values" - ], - customPropertiesForOrgsGetOrganizationValues: [ - "GET /organizations/{org}/org-properties/values" - ], - customPropertiesForReposCreateOrUpdateOrganizationDefinition: [ - "PUT /orgs/{org}/properties/schema/{custom_property_name}" - ], - customPropertiesForReposCreateOrUpdateOrganizationDefinitions: [ - "PATCH /orgs/{org}/properties/schema" - ], - customPropertiesForReposCreateOrUpdateOrganizationValues: [ - "PATCH /orgs/{org}/properties/values" - ], - customPropertiesForReposDeleteOrganizationDefinition: [ - "DELETE /orgs/{org}/properties/schema/{custom_property_name}" - ], - customPropertiesForReposGetOrganizationDefinition: [ - "GET /orgs/{org}/properties/schema/{custom_property_name}" - ], - customPropertiesForReposGetOrganizationDefinitions: [ - "GET /orgs/{org}/properties/schema" - ], - customPropertiesForReposGetOrganizationValues: [ - "GET /orgs/{org}/properties/values" - ], - delete: ["DELETE /orgs/{org}"], - deleteAttestationsBulk: ["POST /orgs/{org}/attestations/delete-request"], - deleteAttestationsById: [ - "DELETE /orgs/{org}/attestations/{attestation_id}" - ], - deleteAttestationsBySubjectDigest: [ - "DELETE /orgs/{org}/attestations/digest/{subject_digest}" - ], - deleteIssueType: ["DELETE /orgs/{org}/issue-types/{issue_type_id}"], - deleteWebhook: ["DELETE /orgs/{org}/hooks/{hook_id}"], - disableSelectedRepositoryImmutableReleasesOrganization: [ - "DELETE /orgs/{org}/settings/immutable-releases/repositories/{repository_id}" - ], - enableSelectedRepositoryImmutableReleasesOrganization: [ - "PUT /orgs/{org}/settings/immutable-releases/repositories/{repository_id}" - ], - get: ["GET /orgs/{org}"], - getImmutableReleasesSettings: [ - "GET /orgs/{org}/settings/immutable-releases" - ], - getImmutableReleasesSettingsRepositories: [ - "GET /orgs/{org}/settings/immutable-releases/repositories" - ], - getMembershipForAuthenticatedUser: ["GET /user/memberships/orgs/{org}"], - getMembershipForUser: ["GET /orgs/{org}/memberships/{username}"], - getOrgRole: ["GET /orgs/{org}/organization-roles/{role_id}"], - getOrgRulesetHistory: ["GET /orgs/{org}/rulesets/{ruleset_id}/history"], - getOrgRulesetVersion: [ - "GET /orgs/{org}/rulesets/{ruleset_id}/history/{version_id}" - ], - getWebhook: ["GET /orgs/{org}/hooks/{hook_id}"], - getWebhookConfigForOrg: ["GET /orgs/{org}/hooks/{hook_id}/config"], - getWebhookDelivery: [ - "GET /orgs/{org}/hooks/{hook_id}/deliveries/{delivery_id}" - ], - list: ["GET /organizations"], - listAppInstallations: ["GET /orgs/{org}/installations"], - listArtifactStorageRecords: [ - "GET /orgs/{org}/artifacts/{subject_digest}/metadata/storage-records" - ], - listAttestationRepositories: ["GET /orgs/{org}/attestations/repositories"], - listAttestations: ["GET /orgs/{org}/attestations/{subject_digest}"], - listAttestationsBulk: [ - "POST /orgs/{org}/attestations/bulk-list{?per_page,before,after}" - ], - listBlockedUsers: ["GET /orgs/{org}/blocks"], - listFailedInvitations: ["GET /orgs/{org}/failed_invitations"], - listForAuthenticatedUser: ["GET /user/orgs"], - listForUser: ["GET /users/{username}/orgs"], - listInvitationTeams: ["GET /orgs/{org}/invitations/{invitation_id}/teams"], - listIssueTypes: ["GET /orgs/{org}/issue-types"], - listMembers: ["GET /orgs/{org}/members"], - listMembershipsForAuthenticatedUser: ["GET /user/memberships/orgs"], - listOrgRoleTeams: ["GET /orgs/{org}/organization-roles/{role_id}/teams"], - listOrgRoleUsers: ["GET /orgs/{org}/organization-roles/{role_id}/users"], - listOrgRoles: ["GET /orgs/{org}/organization-roles"], - listOrganizationFineGrainedPermissions: [ - "GET /orgs/{org}/organization-fine-grained-permissions" - ], - listOutsideCollaborators: ["GET /orgs/{org}/outside_collaborators"], - listPatGrantRepositories: [ - "GET /orgs/{org}/personal-access-tokens/{pat_id}/repositories" - ], - listPatGrantRequestRepositories: [ - "GET /orgs/{org}/personal-access-token-requests/{pat_request_id}/repositories" - ], - listPatGrantRequests: ["GET /orgs/{org}/personal-access-token-requests"], - listPatGrants: ["GET /orgs/{org}/personal-access-tokens"], - listPendingInvitations: ["GET /orgs/{org}/invitations"], - listPublicMembers: ["GET /orgs/{org}/public_members"], - listSecurityManagerTeams: [ - "GET /orgs/{org}/security-managers", - {}, - { - deprecated: "octokit.rest.orgs.listSecurityManagerTeams() is deprecated, see https://docs.github.com/rest/orgs/security-managers#list-security-manager-teams" - } - ], - listWebhookDeliveries: ["GET /orgs/{org}/hooks/{hook_id}/deliveries"], - listWebhooks: ["GET /orgs/{org}/hooks"], - pingWebhook: ["POST /orgs/{org}/hooks/{hook_id}/pings"], - redeliverWebhookDelivery: [ - "POST /orgs/{org}/hooks/{hook_id}/deliveries/{delivery_id}/attempts" - ], - removeMember: ["DELETE /orgs/{org}/members/{username}"], - removeMembershipForUser: ["DELETE /orgs/{org}/memberships/{username}"], - removeOutsideCollaborator: [ - "DELETE /orgs/{org}/outside_collaborators/{username}" - ], - removePublicMembershipForAuthenticatedUser: [ - "DELETE /orgs/{org}/public_members/{username}" - ], - removeSecurityManagerTeam: [ - "DELETE /orgs/{org}/security-managers/teams/{team_slug}", - {}, - { - deprecated: "octokit.rest.orgs.removeSecurityManagerTeam() is deprecated, see https://docs.github.com/rest/orgs/security-managers#remove-a-security-manager-team" - } - ], - reviewPatGrantRequest: [ - "POST /orgs/{org}/personal-access-token-requests/{pat_request_id}" - ], - reviewPatGrantRequestsInBulk: [ - "POST /orgs/{org}/personal-access-token-requests" - ], - revokeAllOrgRolesTeam: [ - "DELETE /orgs/{org}/organization-roles/teams/{team_slug}" - ], - revokeAllOrgRolesUser: [ - "DELETE /orgs/{org}/organization-roles/users/{username}" - ], - revokeOrgRoleTeam: [ - "DELETE /orgs/{org}/organization-roles/teams/{team_slug}/{role_id}" - ], - revokeOrgRoleUser: [ - "DELETE /orgs/{org}/organization-roles/users/{username}/{role_id}" - ], - setImmutableReleasesSettings: [ - "PUT /orgs/{org}/settings/immutable-releases" - ], - setImmutableReleasesSettingsRepositories: [ - "PUT /orgs/{org}/settings/immutable-releases/repositories" - ], - setMembershipForUser: ["PUT /orgs/{org}/memberships/{username}"], - setPublicMembershipForAuthenticatedUser: [ - "PUT /orgs/{org}/public_members/{username}" - ], - unblockUser: ["DELETE /orgs/{org}/blocks/{username}"], - update: ["PATCH /orgs/{org}"], - updateIssueType: ["PUT /orgs/{org}/issue-types/{issue_type_id}"], - updateMembershipForAuthenticatedUser: [ - "PATCH /user/memberships/orgs/{org}" - ], - updatePatAccess: ["POST /orgs/{org}/personal-access-tokens/{pat_id}"], - updatePatAccesses: ["POST /orgs/{org}/personal-access-tokens"], - updateWebhook: ["PATCH /orgs/{org}/hooks/{hook_id}"], - updateWebhookConfigForOrg: ["PATCH /orgs/{org}/hooks/{hook_id}/config"] - }, - packages: { - deletePackageForAuthenticatedUser: [ - "DELETE /user/packages/{package_type}/{package_name}" - ], - deletePackageForOrg: [ - "DELETE /orgs/{org}/packages/{package_type}/{package_name}" - ], - deletePackageForUser: [ - "DELETE /users/{username}/packages/{package_type}/{package_name}" - ], - deletePackageVersionForAuthenticatedUser: [ - "DELETE /user/packages/{package_type}/{package_name}/versions/{package_version_id}" - ], - deletePackageVersionForOrg: [ - "DELETE /orgs/{org}/packages/{package_type}/{package_name}/versions/{package_version_id}" - ], - deletePackageVersionForUser: [ - "DELETE /users/{username}/packages/{package_type}/{package_name}/versions/{package_version_id}" - ], - getAllPackageVersionsForAPackageOwnedByAnOrg: [ - "GET /orgs/{org}/packages/{package_type}/{package_name}/versions", - {}, - { renamed: ["packages", "getAllPackageVersionsForPackageOwnedByOrg"] } - ], - getAllPackageVersionsForAPackageOwnedByTheAuthenticatedUser: [ - "GET /user/packages/{package_type}/{package_name}/versions", - {}, - { - renamed: [ - "packages", - "getAllPackageVersionsForPackageOwnedByAuthenticatedUser" - ] - } - ], - getAllPackageVersionsForPackageOwnedByAuthenticatedUser: [ - "GET /user/packages/{package_type}/{package_name}/versions" - ], - getAllPackageVersionsForPackageOwnedByOrg: [ - "GET /orgs/{org}/packages/{package_type}/{package_name}/versions" - ], - getAllPackageVersionsForPackageOwnedByUser: [ - "GET /users/{username}/packages/{package_type}/{package_name}/versions" - ], - getPackageForAuthenticatedUser: [ - "GET /user/packages/{package_type}/{package_name}" - ], - getPackageForOrganization: [ - "GET /orgs/{org}/packages/{package_type}/{package_name}" - ], - getPackageForUser: [ - "GET /users/{username}/packages/{package_type}/{package_name}" - ], - getPackageVersionForAuthenticatedUser: [ - "GET /user/packages/{package_type}/{package_name}/versions/{package_version_id}" - ], - getPackageVersionForOrganization: [ - "GET /orgs/{org}/packages/{package_type}/{package_name}/versions/{package_version_id}" - ], - getPackageVersionForUser: [ - "GET /users/{username}/packages/{package_type}/{package_name}/versions/{package_version_id}" - ], - listDockerMigrationConflictingPackagesForAuthenticatedUser: [ - "GET /user/docker/conflicts" - ], - listDockerMigrationConflictingPackagesForOrganization: [ - "GET /orgs/{org}/docker/conflicts" - ], - listDockerMigrationConflictingPackagesForUser: [ - "GET /users/{username}/docker/conflicts" - ], - listPackagesForAuthenticatedUser: ["GET /user/packages"], - listPackagesForOrganization: ["GET /orgs/{org}/packages"], - listPackagesForUser: ["GET /users/{username}/packages"], - restorePackageForAuthenticatedUser: [ - "POST /user/packages/{package_type}/{package_name}/restore{?token}" - ], - restorePackageForOrg: [ - "POST /orgs/{org}/packages/{package_type}/{package_name}/restore{?token}" - ], - restorePackageForUser: [ - "POST /users/{username}/packages/{package_type}/{package_name}/restore{?token}" - ], - restorePackageVersionForAuthenticatedUser: [ - "POST /user/packages/{package_type}/{package_name}/versions/{package_version_id}/restore" - ], - restorePackageVersionForOrg: [ - "POST /orgs/{org}/packages/{package_type}/{package_name}/versions/{package_version_id}/restore" - ], - restorePackageVersionForUser: [ - "POST /users/{username}/packages/{package_type}/{package_name}/versions/{package_version_id}/restore" - ] - }, - privateRegistries: { - createOrgPrivateRegistry: ["POST /orgs/{org}/private-registries"], - deleteOrgPrivateRegistry: [ - "DELETE /orgs/{org}/private-registries/{secret_name}" - ], - getOrgPrivateRegistry: ["GET /orgs/{org}/private-registries/{secret_name}"], - getOrgPublicKey: ["GET /orgs/{org}/private-registries/public-key"], - listOrgPrivateRegistries: ["GET /orgs/{org}/private-registries"], - updateOrgPrivateRegistry: [ - "PATCH /orgs/{org}/private-registries/{secret_name}" - ] - }, - projects: { - addItemForOrg: ["POST /orgs/{org}/projectsV2/{project_number}/items"], - addItemForUser: [ - "POST /users/{username}/projectsV2/{project_number}/items" - ], - deleteItemForOrg: [ - "DELETE /orgs/{org}/projectsV2/{project_number}/items/{item_id}" - ], - deleteItemForUser: [ - "DELETE /users/{username}/projectsV2/{project_number}/items/{item_id}" - ], - getFieldForOrg: [ - "GET /orgs/{org}/projectsV2/{project_number}/fields/{field_id}" - ], - getFieldForUser: [ - "GET /users/{username}/projectsV2/{project_number}/fields/{field_id}" - ], - getForOrg: ["GET /orgs/{org}/projectsV2/{project_number}"], - getForUser: ["GET /users/{username}/projectsV2/{project_number}"], - getOrgItem: ["GET /orgs/{org}/projectsV2/{project_number}/items/{item_id}"], - getUserItem: [ - "GET /users/{username}/projectsV2/{project_number}/items/{item_id}" - ], - listFieldsForOrg: ["GET /orgs/{org}/projectsV2/{project_number}/fields"], - listFieldsForUser: [ - "GET /users/{username}/projectsV2/{project_number}/fields" - ], - listForOrg: ["GET /orgs/{org}/projectsV2"], - listForUser: ["GET /users/{username}/projectsV2"], - listItemsForOrg: ["GET /orgs/{org}/projectsV2/{project_number}/items"], - listItemsForUser: [ - "GET /users/{username}/projectsV2/{project_number}/items" - ], - updateItemForOrg: [ - "PATCH /orgs/{org}/projectsV2/{project_number}/items/{item_id}" - ], - updateItemForUser: [ - "PATCH /users/{username}/projectsV2/{project_number}/items/{item_id}" - ] - }, - pulls: { - checkIfMerged: ["GET /repos/{owner}/{repo}/pulls/{pull_number}/merge"], - create: ["POST /repos/{owner}/{repo}/pulls"], - createReplyForReviewComment: [ - "POST /repos/{owner}/{repo}/pulls/{pull_number}/comments/{comment_id}/replies" - ], - createReview: ["POST /repos/{owner}/{repo}/pulls/{pull_number}/reviews"], - createReviewComment: [ - "POST /repos/{owner}/{repo}/pulls/{pull_number}/comments" - ], - deletePendingReview: [ - "DELETE /repos/{owner}/{repo}/pulls/{pull_number}/reviews/{review_id}" - ], - deleteReviewComment: [ - "DELETE /repos/{owner}/{repo}/pulls/comments/{comment_id}" - ], - dismissReview: [ - "PUT /repos/{owner}/{repo}/pulls/{pull_number}/reviews/{review_id}/dismissals" - ], - get: ["GET /repos/{owner}/{repo}/pulls/{pull_number}"], - getReview: [ - "GET /repos/{owner}/{repo}/pulls/{pull_number}/reviews/{review_id}" - ], - getReviewComment: ["GET /repos/{owner}/{repo}/pulls/comments/{comment_id}"], - list: ["GET /repos/{owner}/{repo}/pulls"], - listCommentsForReview: [ - "GET /repos/{owner}/{repo}/pulls/{pull_number}/reviews/{review_id}/comments" - ], - listCommits: ["GET /repos/{owner}/{repo}/pulls/{pull_number}/commits"], - listFiles: ["GET /repos/{owner}/{repo}/pulls/{pull_number}/files"], - listRequestedReviewers: [ - "GET /repos/{owner}/{repo}/pulls/{pull_number}/requested_reviewers" - ], - listReviewComments: [ - "GET /repos/{owner}/{repo}/pulls/{pull_number}/comments" - ], - listReviewCommentsForRepo: ["GET /repos/{owner}/{repo}/pulls/comments"], - listReviews: ["GET /repos/{owner}/{repo}/pulls/{pull_number}/reviews"], - merge: ["PUT /repos/{owner}/{repo}/pulls/{pull_number}/merge"], - removeRequestedReviewers: [ - "DELETE /repos/{owner}/{repo}/pulls/{pull_number}/requested_reviewers" - ], - requestReviewers: [ - "POST /repos/{owner}/{repo}/pulls/{pull_number}/requested_reviewers" - ], - submitReview: [ - "POST /repos/{owner}/{repo}/pulls/{pull_number}/reviews/{review_id}/events" - ], - update: ["PATCH /repos/{owner}/{repo}/pulls/{pull_number}"], - updateBranch: [ - "PUT /repos/{owner}/{repo}/pulls/{pull_number}/update-branch" - ], - updateReview: [ - "PUT /repos/{owner}/{repo}/pulls/{pull_number}/reviews/{review_id}" - ], - updateReviewComment: [ - "PATCH /repos/{owner}/{repo}/pulls/comments/{comment_id}" - ] - }, - rateLimit: { get: ["GET /rate_limit"] }, - reactions: { - createForCommitComment: [ - "POST /repos/{owner}/{repo}/comments/{comment_id}/reactions" - ], - createForIssue: [ - "POST /repos/{owner}/{repo}/issues/{issue_number}/reactions" - ], - createForIssueComment: [ - "POST /repos/{owner}/{repo}/issues/comments/{comment_id}/reactions" - ], - createForPullRequestReviewComment: [ - "POST /repos/{owner}/{repo}/pulls/comments/{comment_id}/reactions" - ], - createForRelease: [ - "POST /repos/{owner}/{repo}/releases/{release_id}/reactions" - ], - createForTeamDiscussionCommentInOrg: [ - "POST /orgs/{org}/teams/{team_slug}/discussions/{discussion_number}/comments/{comment_number}/reactions" - ], - createForTeamDiscussionInOrg: [ - "POST /orgs/{org}/teams/{team_slug}/discussions/{discussion_number}/reactions" - ], - deleteForCommitComment: [ - "DELETE /repos/{owner}/{repo}/comments/{comment_id}/reactions/{reaction_id}" - ], - deleteForIssue: [ - "DELETE /repos/{owner}/{repo}/issues/{issue_number}/reactions/{reaction_id}" - ], - deleteForIssueComment: [ - "DELETE /repos/{owner}/{repo}/issues/comments/{comment_id}/reactions/{reaction_id}" - ], - deleteForPullRequestComment: [ - "DELETE /repos/{owner}/{repo}/pulls/comments/{comment_id}/reactions/{reaction_id}" - ], - deleteForRelease: [ - "DELETE /repos/{owner}/{repo}/releases/{release_id}/reactions/{reaction_id}" - ], - deleteForTeamDiscussion: [ - "DELETE /orgs/{org}/teams/{team_slug}/discussions/{discussion_number}/reactions/{reaction_id}" - ], - deleteForTeamDiscussionComment: [ - "DELETE /orgs/{org}/teams/{team_slug}/discussions/{discussion_number}/comments/{comment_number}/reactions/{reaction_id}" - ], - listForCommitComment: [ - "GET /repos/{owner}/{repo}/comments/{comment_id}/reactions" - ], - listForIssue: ["GET /repos/{owner}/{repo}/issues/{issue_number}/reactions"], - listForIssueComment: [ - "GET /repos/{owner}/{repo}/issues/comments/{comment_id}/reactions" - ], - listForPullRequestReviewComment: [ - "GET /repos/{owner}/{repo}/pulls/comments/{comment_id}/reactions" - ], - listForRelease: [ - "GET /repos/{owner}/{repo}/releases/{release_id}/reactions" - ], - listForTeamDiscussionCommentInOrg: [ - "GET /orgs/{org}/teams/{team_slug}/discussions/{discussion_number}/comments/{comment_number}/reactions" - ], - listForTeamDiscussionInOrg: [ - "GET /orgs/{org}/teams/{team_slug}/discussions/{discussion_number}/reactions" - ] - }, - repos: { - acceptInvitation: [ - "PATCH /user/repository_invitations/{invitation_id}", - {}, - { renamed: ["repos", "acceptInvitationForAuthenticatedUser"] } - ], - acceptInvitationForAuthenticatedUser: [ - "PATCH /user/repository_invitations/{invitation_id}" - ], - addAppAccessRestrictions: [ - "POST /repos/{owner}/{repo}/branches/{branch}/protection/restrictions/apps", - {}, - { mapToData: "apps" } - ], - addCollaborator: ["PUT /repos/{owner}/{repo}/collaborators/{username}"], - addStatusCheckContexts: [ - "POST /repos/{owner}/{repo}/branches/{branch}/protection/required_status_checks/contexts", - {}, - { mapToData: "contexts" } - ], - addTeamAccessRestrictions: [ - "POST /repos/{owner}/{repo}/branches/{branch}/protection/restrictions/teams", - {}, - { mapToData: "teams" } - ], - addUserAccessRestrictions: [ - "POST /repos/{owner}/{repo}/branches/{branch}/protection/restrictions/users", - {}, - { mapToData: "users" } - ], - cancelPagesDeployment: [ - "POST /repos/{owner}/{repo}/pages/deployments/{pages_deployment_id}/cancel" - ], - checkAutomatedSecurityFixes: [ - "GET /repos/{owner}/{repo}/automated-security-fixes" - ], - checkCollaborator: ["GET /repos/{owner}/{repo}/collaborators/{username}"], - checkImmutableReleases: ["GET /repos/{owner}/{repo}/immutable-releases"], - checkPrivateVulnerabilityReporting: [ - "GET /repos/{owner}/{repo}/private-vulnerability-reporting" - ], - checkVulnerabilityAlerts: [ - "GET /repos/{owner}/{repo}/vulnerability-alerts" - ], - codeownersErrors: ["GET /repos/{owner}/{repo}/codeowners/errors"], - compareCommits: ["GET /repos/{owner}/{repo}/compare/{base}...{head}"], - compareCommitsWithBasehead: [ - "GET /repos/{owner}/{repo}/compare/{basehead}" - ], - createAttestation: ["POST /repos/{owner}/{repo}/attestations"], - createAutolink: ["POST /repos/{owner}/{repo}/autolinks"], - createCommitComment: [ - "POST /repos/{owner}/{repo}/commits/{commit_sha}/comments" - ], - createCommitSignatureProtection: [ - "POST /repos/{owner}/{repo}/branches/{branch}/protection/required_signatures" - ], - createCommitStatus: ["POST /repos/{owner}/{repo}/statuses/{sha}"], - createDeployKey: ["POST /repos/{owner}/{repo}/keys"], - createDeployment: ["POST /repos/{owner}/{repo}/deployments"], - createDeploymentBranchPolicy: [ - "POST /repos/{owner}/{repo}/environments/{environment_name}/deployment-branch-policies" - ], - createDeploymentProtectionRule: [ - "POST /repos/{owner}/{repo}/environments/{environment_name}/deployment_protection_rules" - ], - createDeploymentStatus: [ - "POST /repos/{owner}/{repo}/deployments/{deployment_id}/statuses" - ], - createDispatchEvent: ["POST /repos/{owner}/{repo}/dispatches"], - createForAuthenticatedUser: ["POST /user/repos"], - createFork: ["POST /repos/{owner}/{repo}/forks"], - createInOrg: ["POST /orgs/{org}/repos"], - createOrUpdateEnvironment: [ - "PUT /repos/{owner}/{repo}/environments/{environment_name}" - ], - createOrUpdateFileContents: ["PUT /repos/{owner}/{repo}/contents/{path}"], - createOrgRuleset: ["POST /orgs/{org}/rulesets"], - createPagesDeployment: ["POST /repos/{owner}/{repo}/pages/deployments"], - createPagesSite: ["POST /repos/{owner}/{repo}/pages"], - createRelease: ["POST /repos/{owner}/{repo}/releases"], - createRepoRuleset: ["POST /repos/{owner}/{repo}/rulesets"], - createUsingTemplate: [ - "POST /repos/{template_owner}/{template_repo}/generate" - ], - createWebhook: ["POST /repos/{owner}/{repo}/hooks"], - customPropertiesForReposCreateOrUpdateRepositoryValues: [ - "PATCH /repos/{owner}/{repo}/properties/values" - ], - customPropertiesForReposGetRepositoryValues: [ - "GET /repos/{owner}/{repo}/properties/values" - ], - declineInvitation: [ - "DELETE /user/repository_invitations/{invitation_id}", - {}, - { renamed: ["repos", "declineInvitationForAuthenticatedUser"] } - ], - declineInvitationForAuthenticatedUser: [ - "DELETE /user/repository_invitations/{invitation_id}" - ], - delete: ["DELETE /repos/{owner}/{repo}"], - deleteAccessRestrictions: [ - "DELETE /repos/{owner}/{repo}/branches/{branch}/protection/restrictions" - ], - deleteAdminBranchProtection: [ - "DELETE /repos/{owner}/{repo}/branches/{branch}/protection/enforce_admins" - ], - deleteAnEnvironment: [ - "DELETE /repos/{owner}/{repo}/environments/{environment_name}" - ], - deleteAutolink: ["DELETE /repos/{owner}/{repo}/autolinks/{autolink_id}"], - deleteBranchProtection: [ - "DELETE /repos/{owner}/{repo}/branches/{branch}/protection" - ], - deleteCommitComment: ["DELETE /repos/{owner}/{repo}/comments/{comment_id}"], - deleteCommitSignatureProtection: [ - "DELETE /repos/{owner}/{repo}/branches/{branch}/protection/required_signatures" - ], - deleteDeployKey: ["DELETE /repos/{owner}/{repo}/keys/{key_id}"], - deleteDeployment: [ - "DELETE /repos/{owner}/{repo}/deployments/{deployment_id}" - ], - deleteDeploymentBranchPolicy: [ - "DELETE /repos/{owner}/{repo}/environments/{environment_name}/deployment-branch-policies/{branch_policy_id}" - ], - deleteFile: ["DELETE /repos/{owner}/{repo}/contents/{path}"], - deleteInvitation: [ - "DELETE /repos/{owner}/{repo}/invitations/{invitation_id}" - ], - deleteOrgRuleset: ["DELETE /orgs/{org}/rulesets/{ruleset_id}"], - deletePagesSite: ["DELETE /repos/{owner}/{repo}/pages"], - deletePullRequestReviewProtection: [ - "DELETE /repos/{owner}/{repo}/branches/{branch}/protection/required_pull_request_reviews" - ], - deleteRelease: ["DELETE /repos/{owner}/{repo}/releases/{release_id}"], - deleteReleaseAsset: [ - "DELETE /repos/{owner}/{repo}/releases/assets/{asset_id}" - ], - deleteRepoRuleset: ["DELETE /repos/{owner}/{repo}/rulesets/{ruleset_id}"], - deleteWebhook: ["DELETE /repos/{owner}/{repo}/hooks/{hook_id}"], - disableAutomatedSecurityFixes: [ - "DELETE /repos/{owner}/{repo}/automated-security-fixes" - ], - disableDeploymentProtectionRule: [ - "DELETE /repos/{owner}/{repo}/environments/{environment_name}/deployment_protection_rules/{protection_rule_id}" - ], - disableImmutableReleases: [ - "DELETE /repos/{owner}/{repo}/immutable-releases" - ], - disablePrivateVulnerabilityReporting: [ - "DELETE /repos/{owner}/{repo}/private-vulnerability-reporting" - ], - disableVulnerabilityAlerts: [ - "DELETE /repos/{owner}/{repo}/vulnerability-alerts" - ], - downloadArchive: [ - "GET /repos/{owner}/{repo}/zipball/{ref}", - {}, - { renamed: ["repos", "downloadZipballArchive"] } - ], - downloadTarballArchive: ["GET /repos/{owner}/{repo}/tarball/{ref}"], - downloadZipballArchive: ["GET /repos/{owner}/{repo}/zipball/{ref}"], - enableAutomatedSecurityFixes: [ - "PUT /repos/{owner}/{repo}/automated-security-fixes" - ], - enableImmutableReleases: ["PUT /repos/{owner}/{repo}/immutable-releases"], - enablePrivateVulnerabilityReporting: [ - "PUT /repos/{owner}/{repo}/private-vulnerability-reporting" - ], - enableVulnerabilityAlerts: [ - "PUT /repos/{owner}/{repo}/vulnerability-alerts" - ], - generateReleaseNotes: [ - "POST /repos/{owner}/{repo}/releases/generate-notes" - ], - get: ["GET /repos/{owner}/{repo}"], - getAccessRestrictions: [ - "GET /repos/{owner}/{repo}/branches/{branch}/protection/restrictions" - ], - getAdminBranchProtection: [ - "GET /repos/{owner}/{repo}/branches/{branch}/protection/enforce_admins" - ], - getAllDeploymentProtectionRules: [ - "GET /repos/{owner}/{repo}/environments/{environment_name}/deployment_protection_rules" - ], - getAllEnvironments: ["GET /repos/{owner}/{repo}/environments"], - getAllStatusCheckContexts: [ - "GET /repos/{owner}/{repo}/branches/{branch}/protection/required_status_checks/contexts" - ], - getAllTopics: ["GET /repos/{owner}/{repo}/topics"], - getAppsWithAccessToProtectedBranch: [ - "GET /repos/{owner}/{repo}/branches/{branch}/protection/restrictions/apps" - ], - getAutolink: ["GET /repos/{owner}/{repo}/autolinks/{autolink_id}"], - getBranch: ["GET /repos/{owner}/{repo}/branches/{branch}"], - getBranchProtection: [ - "GET /repos/{owner}/{repo}/branches/{branch}/protection" - ], - getBranchRules: ["GET /repos/{owner}/{repo}/rules/branches/{branch}"], - getClones: ["GET /repos/{owner}/{repo}/traffic/clones"], - getCodeFrequencyStats: ["GET /repos/{owner}/{repo}/stats/code_frequency"], - getCollaboratorPermissionLevel: [ - "GET /repos/{owner}/{repo}/collaborators/{username}/permission" - ], - getCombinedStatusForRef: ["GET /repos/{owner}/{repo}/commits/{ref}/status"], - getCommit: ["GET /repos/{owner}/{repo}/commits/{ref}"], - getCommitActivityStats: ["GET /repos/{owner}/{repo}/stats/commit_activity"], - getCommitComment: ["GET /repos/{owner}/{repo}/comments/{comment_id}"], - getCommitSignatureProtection: [ - "GET /repos/{owner}/{repo}/branches/{branch}/protection/required_signatures" - ], - getCommunityProfileMetrics: ["GET /repos/{owner}/{repo}/community/profile"], - getContent: ["GET /repos/{owner}/{repo}/contents/{path}"], - getContributorsStats: ["GET /repos/{owner}/{repo}/stats/contributors"], - getCustomDeploymentProtectionRule: [ - "GET /repos/{owner}/{repo}/environments/{environment_name}/deployment_protection_rules/{protection_rule_id}" - ], - getDeployKey: ["GET /repos/{owner}/{repo}/keys/{key_id}"], - getDeployment: ["GET /repos/{owner}/{repo}/deployments/{deployment_id}"], - getDeploymentBranchPolicy: [ - "GET /repos/{owner}/{repo}/environments/{environment_name}/deployment-branch-policies/{branch_policy_id}" - ], - getDeploymentStatus: [ - "GET /repos/{owner}/{repo}/deployments/{deployment_id}/statuses/{status_id}" - ], - getEnvironment: [ - "GET /repos/{owner}/{repo}/environments/{environment_name}" - ], - getLatestPagesBuild: ["GET /repos/{owner}/{repo}/pages/builds/latest"], - getLatestRelease: ["GET /repos/{owner}/{repo}/releases/latest"], - getOrgRuleSuite: ["GET /orgs/{org}/rulesets/rule-suites/{rule_suite_id}"], - getOrgRuleSuites: ["GET /orgs/{org}/rulesets/rule-suites"], - getOrgRuleset: ["GET /orgs/{org}/rulesets/{ruleset_id}"], - getOrgRulesets: ["GET /orgs/{org}/rulesets"], - getPages: ["GET /repos/{owner}/{repo}/pages"], - getPagesBuild: ["GET /repos/{owner}/{repo}/pages/builds/{build_id}"], - getPagesDeployment: [ - "GET /repos/{owner}/{repo}/pages/deployments/{pages_deployment_id}" - ], - getPagesHealthCheck: ["GET /repos/{owner}/{repo}/pages/health"], - getParticipationStats: ["GET /repos/{owner}/{repo}/stats/participation"], - getPullRequestReviewProtection: [ - "GET /repos/{owner}/{repo}/branches/{branch}/protection/required_pull_request_reviews" - ], - getPunchCardStats: ["GET /repos/{owner}/{repo}/stats/punch_card"], - getReadme: ["GET /repos/{owner}/{repo}/readme"], - getReadmeInDirectory: ["GET /repos/{owner}/{repo}/readme/{dir}"], - getRelease: ["GET /repos/{owner}/{repo}/releases/{release_id}"], - getReleaseAsset: ["GET /repos/{owner}/{repo}/releases/assets/{asset_id}"], - getReleaseByTag: ["GET /repos/{owner}/{repo}/releases/tags/{tag}"], - getRepoRuleSuite: [ - "GET /repos/{owner}/{repo}/rulesets/rule-suites/{rule_suite_id}" - ], - getRepoRuleSuites: ["GET /repos/{owner}/{repo}/rulesets/rule-suites"], - getRepoRuleset: ["GET /repos/{owner}/{repo}/rulesets/{ruleset_id}"], - getRepoRulesetHistory: [ - "GET /repos/{owner}/{repo}/rulesets/{ruleset_id}/history" - ], - getRepoRulesetVersion: [ - "GET /repos/{owner}/{repo}/rulesets/{ruleset_id}/history/{version_id}" - ], - getRepoRulesets: ["GET /repos/{owner}/{repo}/rulesets"], - getStatusChecksProtection: [ - "GET /repos/{owner}/{repo}/branches/{branch}/protection/required_status_checks" - ], - getTeamsWithAccessToProtectedBranch: [ - "GET /repos/{owner}/{repo}/branches/{branch}/protection/restrictions/teams" - ], - getTopPaths: ["GET /repos/{owner}/{repo}/traffic/popular/paths"], - getTopReferrers: ["GET /repos/{owner}/{repo}/traffic/popular/referrers"], - getUsersWithAccessToProtectedBranch: [ - "GET /repos/{owner}/{repo}/branches/{branch}/protection/restrictions/users" - ], - getViews: ["GET /repos/{owner}/{repo}/traffic/views"], - getWebhook: ["GET /repos/{owner}/{repo}/hooks/{hook_id}"], - getWebhookConfigForRepo: [ - "GET /repos/{owner}/{repo}/hooks/{hook_id}/config" - ], - getWebhookDelivery: [ - "GET /repos/{owner}/{repo}/hooks/{hook_id}/deliveries/{delivery_id}" - ], - listActivities: ["GET /repos/{owner}/{repo}/activity"], - listAttestations: [ - "GET /repos/{owner}/{repo}/attestations/{subject_digest}" - ], - listAutolinks: ["GET /repos/{owner}/{repo}/autolinks"], - listBranches: ["GET /repos/{owner}/{repo}/branches"], - listBranchesForHeadCommit: [ - "GET /repos/{owner}/{repo}/commits/{commit_sha}/branches-where-head" - ], - listCollaborators: ["GET /repos/{owner}/{repo}/collaborators"], - listCommentsForCommit: [ - "GET /repos/{owner}/{repo}/commits/{commit_sha}/comments" - ], - listCommitCommentsForRepo: ["GET /repos/{owner}/{repo}/comments"], - listCommitStatusesForRef: [ - "GET /repos/{owner}/{repo}/commits/{ref}/statuses" - ], - listCommits: ["GET /repos/{owner}/{repo}/commits"], - listContributors: ["GET /repos/{owner}/{repo}/contributors"], - listCustomDeploymentRuleIntegrations: [ - "GET /repos/{owner}/{repo}/environments/{environment_name}/deployment_protection_rules/apps" - ], - listDeployKeys: ["GET /repos/{owner}/{repo}/keys"], - listDeploymentBranchPolicies: [ - "GET /repos/{owner}/{repo}/environments/{environment_name}/deployment-branch-policies" - ], - listDeploymentStatuses: [ - "GET /repos/{owner}/{repo}/deployments/{deployment_id}/statuses" - ], - listDeployments: ["GET /repos/{owner}/{repo}/deployments"], - listForAuthenticatedUser: ["GET /user/repos"], - listForOrg: ["GET /orgs/{org}/repos"], - listForUser: ["GET /users/{username}/repos"], - listForks: ["GET /repos/{owner}/{repo}/forks"], - listInvitations: ["GET /repos/{owner}/{repo}/invitations"], - listInvitationsForAuthenticatedUser: ["GET /user/repository_invitations"], - listLanguages: ["GET /repos/{owner}/{repo}/languages"], - listPagesBuilds: ["GET /repos/{owner}/{repo}/pages/builds"], - listPublic: ["GET /repositories"], - listPullRequestsAssociatedWithCommit: [ - "GET /repos/{owner}/{repo}/commits/{commit_sha}/pulls" - ], - listReleaseAssets: [ - "GET /repos/{owner}/{repo}/releases/{release_id}/assets" - ], - listReleases: ["GET /repos/{owner}/{repo}/releases"], - listTags: ["GET /repos/{owner}/{repo}/tags"], - listTeams: ["GET /repos/{owner}/{repo}/teams"], - listWebhookDeliveries: [ - "GET /repos/{owner}/{repo}/hooks/{hook_id}/deliveries" - ], - listWebhooks: ["GET /repos/{owner}/{repo}/hooks"], - merge: ["POST /repos/{owner}/{repo}/merges"], - mergeUpstream: ["POST /repos/{owner}/{repo}/merge-upstream"], - pingWebhook: ["POST /repos/{owner}/{repo}/hooks/{hook_id}/pings"], - redeliverWebhookDelivery: [ - "POST /repos/{owner}/{repo}/hooks/{hook_id}/deliveries/{delivery_id}/attempts" - ], - removeAppAccessRestrictions: [ - "DELETE /repos/{owner}/{repo}/branches/{branch}/protection/restrictions/apps", - {}, - { mapToData: "apps" } - ], - removeCollaborator: [ - "DELETE /repos/{owner}/{repo}/collaborators/{username}" - ], - removeStatusCheckContexts: [ - "DELETE /repos/{owner}/{repo}/branches/{branch}/protection/required_status_checks/contexts", - {}, - { mapToData: "contexts" } - ], - removeStatusCheckProtection: [ - "DELETE /repos/{owner}/{repo}/branches/{branch}/protection/required_status_checks" - ], - removeTeamAccessRestrictions: [ - "DELETE /repos/{owner}/{repo}/branches/{branch}/protection/restrictions/teams", - {}, - { mapToData: "teams" } - ], - removeUserAccessRestrictions: [ - "DELETE /repos/{owner}/{repo}/branches/{branch}/protection/restrictions/users", - {}, - { mapToData: "users" } - ], - renameBranch: ["POST /repos/{owner}/{repo}/branches/{branch}/rename"], - replaceAllTopics: ["PUT /repos/{owner}/{repo}/topics"], - requestPagesBuild: ["POST /repos/{owner}/{repo}/pages/builds"], - setAdminBranchProtection: [ - "POST /repos/{owner}/{repo}/branches/{branch}/protection/enforce_admins" - ], - setAppAccessRestrictions: [ - "PUT /repos/{owner}/{repo}/branches/{branch}/protection/restrictions/apps", - {}, - { mapToData: "apps" } - ], - setStatusCheckContexts: [ - "PUT /repos/{owner}/{repo}/branches/{branch}/protection/required_status_checks/contexts", - {}, - { mapToData: "contexts" } - ], - setTeamAccessRestrictions: [ - "PUT /repos/{owner}/{repo}/branches/{branch}/protection/restrictions/teams", - {}, - { mapToData: "teams" } - ], - setUserAccessRestrictions: [ - "PUT /repos/{owner}/{repo}/branches/{branch}/protection/restrictions/users", - {}, - { mapToData: "users" } - ], - testPushWebhook: ["POST /repos/{owner}/{repo}/hooks/{hook_id}/tests"], - transfer: ["POST /repos/{owner}/{repo}/transfer"], - update: ["PATCH /repos/{owner}/{repo}"], - updateBranchProtection: [ - "PUT /repos/{owner}/{repo}/branches/{branch}/protection" - ], - updateCommitComment: ["PATCH /repos/{owner}/{repo}/comments/{comment_id}"], - updateDeploymentBranchPolicy: [ - "PUT /repos/{owner}/{repo}/environments/{environment_name}/deployment-branch-policies/{branch_policy_id}" - ], - updateInformationAboutPagesSite: ["PUT /repos/{owner}/{repo}/pages"], - updateInvitation: [ - "PATCH /repos/{owner}/{repo}/invitations/{invitation_id}" - ], - updateOrgRuleset: ["PUT /orgs/{org}/rulesets/{ruleset_id}"], - updatePullRequestReviewProtection: [ - "PATCH /repos/{owner}/{repo}/branches/{branch}/protection/required_pull_request_reviews" - ], - updateRelease: ["PATCH /repos/{owner}/{repo}/releases/{release_id}"], - updateReleaseAsset: [ - "PATCH /repos/{owner}/{repo}/releases/assets/{asset_id}" - ], - updateRepoRuleset: ["PUT /repos/{owner}/{repo}/rulesets/{ruleset_id}"], - updateStatusCheckPotection: [ - "PATCH /repos/{owner}/{repo}/branches/{branch}/protection/required_status_checks", - {}, - { renamed: ["repos", "updateStatusCheckProtection"] } - ], - updateStatusCheckProtection: [ - "PATCH /repos/{owner}/{repo}/branches/{branch}/protection/required_status_checks" - ], - updateWebhook: ["PATCH /repos/{owner}/{repo}/hooks/{hook_id}"], - updateWebhookConfigForRepo: [ - "PATCH /repos/{owner}/{repo}/hooks/{hook_id}/config" - ], - uploadReleaseAsset: [ - "POST /repos/{owner}/{repo}/releases/{release_id}/assets{?name,label}", - { baseUrl: "https://uploads.github.com" } - ] - }, - search: { - code: ["GET /search/code"], - commits: ["GET /search/commits"], - issuesAndPullRequests: ["GET /search/issues"], - labels: ["GET /search/labels"], - repos: ["GET /search/repositories"], - topics: ["GET /search/topics"], - users: ["GET /search/users"] - }, - secretScanning: { - createPushProtectionBypass: [ - "POST /repos/{owner}/{repo}/secret-scanning/push-protection-bypasses" - ], - getAlert: [ - "GET /repos/{owner}/{repo}/secret-scanning/alerts/{alert_number}" - ], - getScanHistory: ["GET /repos/{owner}/{repo}/secret-scanning/scan-history"], - listAlertsForOrg: ["GET /orgs/{org}/secret-scanning/alerts"], - listAlertsForRepo: ["GET /repos/{owner}/{repo}/secret-scanning/alerts"], - listLocationsForAlert: [ - "GET /repos/{owner}/{repo}/secret-scanning/alerts/{alert_number}/locations" - ], - listOrgPatternConfigs: [ - "GET /orgs/{org}/secret-scanning/pattern-configurations" - ], - updateAlert: [ - "PATCH /repos/{owner}/{repo}/secret-scanning/alerts/{alert_number}" - ], - updateOrgPatternConfigs: [ - "PATCH /orgs/{org}/secret-scanning/pattern-configurations" - ] - }, - securityAdvisories: { - createFork: [ - "POST /repos/{owner}/{repo}/security-advisories/{ghsa_id}/forks" - ], - createPrivateVulnerabilityReport: [ - "POST /repos/{owner}/{repo}/security-advisories/reports" - ], - createRepositoryAdvisory: [ - "POST /repos/{owner}/{repo}/security-advisories" - ], - createRepositoryAdvisoryCveRequest: [ - "POST /repos/{owner}/{repo}/security-advisories/{ghsa_id}/cve" - ], - getGlobalAdvisory: ["GET /advisories/{ghsa_id}"], - getRepositoryAdvisory: [ - "GET /repos/{owner}/{repo}/security-advisories/{ghsa_id}" - ], - listGlobalAdvisories: ["GET /advisories"], - listOrgRepositoryAdvisories: ["GET /orgs/{org}/security-advisories"], - listRepositoryAdvisories: ["GET /repos/{owner}/{repo}/security-advisories"], - updateRepositoryAdvisory: [ - "PATCH /repos/{owner}/{repo}/security-advisories/{ghsa_id}" - ] - }, - teams: { - addOrUpdateMembershipForUserInOrg: [ - "PUT /orgs/{org}/teams/{team_slug}/memberships/{username}" - ], - addOrUpdateRepoPermissionsInOrg: [ - "PUT /orgs/{org}/teams/{team_slug}/repos/{owner}/{repo}" - ], - checkPermissionsForRepoInOrg: [ - "GET /orgs/{org}/teams/{team_slug}/repos/{owner}/{repo}" - ], - create: ["POST /orgs/{org}/teams"], - createDiscussionCommentInOrg: [ - "POST /orgs/{org}/teams/{team_slug}/discussions/{discussion_number}/comments" - ], - createDiscussionInOrg: ["POST /orgs/{org}/teams/{team_slug}/discussions"], - deleteDiscussionCommentInOrg: [ - "DELETE /orgs/{org}/teams/{team_slug}/discussions/{discussion_number}/comments/{comment_number}" - ], - deleteDiscussionInOrg: [ - "DELETE /orgs/{org}/teams/{team_slug}/discussions/{discussion_number}" - ], - deleteInOrg: ["DELETE /orgs/{org}/teams/{team_slug}"], - getByName: ["GET /orgs/{org}/teams/{team_slug}"], - getDiscussionCommentInOrg: [ - "GET /orgs/{org}/teams/{team_slug}/discussions/{discussion_number}/comments/{comment_number}" - ], - getDiscussionInOrg: [ - "GET /orgs/{org}/teams/{team_slug}/discussions/{discussion_number}" - ], - getMembershipForUserInOrg: [ - "GET /orgs/{org}/teams/{team_slug}/memberships/{username}" - ], - list: ["GET /orgs/{org}/teams"], - listChildInOrg: ["GET /orgs/{org}/teams/{team_slug}/teams"], - listDiscussionCommentsInOrg: [ - "GET /orgs/{org}/teams/{team_slug}/discussions/{discussion_number}/comments" - ], - listDiscussionsInOrg: ["GET /orgs/{org}/teams/{team_slug}/discussions"], - listForAuthenticatedUser: ["GET /user/teams"], - listMembersInOrg: ["GET /orgs/{org}/teams/{team_slug}/members"], - listPendingInvitationsInOrg: [ - "GET /orgs/{org}/teams/{team_slug}/invitations" - ], - listReposInOrg: ["GET /orgs/{org}/teams/{team_slug}/repos"], - removeMembershipForUserInOrg: [ - "DELETE /orgs/{org}/teams/{team_slug}/memberships/{username}" - ], - removeRepoInOrg: [ - "DELETE /orgs/{org}/teams/{team_slug}/repos/{owner}/{repo}" - ], - updateDiscussionCommentInOrg: [ - "PATCH /orgs/{org}/teams/{team_slug}/discussions/{discussion_number}/comments/{comment_number}" - ], - updateDiscussionInOrg: [ - "PATCH /orgs/{org}/teams/{team_slug}/discussions/{discussion_number}" - ], - updateInOrg: ["PATCH /orgs/{org}/teams/{team_slug}"] - }, - users: { - addEmailForAuthenticated: [ - "POST /user/emails", - {}, - { renamed: ["users", "addEmailForAuthenticatedUser"] } - ], - addEmailForAuthenticatedUser: ["POST /user/emails"], - addSocialAccountForAuthenticatedUser: ["POST /user/social_accounts"], - block: ["PUT /user/blocks/{username}"], - checkBlocked: ["GET /user/blocks/{username}"], - checkFollowingForUser: ["GET /users/{username}/following/{target_user}"], - checkPersonIsFollowedByAuthenticated: ["GET /user/following/{username}"], - createGpgKeyForAuthenticated: [ - "POST /user/gpg_keys", - {}, - { renamed: ["users", "createGpgKeyForAuthenticatedUser"] } - ], - createGpgKeyForAuthenticatedUser: ["POST /user/gpg_keys"], - createPublicSshKeyForAuthenticated: [ - "POST /user/keys", - {}, - { renamed: ["users", "createPublicSshKeyForAuthenticatedUser"] } - ], - createPublicSshKeyForAuthenticatedUser: ["POST /user/keys"], - createSshSigningKeyForAuthenticatedUser: ["POST /user/ssh_signing_keys"], - deleteAttestationsBulk: [ - "POST /users/{username}/attestations/delete-request" - ], - deleteAttestationsById: [ - "DELETE /users/{username}/attestations/{attestation_id}" - ], - deleteAttestationsBySubjectDigest: [ - "DELETE /users/{username}/attestations/digest/{subject_digest}" - ], - deleteEmailForAuthenticated: [ - "DELETE /user/emails", - {}, - { renamed: ["users", "deleteEmailForAuthenticatedUser"] } - ], - deleteEmailForAuthenticatedUser: ["DELETE /user/emails"], - deleteGpgKeyForAuthenticated: [ - "DELETE /user/gpg_keys/{gpg_key_id}", - {}, - { renamed: ["users", "deleteGpgKeyForAuthenticatedUser"] } - ], - deleteGpgKeyForAuthenticatedUser: ["DELETE /user/gpg_keys/{gpg_key_id}"], - deletePublicSshKeyForAuthenticated: [ - "DELETE /user/keys/{key_id}", - {}, - { renamed: ["users", "deletePublicSshKeyForAuthenticatedUser"] } - ], - deletePublicSshKeyForAuthenticatedUser: ["DELETE /user/keys/{key_id}"], - deleteSocialAccountForAuthenticatedUser: ["DELETE /user/social_accounts"], - deleteSshSigningKeyForAuthenticatedUser: [ - "DELETE /user/ssh_signing_keys/{ssh_signing_key_id}" - ], - follow: ["PUT /user/following/{username}"], - getAuthenticated: ["GET /user"], - getById: ["GET /user/{account_id}"], - getByUsername: ["GET /users/{username}"], - getContextForUser: ["GET /users/{username}/hovercard"], - getGpgKeyForAuthenticated: [ - "GET /user/gpg_keys/{gpg_key_id}", - {}, - { renamed: ["users", "getGpgKeyForAuthenticatedUser"] } - ], - getGpgKeyForAuthenticatedUser: ["GET /user/gpg_keys/{gpg_key_id}"], - getPublicSshKeyForAuthenticated: [ - "GET /user/keys/{key_id}", - {}, - { renamed: ["users", "getPublicSshKeyForAuthenticatedUser"] } - ], - getPublicSshKeyForAuthenticatedUser: ["GET /user/keys/{key_id}"], - getSshSigningKeyForAuthenticatedUser: [ - "GET /user/ssh_signing_keys/{ssh_signing_key_id}" - ], - list: ["GET /users"], - listAttestations: ["GET /users/{username}/attestations/{subject_digest}"], - listAttestationsBulk: [ - "POST /users/{username}/attestations/bulk-list{?per_page,before,after}" - ], - listBlockedByAuthenticated: [ - "GET /user/blocks", - {}, - { renamed: ["users", "listBlockedByAuthenticatedUser"] } - ], - listBlockedByAuthenticatedUser: ["GET /user/blocks"], - listEmailsForAuthenticated: [ - "GET /user/emails", - {}, - { renamed: ["users", "listEmailsForAuthenticatedUser"] } - ], - listEmailsForAuthenticatedUser: ["GET /user/emails"], - listFollowedByAuthenticated: [ - "GET /user/following", - {}, - { renamed: ["users", "listFollowedByAuthenticatedUser"] } - ], - listFollowedByAuthenticatedUser: ["GET /user/following"], - listFollowersForAuthenticatedUser: ["GET /user/followers"], - listFollowersForUser: ["GET /users/{username}/followers"], - listFollowingForUser: ["GET /users/{username}/following"], - listGpgKeysForAuthenticated: [ - "GET /user/gpg_keys", - {}, - { renamed: ["users", "listGpgKeysForAuthenticatedUser"] } - ], - listGpgKeysForAuthenticatedUser: ["GET /user/gpg_keys"], - listGpgKeysForUser: ["GET /users/{username}/gpg_keys"], - listPublicEmailsForAuthenticated: [ - "GET /user/public_emails", - {}, - { renamed: ["users", "listPublicEmailsForAuthenticatedUser"] } - ], - listPublicEmailsForAuthenticatedUser: ["GET /user/public_emails"], - listPublicKeysForUser: ["GET /users/{username}/keys"], - listPublicSshKeysForAuthenticated: [ - "GET /user/keys", - {}, - { renamed: ["users", "listPublicSshKeysForAuthenticatedUser"] } - ], - listPublicSshKeysForAuthenticatedUser: ["GET /user/keys"], - listSocialAccountsForAuthenticatedUser: ["GET /user/social_accounts"], - listSocialAccountsForUser: ["GET /users/{username}/social_accounts"], - listSshSigningKeysForAuthenticatedUser: ["GET /user/ssh_signing_keys"], - listSshSigningKeysForUser: ["GET /users/{username}/ssh_signing_keys"], - setPrimaryEmailVisibilityForAuthenticated: [ - "PATCH /user/email/visibility", - {}, - { renamed: ["users", "setPrimaryEmailVisibilityForAuthenticatedUser"] } - ], - setPrimaryEmailVisibilityForAuthenticatedUser: [ - "PATCH /user/email/visibility" - ], - unblock: ["DELETE /user/blocks/{username}"], - unfollow: ["DELETE /user/following/{username}"], - updateAuthenticated: ["PATCH /user"] - } -}; -var endpoints_default$1 = Endpoints$1; - -const endpointMethodsMap$1 = /* @__PURE__ */ new Map(); -for (const [scope, endpoints] of Object.entries(endpoints_default$1)) { - for (const [methodName, endpoint] of Object.entries(endpoints)) { - const [route, defaults, decorations] = endpoint; - const [method, url] = route.split(/ /); - const endpointDefaults = Object.assign( - { - method, - url - }, - defaults - ); - if (!endpointMethodsMap$1.has(scope)) { - endpointMethodsMap$1.set(scope, /* @__PURE__ */ new Map()); - } - endpointMethodsMap$1.get(scope).set(methodName, { - scope, - methodName, - endpointDefaults, - decorations - }); - } -} -const handler$1 = { - has({ scope }, methodName) { - return endpointMethodsMap$1.get(scope).has(methodName); - }, - getOwnPropertyDescriptor(target, methodName) { - return { - value: this.get(target, methodName), - // ensures method is in the cache - configurable: true, - writable: true, - enumerable: true - }; - }, - defineProperty(target, methodName, descriptor) { - Object.defineProperty(target.cache, methodName, descriptor); - return true; - }, - deleteProperty(target, methodName) { - delete target.cache[methodName]; - return true; - }, - ownKeys({ scope }) { - return [...endpointMethodsMap$1.get(scope).keys()]; - }, - set(target, methodName, value) { - return target.cache[methodName] = value; - }, - get({ octokit, scope, cache }, methodName) { - if (cache[methodName]) { - return cache[methodName]; - } - const method = endpointMethodsMap$1.get(scope).get(methodName); - if (!method) { - return void 0; - } - const { endpointDefaults, decorations } = method; - if (decorations) { - cache[methodName] = decorate$1( - octokit, - scope, - methodName, - endpointDefaults, - decorations - ); - } else { - cache[methodName] = octokit.request.defaults(endpointDefaults); - } - return cache[methodName]; - } -}; -function endpointsToMethods$1(octokit) { - const newMethods = {}; - for (const scope of endpointMethodsMap$1.keys()) { - newMethods[scope] = new Proxy({ octokit, scope, cache: {} }, handler$1); - } - return newMethods; -} -function decorate$1(octokit, scope, methodName, defaults, decorations) { - const requestWithDefaults = octokit.request.defaults(defaults); - function withDecorations(...args) { - let options = requestWithDefaults.endpoint.merge(...args); - if (decorations.mapToData) { - options = Object.assign({}, options, { - data: options[decorations.mapToData], - [decorations.mapToData]: void 0 - }); - return requestWithDefaults(options); - } - if (decorations.renamed) { - const [newScope, newMethodName] = decorations.renamed; - octokit.log.warn( - `octokit.${scope}.${methodName}() has been renamed to octokit.${newScope}.${newMethodName}()` - ); - } - if (decorations.deprecated) { - octokit.log.warn(decorations.deprecated); - } - if (decorations.renamedParameters) { - const options2 = requestWithDefaults.endpoint.merge(...args); - for (const [name, alias] of Object.entries( - decorations.renamedParameters - )) { - if (name in options2) { - octokit.log.warn( - `"${name}" parameter is deprecated for "octokit.${scope}.${methodName}()". Use "${alias}" instead` - ); - if (!(alias in options2)) { - options2[alias] = options2[name]; - } - delete options2[name]; - } - } - return requestWithDefaults(options2); - } - return requestWithDefaults(...args); - } - return Object.assign(withDecorations, requestWithDefaults); -} - -function legacyRestEndpointMethods$1(octokit) { - const api = endpointsToMethods$1(octokit); - return { - ...api, - rest: api - }; -} -legacyRestEndpointMethods$1.VERSION = VERSION$7; - -const VERSION$6 = "22.0.1"; - -const Octokit$1 = Octokit$2.plugin(requestLog, legacyRestEndpointMethods$1, paginateRest$1).defaults( - { - userAgent: `octokit-rest.js/${VERSION$6}` - } -); - -var github = {}; - -var context = {}; - -var hasRequiredContext; - -function requireContext () { - if (hasRequiredContext) return context; - hasRequiredContext = 1; - Object.defineProperty(context, "__esModule", { value: true }); - context.Context = void 0; - const fs_1 = fs; - const os_1 = require$$0; - class Context { - /** - * Hydrate the context from the environment - */ - constructor() { - var _a, _b, _c; - this.payload = {}; - if (process.env.GITHUB_EVENT_PATH) { - if ((0, fs_1.existsSync)(process.env.GITHUB_EVENT_PATH)) { - this.payload = JSON.parse((0, fs_1.readFileSync)(process.env.GITHUB_EVENT_PATH, { encoding: 'utf8' })); - } - else { - const path = process.env.GITHUB_EVENT_PATH; - process.stdout.write(`GITHUB_EVENT_PATH ${path} does not exist${os_1.EOL}`); - } - } - this.eventName = process.env.GITHUB_EVENT_NAME; - this.sha = process.env.GITHUB_SHA; - this.ref = process.env.GITHUB_REF; - this.workflow = process.env.GITHUB_WORKFLOW; - this.action = process.env.GITHUB_ACTION; - this.actor = process.env.GITHUB_ACTOR; - this.job = process.env.GITHUB_JOB; - this.runAttempt = parseInt(process.env.GITHUB_RUN_ATTEMPT, 10); - this.runNumber = parseInt(process.env.GITHUB_RUN_NUMBER, 10); - this.runId = parseInt(process.env.GITHUB_RUN_ID, 10); - this.apiUrl = (_a = process.env.GITHUB_API_URL) !== null && _a !== void 0 ? _a : `https://api.github.com`; - this.serverUrl = (_b = process.env.GITHUB_SERVER_URL) !== null && _b !== void 0 ? _b : `https://github.com`; - this.graphqlUrl = - (_c = process.env.GITHUB_GRAPHQL_URL) !== null && _c !== void 0 ? _c : `https://api.github.com/graphql`; - } - get issue() { - const payload = this.payload; - return Object.assign(Object.assign({}, this.repo), { number: (payload.issue || payload.pull_request || payload).number }); - } - get repo() { - if (process.env.GITHUB_REPOSITORY) { - const [owner, repo] = process.env.GITHUB_REPOSITORY.split('/'); - return { owner, repo }; - } - if (this.payload.repository) { - return { - owner: this.payload.repository.owner.login, - repo: this.payload.repository.name - }; - } - throw new Error("context.repo requires a GITHUB_REPOSITORY environment variable like 'owner/repo'"); - } - } - context.Context = Context; - - return context; -} - -var utils$2 = {}; - -var utils$1 = {}; - -var lib$1 = {}; - -var proxy = {}; - -var hasRequiredProxy; - -function requireProxy () { - if (hasRequiredProxy) return proxy; - hasRequiredProxy = 1; - Object.defineProperty(proxy, "__esModule", { value: true }); - proxy.checkBypass = proxy.getProxyUrl = void 0; - function getProxyUrl(reqUrl) { - const usingSsl = reqUrl.protocol === 'https:'; - if (checkBypass(reqUrl)) { - return undefined; - } - const proxyVar = (() => { - if (usingSsl) { - return process.env['https_proxy'] || process.env['HTTPS_PROXY']; - } - else { - return process.env['http_proxy'] || process.env['HTTP_PROXY']; - } - })(); - if (proxyVar) { - try { - return new DecodedURL(proxyVar); - } - catch (_a) { - if (!proxyVar.startsWith('http://') && !proxyVar.startsWith('https://')) - return new DecodedURL(`http://${proxyVar}`); - } - } - else { - return undefined; - } - } - proxy.getProxyUrl = getProxyUrl; - function checkBypass(reqUrl) { - if (!reqUrl.hostname) { - return false; - } - const reqHost = reqUrl.hostname; - if (isLoopbackAddress(reqHost)) { - return true; - } - const noProxy = process.env['no_proxy'] || process.env['NO_PROXY'] || ''; - if (!noProxy) { - return false; - } - // Determine the request port - let reqPort; - if (reqUrl.port) { - reqPort = Number(reqUrl.port); - } - else if (reqUrl.protocol === 'http:') { - reqPort = 80; - } - else if (reqUrl.protocol === 'https:') { - reqPort = 443; - } - // Format the request hostname and hostname with port - const upperReqHosts = [reqUrl.hostname.toUpperCase()]; - if (typeof reqPort === 'number') { - upperReqHosts.push(`${upperReqHosts[0]}:${reqPort}`); - } - // Compare request host against noproxy - for (const upperNoProxyItem of noProxy - .split(',') - .map(x => x.trim().toUpperCase()) - .filter(x => x)) { - if (upperNoProxyItem === '*' || - upperReqHosts.some(x => x === upperNoProxyItem || - x.endsWith(`.${upperNoProxyItem}`) || - (upperNoProxyItem.startsWith('.') && - x.endsWith(`${upperNoProxyItem}`)))) { - return true; - } - } - return false; - } - proxy.checkBypass = checkBypass; - function isLoopbackAddress(host) { - const hostLower = host.toLowerCase(); - return (hostLower === 'localhost' || - hostLower.startsWith('127.') || - hostLower.startsWith('[::1]') || - hostLower.startsWith('[0:0:0:0:0:0:0:1]')); - } - class DecodedURL extends URL { - constructor(url, base) { - super(url, base); - this._decodedUsername = decodeURIComponent(super.username); - this._decodedPassword = decodeURIComponent(super.password); - } - get username() { - return this._decodedUsername; - } - get password() { - return this._decodedPassword; - } - } - - return proxy; -} - -var hasRequiredLib$1; - -function requireLib$1 () { - if (hasRequiredLib$1) return lib$1; - hasRequiredLib$1 = 1; - /* eslint-disable @typescript-eslint/no-explicit-any */ - var __createBinding = (lib$1 && lib$1.__createBinding) || (Object.create ? (function(o, m, k, k2) { - if (k2 === undefined) k2 = k; - var desc = Object.getOwnPropertyDescriptor(m, k); - if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { - desc = { enumerable: true, get: function() { return m[k]; } }; - } - Object.defineProperty(o, k2, desc); - }) : (function(o, m, k, k2) { - if (k2 === undefined) k2 = k; - o[k2] = m[k]; - })); - var __setModuleDefault = (lib$1 && lib$1.__setModuleDefault) || (Object.create ? (function(o, v) { - Object.defineProperty(o, "default", { enumerable: true, value: v }); - }) : function(o, v) { - o["default"] = v; - }); - var __importStar = (lib$1 && lib$1.__importStar) || function (mod) { - if (mod && mod.__esModule) return mod; - var result = {}; - if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); - __setModuleDefault(result, mod); - return result; - }; - var __awaiter = (lib$1 && lib$1.__awaiter) || function (thisArg, _arguments, P, generator) { - function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } - return new (P || (P = Promise))(function (resolve, reject) { - function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } - function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } - function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } - step((generator = generator.apply(thisArg, _arguments || [])).next()); - }); - }; - Object.defineProperty(lib$1, "__esModule", { value: true }); - lib$1.HttpClient = lib$1.isHttps = lib$1.HttpClientResponse = lib$1.HttpClientError = lib$1.getProxyUrl = lib$1.MediaTypes = lib$1.Headers = lib$1.HttpCodes = void 0; - const http = __importStar(require$$2$1); - const https = __importStar(require$$1); - const pm = __importStar(requireProxy()); - const tunnel = __importStar(requireTunnel()); - const undici_1 = requireUndici(); - var HttpCodes; - (function (HttpCodes) { - HttpCodes[HttpCodes["OK"] = 200] = "OK"; - HttpCodes[HttpCodes["MultipleChoices"] = 300] = "MultipleChoices"; - HttpCodes[HttpCodes["MovedPermanently"] = 301] = "MovedPermanently"; - HttpCodes[HttpCodes["ResourceMoved"] = 302] = "ResourceMoved"; - HttpCodes[HttpCodes["SeeOther"] = 303] = "SeeOther"; - HttpCodes[HttpCodes["NotModified"] = 304] = "NotModified"; - HttpCodes[HttpCodes["UseProxy"] = 305] = "UseProxy"; - HttpCodes[HttpCodes["SwitchProxy"] = 306] = "SwitchProxy"; - HttpCodes[HttpCodes["TemporaryRedirect"] = 307] = "TemporaryRedirect"; - HttpCodes[HttpCodes["PermanentRedirect"] = 308] = "PermanentRedirect"; - HttpCodes[HttpCodes["BadRequest"] = 400] = "BadRequest"; - HttpCodes[HttpCodes["Unauthorized"] = 401] = "Unauthorized"; - HttpCodes[HttpCodes["PaymentRequired"] = 402] = "PaymentRequired"; - HttpCodes[HttpCodes["Forbidden"] = 403] = "Forbidden"; - HttpCodes[HttpCodes["NotFound"] = 404] = "NotFound"; - HttpCodes[HttpCodes["MethodNotAllowed"] = 405] = "MethodNotAllowed"; - HttpCodes[HttpCodes["NotAcceptable"] = 406] = "NotAcceptable"; - HttpCodes[HttpCodes["ProxyAuthenticationRequired"] = 407] = "ProxyAuthenticationRequired"; - HttpCodes[HttpCodes["RequestTimeout"] = 408] = "RequestTimeout"; - HttpCodes[HttpCodes["Conflict"] = 409] = "Conflict"; - HttpCodes[HttpCodes["Gone"] = 410] = "Gone"; - HttpCodes[HttpCodes["TooManyRequests"] = 429] = "TooManyRequests"; - HttpCodes[HttpCodes["InternalServerError"] = 500] = "InternalServerError"; - HttpCodes[HttpCodes["NotImplemented"] = 501] = "NotImplemented"; - HttpCodes[HttpCodes["BadGateway"] = 502] = "BadGateway"; - HttpCodes[HttpCodes["ServiceUnavailable"] = 503] = "ServiceUnavailable"; - HttpCodes[HttpCodes["GatewayTimeout"] = 504] = "GatewayTimeout"; - })(HttpCodes || (lib$1.HttpCodes = HttpCodes = {})); - var Headers; - (function (Headers) { - Headers["Accept"] = "accept"; - Headers["ContentType"] = "content-type"; - })(Headers || (lib$1.Headers = Headers = {})); - var MediaTypes; - (function (MediaTypes) { - MediaTypes["ApplicationJson"] = "application/json"; - })(MediaTypes || (lib$1.MediaTypes = MediaTypes = {})); - /** - * Returns the proxy URL, depending upon the supplied url and proxy environment variables. - * @param serverUrl The server URL where the request will be sent. For example, https://api.github.com - */ - function getProxyUrl(serverUrl) { - const proxyUrl = pm.getProxyUrl(new URL(serverUrl)); - return proxyUrl ? proxyUrl.href : ''; - } - lib$1.getProxyUrl = getProxyUrl; - const HttpRedirectCodes = [ - HttpCodes.MovedPermanently, - HttpCodes.ResourceMoved, - HttpCodes.SeeOther, - HttpCodes.TemporaryRedirect, - HttpCodes.PermanentRedirect - ]; - const HttpResponseRetryCodes = [ - HttpCodes.BadGateway, - HttpCodes.ServiceUnavailable, - HttpCodes.GatewayTimeout - ]; - const RetryableHttpVerbs = ['OPTIONS', 'GET', 'DELETE', 'HEAD']; - const ExponentialBackoffCeiling = 10; - const ExponentialBackoffTimeSlice = 5; - class HttpClientError extends Error { - constructor(message, statusCode) { - super(message); - this.name = 'HttpClientError'; - this.statusCode = statusCode; - Object.setPrototypeOf(this, HttpClientError.prototype); - } - } - lib$1.HttpClientError = HttpClientError; - class HttpClientResponse { - constructor(message) { - this.message = message; - } - readBody() { - return __awaiter(this, void 0, void 0, function* () { - return new Promise((resolve) => __awaiter(this, void 0, void 0, function* () { - let output = Buffer.alloc(0); - this.message.on('data', (chunk) => { - output = Buffer.concat([output, chunk]); - }); - this.message.on('end', () => { - resolve(output.toString()); - }); - })); - }); - } - readBodyBuffer() { - return __awaiter(this, void 0, void 0, function* () { - return new Promise((resolve) => __awaiter(this, void 0, void 0, function* () { - const chunks = []; - this.message.on('data', (chunk) => { - chunks.push(chunk); - }); - this.message.on('end', () => { - resolve(Buffer.concat(chunks)); - }); - })); - }); - } - } - lib$1.HttpClientResponse = HttpClientResponse; - function isHttps(requestUrl) { - const parsedUrl = new URL(requestUrl); - return parsedUrl.protocol === 'https:'; - } - lib$1.isHttps = isHttps; - class HttpClient { - constructor(userAgent, handlers, requestOptions) { - this._ignoreSslError = false; - this._allowRedirects = true; - this._allowRedirectDowngrade = false; - this._maxRedirects = 50; - this._allowRetries = false; - this._maxRetries = 1; - this._keepAlive = false; - this._disposed = false; - this.userAgent = userAgent; - this.handlers = handlers || []; - this.requestOptions = requestOptions; - if (requestOptions) { - if (requestOptions.ignoreSslError != null) { - this._ignoreSslError = requestOptions.ignoreSslError; - } - this._socketTimeout = requestOptions.socketTimeout; - if (requestOptions.allowRedirects != null) { - this._allowRedirects = requestOptions.allowRedirects; - } - if (requestOptions.allowRedirectDowngrade != null) { - this._allowRedirectDowngrade = requestOptions.allowRedirectDowngrade; - } - if (requestOptions.maxRedirects != null) { - this._maxRedirects = Math.max(requestOptions.maxRedirects, 0); - } - if (requestOptions.keepAlive != null) { - this._keepAlive = requestOptions.keepAlive; - } - if (requestOptions.allowRetries != null) { - this._allowRetries = requestOptions.allowRetries; - } - if (requestOptions.maxRetries != null) { - this._maxRetries = requestOptions.maxRetries; - } - } - } - options(requestUrl, additionalHeaders) { - return __awaiter(this, void 0, void 0, function* () { - return this.request('OPTIONS', requestUrl, null, additionalHeaders || {}); - }); - } - get(requestUrl, additionalHeaders) { - return __awaiter(this, void 0, void 0, function* () { - return this.request('GET', requestUrl, null, additionalHeaders || {}); - }); - } - del(requestUrl, additionalHeaders) { - return __awaiter(this, void 0, void 0, function* () { - return this.request('DELETE', requestUrl, null, additionalHeaders || {}); - }); - } - post(requestUrl, data, additionalHeaders) { - return __awaiter(this, void 0, void 0, function* () { - return this.request('POST', requestUrl, data, additionalHeaders || {}); - }); - } - patch(requestUrl, data, additionalHeaders) { - return __awaiter(this, void 0, void 0, function* () { - return this.request('PATCH', requestUrl, data, additionalHeaders || {}); - }); - } - put(requestUrl, data, additionalHeaders) { - return __awaiter(this, void 0, void 0, function* () { - return this.request('PUT', requestUrl, data, additionalHeaders || {}); - }); - } - head(requestUrl, additionalHeaders) { - return __awaiter(this, void 0, void 0, function* () { - return this.request('HEAD', requestUrl, null, additionalHeaders || {}); - }); - } - sendStream(verb, requestUrl, stream, additionalHeaders) { - return __awaiter(this, void 0, void 0, function* () { - return this.request(verb, requestUrl, stream, additionalHeaders); - }); - } - /** - * Gets a typed object from an endpoint - * Be aware that not found returns a null. Other errors (4xx, 5xx) reject the promise - */ - getJson(requestUrl, additionalHeaders = {}) { - return __awaiter(this, void 0, void 0, function* () { - additionalHeaders[Headers.Accept] = this._getExistingOrDefaultHeader(additionalHeaders, Headers.Accept, MediaTypes.ApplicationJson); - const res = yield this.get(requestUrl, additionalHeaders); - return this._processResponse(res, this.requestOptions); - }); - } - postJson(requestUrl, obj, additionalHeaders = {}) { - return __awaiter(this, void 0, void 0, function* () { - const data = JSON.stringify(obj, null, 2); - additionalHeaders[Headers.Accept] = this._getExistingOrDefaultHeader(additionalHeaders, Headers.Accept, MediaTypes.ApplicationJson); - additionalHeaders[Headers.ContentType] = this._getExistingOrDefaultHeader(additionalHeaders, Headers.ContentType, MediaTypes.ApplicationJson); - const res = yield this.post(requestUrl, data, additionalHeaders); - return this._processResponse(res, this.requestOptions); - }); - } - putJson(requestUrl, obj, additionalHeaders = {}) { - return __awaiter(this, void 0, void 0, function* () { - const data = JSON.stringify(obj, null, 2); - additionalHeaders[Headers.Accept] = this._getExistingOrDefaultHeader(additionalHeaders, Headers.Accept, MediaTypes.ApplicationJson); - additionalHeaders[Headers.ContentType] = this._getExistingOrDefaultHeader(additionalHeaders, Headers.ContentType, MediaTypes.ApplicationJson); - const res = yield this.put(requestUrl, data, additionalHeaders); - return this._processResponse(res, this.requestOptions); - }); - } - patchJson(requestUrl, obj, additionalHeaders = {}) { - return __awaiter(this, void 0, void 0, function* () { - const data = JSON.stringify(obj, null, 2); - additionalHeaders[Headers.Accept] = this._getExistingOrDefaultHeader(additionalHeaders, Headers.Accept, MediaTypes.ApplicationJson); - additionalHeaders[Headers.ContentType] = this._getExistingOrDefaultHeader(additionalHeaders, Headers.ContentType, MediaTypes.ApplicationJson); - const res = yield this.patch(requestUrl, data, additionalHeaders); - return this._processResponse(res, this.requestOptions); - }); - } - /** - * Makes a raw http request. - * All other methods such as get, post, patch, and request ultimately call this. - * Prefer get, del, post and patch - */ - request(verb, requestUrl, data, headers) { - return __awaiter(this, void 0, void 0, function* () { - if (this._disposed) { - throw new Error('Client has already been disposed.'); - } - const parsedUrl = new URL(requestUrl); - let info = this._prepareRequest(verb, parsedUrl, headers); - // Only perform retries on reads since writes may not be idempotent. - const maxTries = this._allowRetries && RetryableHttpVerbs.includes(verb) - ? this._maxRetries + 1 - : 1; - let numTries = 0; - let response; - do { - response = yield this.requestRaw(info, data); - // Check if it's an authentication challenge - if (response && - response.message && - response.message.statusCode === HttpCodes.Unauthorized) { - let authenticationHandler; - for (const handler of this.handlers) { - if (handler.canHandleAuthentication(response)) { - authenticationHandler = handler; - break; - } - } - if (authenticationHandler) { - return authenticationHandler.handleAuthentication(this, info, data); - } - else { - // We have received an unauthorized response but have no handlers to handle it. - // Let the response return to the caller. - return response; - } - } - let redirectsRemaining = this._maxRedirects; - while (response.message.statusCode && - HttpRedirectCodes.includes(response.message.statusCode) && - this._allowRedirects && - redirectsRemaining > 0) { - const redirectUrl = response.message.headers['location']; - if (!redirectUrl) { - // if there's no location to redirect to, we won't - break; - } - const parsedRedirectUrl = new URL(redirectUrl); - if (parsedUrl.protocol === 'https:' && - parsedUrl.protocol !== parsedRedirectUrl.protocol && - !this._allowRedirectDowngrade) { - throw new Error('Redirect from HTTPS to HTTP protocol. This downgrade is not allowed for security reasons. If you want to allow this behavior, set the allowRedirectDowngrade option to true.'); - } - // we need to finish reading the response before reassigning response - // which will leak the open socket. - yield response.readBody(); - // strip authorization header if redirected to a different hostname - if (parsedRedirectUrl.hostname !== parsedUrl.hostname) { - for (const header in headers) { - // header names are case insensitive - if (header.toLowerCase() === 'authorization') { - delete headers[header]; - } - } - } - // let's make the request with the new redirectUrl - info = this._prepareRequest(verb, parsedRedirectUrl, headers); - response = yield this.requestRaw(info, data); - redirectsRemaining--; - } - if (!response.message.statusCode || - !HttpResponseRetryCodes.includes(response.message.statusCode)) { - // If not a retry code, return immediately instead of retrying - return response; - } - numTries += 1; - if (numTries < maxTries) { - yield response.readBody(); - yield this._performExponentialBackoff(numTries); - } - } while (numTries < maxTries); - return response; - }); - } - /** - * Needs to be called if keepAlive is set to true in request options. - */ - dispose() { - if (this._agent) { - this._agent.destroy(); - } - this._disposed = true; - } - /** - * Raw request. - * @param info - * @param data - */ - requestRaw(info, data) { - return __awaiter(this, void 0, void 0, function* () { - return new Promise((resolve, reject) => { - function callbackForResult(err, res) { - if (err) { - reject(err); - } - else if (!res) { - // If `err` is not passed, then `res` must be passed. - reject(new Error('Unknown error')); - } - else { - resolve(res); - } - } - this.requestRawWithCallback(info, data, callbackForResult); - }); - }); - } - /** - * Raw request with callback. - * @param info - * @param data - * @param onResult - */ - requestRawWithCallback(info, data, onResult) { - if (typeof data === 'string') { - if (!info.options.headers) { - info.options.headers = {}; - } - info.options.headers['Content-Length'] = Buffer.byteLength(data, 'utf8'); - } - let callbackCalled = false; - function handleResult(err, res) { - if (!callbackCalled) { - callbackCalled = true; - onResult(err, res); - } - } - const req = info.httpModule.request(info.options, (msg) => { - const res = new HttpClientResponse(msg); - handleResult(undefined, res); - }); - let socket; - req.on('socket', sock => { - socket = sock; - }); - // If we ever get disconnected, we want the socket to timeout eventually - req.setTimeout(this._socketTimeout || 3 * 60000, () => { - if (socket) { - socket.end(); - } - handleResult(new Error(`Request timeout: ${info.options.path}`)); - }); - req.on('error', function (err) { - // err has statusCode property - // res should have headers - handleResult(err); - }); - if (data && typeof data === 'string') { - req.write(data, 'utf8'); - } - if (data && typeof data !== 'string') { - data.on('close', function () { - req.end(); - }); - data.pipe(req); - } - else { - req.end(); - } - } - /** - * Gets an http agent. This function is useful when you need an http agent that handles - * routing through a proxy server - depending upon the url and proxy environment variables. - * @param serverUrl The server URL where the request will be sent. For example, https://api.github.com - */ - getAgent(serverUrl) { - const parsedUrl = new URL(serverUrl); - return this._getAgent(parsedUrl); - } - getAgentDispatcher(serverUrl) { - const parsedUrl = new URL(serverUrl); - const proxyUrl = pm.getProxyUrl(parsedUrl); - const useProxy = proxyUrl && proxyUrl.hostname; - if (!useProxy) { - return; - } - return this._getProxyAgentDispatcher(parsedUrl, proxyUrl); - } - _prepareRequest(method, requestUrl, headers) { - const info = {}; - info.parsedUrl = requestUrl; - const usingSsl = info.parsedUrl.protocol === 'https:'; - info.httpModule = usingSsl ? https : http; - const defaultPort = usingSsl ? 443 : 80; - info.options = {}; - info.options.host = info.parsedUrl.hostname; - info.options.port = info.parsedUrl.port - ? parseInt(info.parsedUrl.port) - : defaultPort; - info.options.path = - (info.parsedUrl.pathname || '') + (info.parsedUrl.search || ''); - info.options.method = method; - info.options.headers = this._mergeHeaders(headers); - if (this.userAgent != null) { - info.options.headers['user-agent'] = this.userAgent; - } - info.options.agent = this._getAgent(info.parsedUrl); - // gives handlers an opportunity to participate - if (this.handlers) { - for (const handler of this.handlers) { - handler.prepareRequest(info.options); - } - } - return info; - } - _mergeHeaders(headers) { - if (this.requestOptions && this.requestOptions.headers) { - return Object.assign({}, lowercaseKeys(this.requestOptions.headers), lowercaseKeys(headers || {})); - } - return lowercaseKeys(headers || {}); - } - _getExistingOrDefaultHeader(additionalHeaders, header, _default) { - let clientHeader; - if (this.requestOptions && this.requestOptions.headers) { - clientHeader = lowercaseKeys(this.requestOptions.headers)[header]; - } - return additionalHeaders[header] || clientHeader || _default; - } - _getAgent(parsedUrl) { - let agent; - const proxyUrl = pm.getProxyUrl(parsedUrl); - const useProxy = proxyUrl && proxyUrl.hostname; - if (this._keepAlive && useProxy) { - agent = this._proxyAgent; - } - if (!useProxy) { - agent = this._agent; - } - // if agent is already assigned use that agent. - if (agent) { - return agent; - } - const usingSsl = parsedUrl.protocol === 'https:'; - let maxSockets = 100; - if (this.requestOptions) { - maxSockets = this.requestOptions.maxSockets || http.globalAgent.maxSockets; - } - // This is `useProxy` again, but we need to check `proxyURl` directly for TypeScripts's flow analysis. - if (proxyUrl && proxyUrl.hostname) { - const agentOptions = { - maxSockets, - keepAlive: this._keepAlive, - proxy: Object.assign(Object.assign({}, ((proxyUrl.username || proxyUrl.password) && { - proxyAuth: `${proxyUrl.username}:${proxyUrl.password}` - })), { host: proxyUrl.hostname, port: proxyUrl.port }) - }; - let tunnelAgent; - const overHttps = proxyUrl.protocol === 'https:'; - if (usingSsl) { - tunnelAgent = overHttps ? tunnel.httpsOverHttps : tunnel.httpsOverHttp; - } - else { - tunnelAgent = overHttps ? tunnel.httpOverHttps : tunnel.httpOverHttp; - } - agent = tunnelAgent(agentOptions); - this._proxyAgent = agent; - } - // if tunneling agent isn't assigned create a new agent - if (!agent) { - const options = { keepAlive: this._keepAlive, maxSockets }; - agent = usingSsl ? new https.Agent(options) : new http.Agent(options); - this._agent = agent; - } - if (usingSsl && this._ignoreSslError) { - // we don't want to set NODE_TLS_REJECT_UNAUTHORIZED=0 since that will affect request for entire process - // http.RequestOptions doesn't expose a way to modify RequestOptions.agent.options - // we have to cast it to any and change it directly - agent.options = Object.assign(agent.options || {}, { - rejectUnauthorized: false - }); - } - return agent; - } - _getProxyAgentDispatcher(parsedUrl, proxyUrl) { - let proxyAgent; - if (this._keepAlive) { - proxyAgent = this._proxyAgentDispatcher; - } - // if agent is already assigned use that agent. - if (proxyAgent) { - return proxyAgent; - } - const usingSsl = parsedUrl.protocol === 'https:'; - proxyAgent = new undici_1.ProxyAgent(Object.assign({ uri: proxyUrl.href, pipelining: !this._keepAlive ? 0 : 1 }, ((proxyUrl.username || proxyUrl.password) && { - token: `Basic ${Buffer.from(`${proxyUrl.username}:${proxyUrl.password}`).toString('base64')}` - }))); - this._proxyAgentDispatcher = proxyAgent; - if (usingSsl && this._ignoreSslError) { - // we don't want to set NODE_TLS_REJECT_UNAUTHORIZED=0 since that will affect request for entire process - // http.RequestOptions doesn't expose a way to modify RequestOptions.agent.options - // we have to cast it to any and change it directly - proxyAgent.options = Object.assign(proxyAgent.options.requestTls || {}, { - rejectUnauthorized: false - }); - } - return proxyAgent; - } - _performExponentialBackoff(retryNumber) { - return __awaiter(this, void 0, void 0, function* () { - retryNumber = Math.min(ExponentialBackoffCeiling, retryNumber); - const ms = ExponentialBackoffTimeSlice * Math.pow(2, retryNumber); - return new Promise(resolve => setTimeout(() => resolve(), ms)); - }); - } - _processResponse(res, options) { - return __awaiter(this, void 0, void 0, function* () { - return new Promise((resolve, reject) => __awaiter(this, void 0, void 0, function* () { - const statusCode = res.message.statusCode || 0; - const response = { - statusCode, - result: null, - headers: {} - }; - // not found leads to null obj returned - if (statusCode === HttpCodes.NotFound) { - resolve(response); - } - // get the result from the body - function dateTimeDeserializer(key, value) { - if (typeof value === 'string') { - const a = new Date(value); - if (!isNaN(a.valueOf())) { - return a; - } - } - return value; - } - let obj; - let contents; - try { - contents = yield res.readBody(); - if (contents && contents.length > 0) { - if (options && options.deserializeDates) { - obj = JSON.parse(contents, dateTimeDeserializer); - } - else { - obj = JSON.parse(contents); - } - response.result = obj; - } - response.headers = res.message.headers; - } - catch (err) { - // Invalid resource (contents not json); leaving result obj null - } - // note that 3xx redirects are handled by the http layer. - if (statusCode > 299) { - let msg; - // if exception/error in body, attempt to get better error - if (obj && obj.message) { - msg = obj.message; - } - else if (contents && contents.length > 0) { - // it may be the case that the exception is in the body message as string - msg = contents; - } - else { - msg = `Failed request: (${statusCode})`; - } - const err = new HttpClientError(msg, statusCode); - err.result = response.result; - reject(err); - } - else { - resolve(response); - } - })); - }); - } - } - lib$1.HttpClient = HttpClient; - const lowercaseKeys = (obj) => Object.keys(obj).reduce((c, k) => ((c[k.toLowerCase()] = obj[k]), c), {}); - - return lib$1; + * Adds an error issue + * @param message error issue message. Errors will be converted to string via toString() + * @param properties optional properties to add to the annotation. + */ + function error(message, properties = {}) { + (0, command_1.issueCommand)('error', (0, utils_1.toCommandProperties)(properties), message instanceof Error ? message.toString() : message); + } + /** + * Adds a warning issue + * @param message warning issue message. Errors will be converted to string via toString() + * @param properties optional properties to add to the annotation. + */ + function warning(message, properties = {}) { + (0, command_1.issueCommand)('warning', (0, utils_1.toCommandProperties)(properties), message instanceof Error ? message.toString() : message); + } + /** + * Adds a notice issue + * @param message notice issue message. Errors will be converted to string via toString() + * @param properties optional properties to add to the annotation. + */ + function notice(message, properties = {}) { + (0, command_1.issueCommand)('notice', (0, utils_1.toCommandProperties)(properties), message instanceof Error ? message.toString() : message); + } + /** + * Writes info to log with console.log. + * @param message info message + */ + function info(message) { + process.stdout.write(message + os.EOL); + } + /** + * Begin an output group. + * + * Output until the next `groupEnd` will be foldable in this group + * + * @param name The name of the output group + */ + function startGroup(name) { + (0, command_1.issue)('group', name); + } + /** + * End an output group. + */ + function endGroup() { + (0, command_1.issue)('endgroup'); + } + /** + * Wrap an asynchronous function call in a group. + * + * Returns the same type as the function itself. + * + * @param name The name of the group + * @param fn The function to wrap in the group + */ + function group(name, fn) { + return __awaiter(this, void 0, void 0, function* () { + startGroup(name); + let result; + try { + result = yield fn(); + } + finally { + endGroup(); + } + return result; + }); + } + //----------------------------------------------------------------------- + // Wrapper action state + //----------------------------------------------------------------------- + /** + * Saves state for current action, the state can only be retrieved by this action's post job execution. + * + * @param name name of the state to store + * @param value value to store. Non-string values will be converted to a string via JSON.stringify + */ + // eslint-disable-next-line @typescript-eslint/no-explicit-any + function saveState(name, value) { + const filePath = process.env['GITHUB_STATE'] || ''; + if (filePath) { + return (0, file_command_1.issueFileCommand)('STATE', (0, file_command_1.prepareKeyValueMessage)(name, value)); + } + (0, command_1.issueCommand)('save-state', { name }, (0, utils_1.toCommandValue)(value)); + } + /** + * Gets the value of an state set by this action's main execution. + * + * @param name name of the state to get + * @returns string + */ + function getState(name) { + return process.env[`STATE_${name}`] || ''; + } + function getIDToken(aud) { + return __awaiter(this, void 0, void 0, function* () { + return yield oidc_utils_1.OidcClient.getIDToken(aud); + }); + } + /** + * Summary exports + */ + var summary_1 = requireSummary(); + Object.defineProperty(exports$1, "summary", { enumerable: true, get: function () { return summary_1.summary; } }); + /** + * @deprecated use core.summary + */ + var summary_2 = requireSummary(); + Object.defineProperty(exports$1, "markdownSummary", { enumerable: true, get: function () { return summary_2.markdownSummary; } }); + /** + * Path exports + */ + var path_utils_1 = requirePathUtils(); + Object.defineProperty(exports$1, "toPosixPath", { enumerable: true, get: function () { return path_utils_1.toPosixPath; } }); + Object.defineProperty(exports$1, "toWin32Path", { enumerable: true, get: function () { return path_utils_1.toWin32Path; } }); + Object.defineProperty(exports$1, "toPlatformPath", { enumerable: true, get: function () { return path_utils_1.toPlatformPath; } }); + /** + * Platform utilities exports + */ + exports$1.platform = __importStar(requirePlatform()); + + } (core)); + return core; } -var hasRequiredUtils$2; - -function requireUtils$2 () { - if (hasRequiredUtils$2) return utils$1; - hasRequiredUtils$2 = 1; - var __createBinding = (utils$1 && utils$1.__createBinding) || (Object.create ? (function(o, m, k, k2) { - if (k2 === undefined) k2 = k; - var desc = Object.getOwnPropertyDescriptor(m, k); - if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { - desc = { enumerable: true, get: function() { return m[k]; } }; - } - Object.defineProperty(o, k2, desc); - }) : (function(o, m, k, k2) { - if (k2 === undefined) k2 = k; - o[k2] = m[k]; - })); - var __setModuleDefault = (utils$1 && utils$1.__setModuleDefault) || (Object.create ? (function(o, v) { - Object.defineProperty(o, "default", { enumerable: true, value: v }); - }) : function(o, v) { - o["default"] = v; - }); - var __importStar = (utils$1 && utils$1.__importStar) || function (mod) { - if (mod && mod.__esModule) return mod; - var result = {}; - if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); - __setModuleDefault(result, mod); - return result; - }; - var __awaiter = (utils$1 && utils$1.__awaiter) || function (thisArg, _arguments, P, generator) { - function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } - return new (P || (P = Promise))(function (resolve, reject) { - function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } - function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } - function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } - step((generator = generator.apply(thisArg, _arguments || [])).next()); - }); - }; - Object.defineProperty(utils$1, "__esModule", { value: true }); - utils$1.getApiBaseUrl = utils$1.getProxyFetch = utils$1.getProxyAgentDispatcher = utils$1.getProxyAgent = utils$1.getAuthString = void 0; - const httpClient = __importStar(requireLib$1()); - const undici_1 = requireUndici(); - function getAuthString(token, options) { - if (!token && !options.auth) { - throw new Error('Parameter token or opts.auth is required'); - } - else if (token && options.auth) { - throw new Error('Parameters token and opts.auth may not both be specified'); - } - return typeof options.auth === 'string' ? options.auth : `token ${token}`; - } - utils$1.getAuthString = getAuthString; - function getProxyAgent(destinationUrl) { - const hc = new httpClient.HttpClient(); - return hc.getAgent(destinationUrl); - } - utils$1.getProxyAgent = getProxyAgent; - function getProxyAgentDispatcher(destinationUrl) { - const hc = new httpClient.HttpClient(); - return hc.getAgentDispatcher(destinationUrl); - } - utils$1.getProxyAgentDispatcher = getProxyAgentDispatcher; - function getProxyFetch(destinationUrl) { - const httpDispatcher = getProxyAgentDispatcher(destinationUrl); - const proxyFetch = (url, opts) => __awaiter(this, void 0, void 0, function* () { - return (0, undici_1.fetch)(url, Object.assign(Object.assign({}, opts), { dispatcher: httpDispatcher })); - }); - return proxyFetch; - } - utils$1.getProxyFetch = getProxyFetch; - function getApiBaseUrl() { - return process.env['GITHUB_API_URL'] || 'https://api.github.com'; - } - utils$1.getApiBaseUrl = getApiBaseUrl; - - return utils$1; -} +var coreExports = requireCore(); function getUserAgent() { - if (typeof navigator === "object" && "userAgent" in navigator) { - return navigator.userAgent; - } - if (typeof process === "object" && process.version !== undefined) { - return `Node.js/${process.version.substr(1)} (${process.platform}; ${process.arch})`; - } - return ""; -} + if (typeof navigator === "object" && "userAgent" in navigator) { + return navigator.userAgent; + } -var beforeAfterHook = {exports: {}}; + if (typeof process === "object" && process.version !== undefined) { + return `Node.js/${process.version.substr(1)} (${process.platform}; ${ + process.arch + })`; + } -var register_1; -var hasRequiredRegister; + return ""; +} -function requireRegister () { - if (hasRequiredRegister) return register_1; - hasRequiredRegister = 1; - register_1 = register; +// @ts-check - function register(state, name, method, options) { - if (typeof method !== "function") { - throw new Error("method for before hook must be a function"); - } +function register(state, name, method, options) { + if (typeof method !== "function") { + throw new Error("method for before hook must be a function"); + } - if (!options) { - options = {}; - } + if (!options) { + options = {}; + } - if (Array.isArray(name)) { - return name.reverse().reduce(function (callback, name) { - return register.bind(null, state, name, callback, options); - }, method)(); - } + if (Array.isArray(name)) { + return name.reverse().reduce((callback, name) => { + return register.bind(null, state, name, callback, options); + }, method)(); + } - return Promise.resolve().then(function () { - if (!state.registry[name]) { - return method(options); - } + return Promise.resolve().then(() => { + if (!state.registry[name]) { + return method(options); + } - return state.registry[name].reduce(function (method, registered) { - return registered.hook.bind(null, method, options); - }, method)(); - }); - } - return register_1; + return state.registry[name].reduce((method, registered) => { + return registered.hook.bind(null, method, options); + }, method)(); + }); } -var add; -var hasRequiredAdd; - -function requireAdd () { - if (hasRequiredAdd) return add; - hasRequiredAdd = 1; - add = addHook; +// @ts-check - function addHook(state, kind, name, hook) { - var orig = hook; - if (!state.registry[name]) { - state.registry[name] = []; - } +function addHook(state, kind, name, hook) { + const orig = hook; + if (!state.registry[name]) { + state.registry[name] = []; + } - if (kind === "before") { - hook = function (method, options) { - return Promise.resolve() - .then(orig.bind(null, options)) - .then(method.bind(null, options)); - }; - } + if (kind === "before") { + hook = (method, options) => { + return Promise.resolve() + .then(orig.bind(null, options)) + .then(method.bind(null, options)); + }; + } - if (kind === "after") { - hook = function (method, options) { - var result; - return Promise.resolve() - .then(method.bind(null, options)) - .then(function (result_) { - result = result_; - return orig(result, options); - }) - .then(function () { - return result; - }); - }; - } + if (kind === "after") { + hook = (method, options) => { + let result; + return Promise.resolve() + .then(method.bind(null, options)) + .then((result_) => { + result = result_; + return orig(result, options); + }) + .then(() => { + return result; + }); + }; + } - if (kind === "error") { - hook = function (method, options) { - return Promise.resolve() - .then(method.bind(null, options)) - .catch(function (error) { - return orig(error, options); - }); - }; - } + if (kind === "error") { + hook = (method, options) => { + return Promise.resolve() + .then(method.bind(null, options)) + .catch((error) => { + return orig(error, options); + }); + }; + } - state.registry[name].push({ - hook: hook, - orig: orig, - }); - } - return add; + state.registry[name].push({ + hook: hook, + orig: orig, + }); } -var remove; -var hasRequiredRemove; - -function requireRemove () { - if (hasRequiredRemove) return remove; - hasRequiredRemove = 1; - remove = removeHook; +// @ts-check - function removeHook(state, name, method) { - if (!state.registry[name]) { - return; - } +function removeHook(state, name, method) { + if (!state.registry[name]) { + return; + } - var index = state.registry[name] - .map(function (registered) { - return registered.orig; - }) - .indexOf(method); + const index = state.registry[name] + .map((registered) => { + return registered.orig; + }) + .indexOf(method); - if (index === -1) { - return; - } + if (index === -1) { + return; + } - state.registry[name].splice(index, 1); - } - return remove; + state.registry[name].splice(index, 1); } -var hasRequiredBeforeAfterHook; - -function requireBeforeAfterHook () { - if (hasRequiredBeforeAfterHook) return beforeAfterHook.exports; - hasRequiredBeforeAfterHook = 1; - var register = requireRegister(); - var addHook = requireAdd(); - var removeHook = requireRemove(); - - // bind with array of arguments: https://stackoverflow.com/a/21792913 - var bind = Function.bind; - var bindable = bind.bind(bind); - - function bindApi(hook, state, name) { - var removeHookRef = bindable(removeHook, null).apply( - null, - name ? [state, name] : [state] - ); - hook.api = { remove: removeHookRef }; - hook.remove = removeHookRef; - ["before", "error", "after", "wrap"].forEach(function (kind) { - var args = name ? [state, kind, name] : [state, kind]; - hook[kind] = hook.api[kind] = bindable(addHook, null).apply(null, args); - }); - } - - function HookSingular() { - var singularHookName = "h"; - var singularHookState = { - registry: {}, - }; - var singularHook = register.bind(null, singularHookState, singularHookName); - bindApi(singularHook, singularHookState, singularHookName); - return singularHook; - } +// @ts-check - function HookCollection() { - var state = { - registry: {}, - }; - var hook = register.bind(null, state); - bindApi(hook, state); +// bind with array of arguments: https://stackoverflow.com/a/21792913 +const bind = Function.bind; +const bindable = bind.bind(bind); - return hook; - } +function bindApi(hook, state, name) { + const removeHookRef = bindable(removeHook, null).apply( + null, + [state] + ); + hook.api = { remove: removeHookRef }; + hook.remove = removeHookRef; + ["before", "error", "after", "wrap"].forEach((kind) => { + const args = [state, kind]; + hook[kind] = hook.api[kind] = bindable(addHook, null).apply(null, args); + }); +} - var collectionHookDeprecationMessageDisplayed = false; - function Hook() { - if (!collectionHookDeprecationMessageDisplayed) { - console.warn( - '[before-after-hook]: "Hook()" repurposing warning, use "Hook.Collection()". Read more: https://git.io/upgrade-before-after-hook-to-1.4' - ); - collectionHookDeprecationMessageDisplayed = true; - } - return HookCollection(); - } +function Collection$1() { + const state = { + registry: {}, + }; - Hook.Singular = HookSingular.bind(); - Hook.Collection = HookCollection.bind(); + const hook = register.bind(null, state); + bindApi(hook, state); - beforeAfterHook.exports = Hook; - // expose constructors as a named property for TypeScript - beforeAfterHook.exports.Hook = Hook; - beforeAfterHook.exports.Singular = Hook.Singular; - beforeAfterHook.exports.Collection = Hook.Collection; - return beforeAfterHook.exports; + return hook; } -var beforeAfterHookExports = requireBeforeAfterHook(); +var Hook = { Collection: Collection$1 }; + +// pkg/dist-src/defaults.js -const VERSION$5 = "9.0.6"; +// pkg/dist-src/version.js +var VERSION$7 = "0.0.0-development"; -const userAgent = `octokit-endpoint.js/${VERSION$5} ${getUserAgent()}`; -const DEFAULTS = { +// pkg/dist-src/defaults.js +var userAgent = `octokit-endpoint.js/${VERSION$7} ${getUserAgent()}`; +var DEFAULTS = { method: "GET", baseUrl: "https://api.github.com", headers: { @@ -32232,6 +31359,7 @@ const DEFAULTS = { } }; +// pkg/dist-src/util/lowercase-keys.js function lowercaseKeys(object) { if (!object) { return {}; @@ -32242,26 +31370,23 @@ function lowercaseKeys(object) { }, {}); } +// pkg/dist-src/util/is-plain-object.js function isPlainObject$1(value) { - if (typeof value !== "object" || value === null) - return false; - if (Object.prototype.toString.call(value) !== "[object Object]") - return false; + if (typeof value !== "object" || value === null) return false; + if (Object.prototype.toString.call(value) !== "[object Object]") return false; const proto = Object.getPrototypeOf(value); - if (proto === null) - return true; + if (proto === null) return true; const Ctor = Object.prototype.hasOwnProperty.call(proto, "constructor") && proto.constructor; return typeof Ctor === "function" && Ctor instanceof Ctor && Function.prototype.call(Ctor) === Function.prototype.call(value); } +// pkg/dist-src/util/merge-deep.js function mergeDeep(defaults, options) { const result = Object.assign({}, defaults); Object.keys(options).forEach((key) => { if (isPlainObject$1(options[key])) { - if (!(key in defaults)) - Object.assign(result, { [key]: options[key] }); - else - result[key] = mergeDeep(defaults[key], options[key]); + if (!(key in defaults)) Object.assign(result, { [key]: options[key] }); + else result[key] = mergeDeep(defaults[key], options[key]); } else { Object.assign(result, { [key]: options[key] }); } @@ -32269,6 +31394,7 @@ function mergeDeep(defaults, options) { return result; } +// pkg/dist-src/util/remove-undefined-properties.js function removeUndefinedProperties(obj) { for (const key in obj) { if (obj[key] === void 0) { @@ -32278,6 +31404,7 @@ function removeUndefinedProperties(obj) { return obj; } +// pkg/dist-src/merge.js function merge$1(defaults, route, options) { if (typeof route === "string") { let [method, url] = route.split(" "); @@ -32300,6 +31427,7 @@ function merge$1(defaults, route, options) { return mergedOptions; } +// pkg/dist-src/util/add-query-parameters.js function addQueryParameters(url, parameters) { const separator = /\?/.test(url) ? "&" : "?"; const names = Object.keys(parameters); @@ -32314,7 +31442,8 @@ function addQueryParameters(url, parameters) { }).join("&"); } -const urlVariableRegex = /\{[^{}}]+\}/g; +// pkg/dist-src/util/extract-url-variable-names.js +var urlVariableRegex = /\{[^{}}]+\}/g; function removeNonChars(variableName) { return variableName.replace(/(?:^\W+)|(?:(? a.concat(b), []); } +// pkg/dist-src/util/omit.js function omit(object, keysToOmit) { const result = { __proto__: null }; for (const key of Object.keys(object)) { @@ -32336,6 +31466,7 @@ function omit(object, keysToOmit) { return result; } +// pkg/dist-src/util/url-template.js function encodeReserved(str) { return str.split(/(%[0-9A-Fa-f]{2})/g).map(function(part) { if (!/%[0-9A-Fa-f]/.test(part)) { @@ -32366,7 +31497,7 @@ function isKeyOperator(operator) { function getValues(context, operator, key, modifier) { var value = context[key], result = []; if (isDefined(value) && value !== "") { - if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") { + if (typeof value === "string" || typeof value === "number" || typeof value === "bigint" || typeof value === "boolean") { value = value.toString(); if (modifier && modifier !== "*") { value = value.substring(0, parseInt(modifier, 10)); @@ -32467,6 +31598,7 @@ function expand(template, context) { } } +// pkg/dist-src/parse.js function parse$1(options) { let method = options.method.toUpperCase(); let url = (options.url || "/").replace(/:([a-z]\w+)/g, "{$1}"); @@ -32531,166 +31663,376 @@ function parse$1(options) { ); } +// pkg/dist-src/endpoint-with-defaults.js function endpointWithDefaults(defaults, route, options) { return parse$1(merge$1(defaults, route, options)); } -function withDefaults$2(oldDefaults, newDefaults) { - const DEFAULTS = merge$1(oldDefaults, newDefaults); - const endpoint = endpointWithDefaults.bind(null, DEFAULTS); - return Object.assign(endpoint, { - DEFAULTS, - defaults: withDefaults$2.bind(null, DEFAULTS), - merge: merge$1.bind(null, DEFAULTS), - parse: parse$1 - }); +// pkg/dist-src/with-defaults.js +function withDefaults$2(oldDefaults, newDefaults) { + const DEFAULTS2 = merge$1(oldDefaults, newDefaults); + const endpoint2 = endpointWithDefaults.bind(null, DEFAULTS2); + return Object.assign(endpoint2, { + DEFAULTS: DEFAULTS2, + defaults: withDefaults$2.bind(null, DEFAULTS2), + merge: merge$1.bind(null, DEFAULTS2), + parse: parse$1 + }); +} + +// pkg/dist-src/index.js +var endpoint = withDefaults$2(null, DEFAULTS); + +var fastContentTypeParse = {}; + +var hasRequiredFastContentTypeParse; + +function requireFastContentTypeParse () { + if (hasRequiredFastContentTypeParse) return fastContentTypeParse; + hasRequiredFastContentTypeParse = 1; + + const NullObject = function NullObject () { }; + NullObject.prototype = Object.create(null); + + /** + * RegExp to match *( ";" parameter ) in RFC 7231 sec 3.1.1.1 + * + * parameter = token "=" ( token / quoted-string ) + * token = 1*tchar + * tchar = "!" / "#" / "$" / "%" / "&" / "'" / "*" + * / "+" / "-" / "." / "^" / "_" / "`" / "|" / "~" + * / DIGIT / ALPHA + * ; any VCHAR, except delimiters + * quoted-string = DQUOTE *( qdtext / quoted-pair ) DQUOTE + * qdtext = HTAB / SP / %x21 / %x23-5B / %x5D-7E / obs-text + * obs-text = %x80-FF + * quoted-pair = "\" ( HTAB / SP / VCHAR / obs-text ) + */ + const paramRE = /; *([!#$%&'*+.^\w`|~-]+)=("(?:[\v\u0020\u0021\u0023-\u005b\u005d-\u007e\u0080-\u00ff]|\\[\v\u0020-\u00ff])*"|[!#$%&'*+.^\w`|~-]+) */gu; + + /** + * RegExp to match quoted-pair in RFC 7230 sec 3.2.6 + * + * quoted-pair = "\" ( HTAB / SP / VCHAR / obs-text ) + * obs-text = %x80-FF + */ + const quotedPairRE = /\\([\v\u0020-\u00ff])/gu; + + /** + * RegExp to match type in RFC 7231 sec 3.1.1.1 + * + * media-type = type "/" subtype + * type = token + * subtype = token + */ + const mediaTypeRE = /^[!#$%&'*+.^\w|~-]+\/[!#$%&'*+.^\w|~-]+$/u; + + // default ContentType to prevent repeated object creation + const defaultContentType = { type: '', parameters: new NullObject() }; + Object.freeze(defaultContentType.parameters); + Object.freeze(defaultContentType); + + /** + * Parse media type to object. + * + * @param {string|object} header + * @return {Object} + * @public + */ + + function parse (header) { + if (typeof header !== 'string') { + throw new TypeError('argument header is required and must be a string') + } + + let index = header.indexOf(';'); + const type = index !== -1 + ? header.slice(0, index).trim() + : header.trim(); + + if (mediaTypeRE.test(type) === false) { + throw new TypeError('invalid media type') + } + + const result = { + type: type.toLowerCase(), + parameters: new NullObject() + }; + + // parse parameters + if (index === -1) { + return result + } + + let key; + let match; + let value; + + paramRE.lastIndex = index; + + while ((match = paramRE.exec(header))) { + if (match.index !== index) { + throw new TypeError('invalid parameter format') + } + + index += match[0].length; + key = match[1].toLowerCase(); + value = match[2]; + + if (value[0] === '"') { + // remove quotes and escapes + value = value + .slice(1, value.length - 1); + + quotedPairRE.test(value) && (value = value.replace(quotedPairRE, '$1')); + } + + result.parameters[key] = value; + } + + if (index !== header.length) { + throw new TypeError('invalid parameter format') + } + + return result + } + + function safeParse (header) { + if (typeof header !== 'string') { + return defaultContentType + } + + let index = header.indexOf(';'); + const type = index !== -1 + ? header.slice(0, index).trim() + : header.trim(); + + if (mediaTypeRE.test(type) === false) { + return defaultContentType + } + + const result = { + type: type.toLowerCase(), + parameters: new NullObject() + }; + + // parse parameters + if (index === -1) { + return result + } + + let key; + let match; + let value; + + paramRE.lastIndex = index; + + while ((match = paramRE.exec(header))) { + if (match.index !== index) { + return defaultContentType + } + + index += match[0].length; + key = match[1].toLowerCase(); + value = match[2]; + + if (value[0] === '"') { + // remove quotes and escapes + value = value + .slice(1, value.length - 1); + + quotedPairRE.test(value) && (value = value.replace(quotedPairRE, '$1')); + } + + result.parameters[key] = value; + } + + if (index !== header.length) { + return defaultContentType + } + + return result + } + + fastContentTypeParse.default = { parse, safeParse }; + fastContentTypeParse.parse = parse; + fastContentTypeParse.safeParse = safeParse; + fastContentTypeParse.defaultContentType = defaultContentType; + return fastContentTypeParse; } -const endpoint = withDefaults$2(null, DEFAULTS); +var fastContentTypeParseExports = requireFastContentTypeParse(); -const VERSION$4 = "8.4.1"; +const intRegex = /^-?\d+$/; +const noiseValue = /^-?\d+n+$/; // Noise - strings that match the custom format before being converted to it +const originalStringify = JSON.stringify; +const originalParse = JSON.parse; +const customFormat = /^-?\d+n$/; -function isPlainObject(value) { - if (typeof value !== "object" || value === null) - return false; - if (Object.prototype.toString.call(value) !== "[object Object]") - return false; - const proto = Object.getPrototypeOf(value); - if (proto === null) - return true; - const Ctor = Object.prototype.hasOwnProperty.call(proto, "constructor") && proto.constructor; - return typeof Ctor === "function" && Ctor instanceof Ctor && Function.prototype.call(Ctor) === Function.prototype.call(value); -} +const bigIntsStringify = /([\[:])?"(-?\d+)n"($|([\\n]|\s)*(\s|[\\n])*[,\}\]])/g; +const noiseStringify = + /([\[:])?("-?\d+n+)n("$|"([\\n]|\s)*(\s|[\\n])*[,\}\]])/g; -class Deprecation extends Error { - constructor(message) { - super(message); // Maintains proper stack trace (only available on V8) +/** @typedef {(key: string, value: any, context?: { source: string }) => any} Reviver */ - /* istanbul ignore next */ +/** + * Function to serialize value to a JSON string. + * Converts BigInt values to a custom format (strings with digits and "n" at the end) and then converts them to proper big integers in a JSON string. + * @param {*} value - The value to convert to a JSON string. + * @param {(Function|Array|null)} [replacer] - A function that alters the behavior of the stringification process, or an array of strings to indicate properties to exclude. + * @param {(string|number)} [space] - A string or number to specify indentation or pretty-printing. + * @returns {string} The JSON string representation. + */ +const JSONStringify = (value, replacer, space) => { + if ("rawJSON" in JSON) { + return originalStringify( + value, + (key, value) => { + if (typeof value === "bigint") return JSON.rawJSON(value.toString()); - if (Error.captureStackTrace) { - Error.captureStackTrace(this, this.constructor); - } + if (Array.isArray(replacer) && replacer.includes(key)) return value; - this.name = 'Deprecation'; + return value; + }, + space, + ); } -} + if (!value) return originalStringify(value, replacer, space); -var once$1 = {exports: {}}; + const convertedToCustomJSON = originalStringify( + value, + (key, value) => { + const isNoise = + typeof value === "string" && Boolean(value.match(noiseValue)); -var wrappy_1; -var hasRequiredWrappy; + if (isNoise) return value.toString() + "n"; // Mark noise values with additional "n" to offset the deletion of one "n" during the processing -function requireWrappy () { - if (hasRequiredWrappy) return wrappy_1; - hasRequiredWrappy = 1; - // Returns a wrapper function that returns a wrapped callback - // The wrapper function should do some stuff, and return a - // presumably different callback function. - // This makes sure that own properties are retained, so that - // decorations and such are not lost along the way. - wrappy_1 = wrappy; - function wrappy (fn, cb) { - if (fn && cb) return wrappy(fn)(cb) + if (typeof value === "bigint") return value.toString() + "n"; - if (typeof fn !== 'function') - throw new TypeError('need wrapper function') + if (Array.isArray(replacer) && replacer.includes(key)) return value; - Object.keys(fn).forEach(function (k) { - wrapper[k] = fn[k]; - }); + return value; + }, + space, + ); + const processedJSON = convertedToCustomJSON.replace( + bigIntsStringify, + "$1$2$3", + ); // Delete one "n" off the end of every BigInt value + const denoisedJSON = processedJSON.replace(noiseStringify, "$1$2$3"); // Remove one "n" off the end of every noisy string - return wrapper + return denoisedJSON; +}; - function wrapper() { - var args = new Array(arguments.length); - for (var i = 0; i < args.length; i++) { - args[i] = arguments[i]; - } - var ret = fn.apply(this, args); - var cb = args[args.length-1]; - if (typeof ret === 'function' && ret !== cb) { - Object.keys(cb).forEach(function (k) { - ret[k] = cb[k]; - }); - } - return ret - } - } - return wrappy_1; -} +/** + * Support for JSON.parse's context.source feature detection. + * @type {boolean} + */ +const isContextSourceSupported = () => + JSON.parse("1", (_, __, context) => !!context && context.source === "1"); -var hasRequiredOnce; +/** + * Convert marked big numbers to BigInt + * @type {Reviver} + */ +const convertMarkedBigIntsReviver = (key, value, context, userReviver) => { + const isCustomFormatBigInt = + typeof value === "string" && value.match(customFormat); + if (isCustomFormatBigInt) return BigInt(value.slice(0, -1)); -function requireOnce () { - if (hasRequiredOnce) return once$1.exports; - hasRequiredOnce = 1; - var wrappy = requireWrappy(); - once$1.exports = wrappy(once); - once$1.exports.strict = wrappy(onceStrict); + const isNoiseValue = typeof value === "string" && value.match(noiseValue); + if (isNoiseValue) return value.slice(0, -1); - once.proto = once(function () { - Object.defineProperty(Function.prototype, 'once', { - value: function () { - return once(this) - }, - configurable: true - }); + return value; +}; - Object.defineProperty(Function.prototype, 'onceStrict', { - value: function () { - return onceStrict(this) - }, - configurable: true - }); - }); +/** + * Faster (2x) and simpler function to parse JSON. + * Based on JSON.parse's context.source feature, which is not universally available now. + * Does not support the legacy custom format, used in the first version of this library. + */ +const JSONParseV2 = (text, reviver) => { + return JSON.parse(text, (key, value, context) => { + const isBigNumber = + typeof value === "number" && + (value > Number.MAX_SAFE_INTEGER || value < Number.MIN_SAFE_INTEGER); + const isInt = context && intRegex.test(context.source); + const isBigInt = isBigNumber && isInt; - function once (fn) { - var f = function () { - if (f.called) return f.value - f.called = true; - return f.value = fn.apply(this, arguments) - }; - f.called = false; - return f - } + if (isBigInt) return BigInt(context.source); - function onceStrict (fn) { - var f = function () { - if (f.called) - throw new Error(f.onceError) - f.called = true; - return f.value = fn.apply(this, arguments) - }; - var name = fn.name || 'Function wrapped with `once`'; - f.onceError = name + " shouldn't be called more than once"; - f.called = false; - return f - } - return once$1.exports; -} + return value; + }); +}; + +const MAX_INT = Number.MAX_SAFE_INTEGER.toString(); +const MAX_DIGITS = MAX_INT.length; +const stringsOrLargeNumbers = + /"(?:\\.|[^"])*"|-?(0|[1-9][0-9]*)(\.[0-9]+)?([eE][+-]?[0-9]+)?/g; +const noiseValueWithQuotes = /^"-?\d+n+"$/; // Noise - strings that match the custom format before being converted to it + +/** + * Function to parse JSON. + * If JSON has number values greater than Number.MAX_SAFE_INTEGER, we convert those values to a custom format, then parse them to BigInt values. + * Other types of values are not affected and parsed as native JSON.parse() would parse them. + */ +const JSONParse = (text, reviver) => { + if (!text) return originalParse(text, reviver); + + if (isContextSourceSupported()) return JSONParseV2(text); // Shortcut to a faster (2x) and simpler version + + // Find and mark big numbers with "n" + const serializedData = text.replace( + stringsOrLargeNumbers, + (text, digits, fractional, exponential) => { + const isString = text[0] === '"'; + const isNoise = isString && Boolean(text.match(noiseValueWithQuotes)); + + if (isNoise) return text.substring(0, text.length - 1) + 'n"'; // Mark noise values with additional "n" to offset the deletion of one "n" during the processing + + const isFractionalOrExponential = fractional || exponential; + const isLessThanMaxSafeInt = + digits && + (digits.length < MAX_DIGITS || + (digits.length === MAX_DIGITS && digits <= MAX_INT)); // With a fixed number of digits, we can correctly use lexicographical comparison to do a numeric comparison + + if (isString || isFractionalOrExponential || isLessThanMaxSafeInt) + return text; -var onceExports = requireOnce(); -var once = /*@__PURE__*/getDefaultExportFromCjs(onceExports); + return '"' + text + 'n"'; + }, + ); + + return originalParse(serializedData, (key, value, context) => + convertMarkedBigIntsReviver(key, value), + ); +}; -const logOnceCode = once((deprecation) => console.warn(deprecation)); -const logOnceHeaders = once((deprecation) => console.warn(deprecation)); class RequestError extends Error { + name; + /** + * http status code + */ + status; + /** + * Request options that lead to the error. + */ + request; + /** + * Response object if a response was received + */ + response; constructor(message, statusCode, options) { - super(message); - if (Error.captureStackTrace) { - Error.captureStackTrace(this, this.constructor); - } + super(message, { cause: options.cause }); this.name = "HttpError"; - this.status = statusCode; - let headers; - if ("headers" in options && typeof options.headers !== "undefined") { - headers = options.headers; + this.status = Number.parseInt(statusCode); + if (Number.isNaN(this.status)) { + this.status = 0; } + /* v8 ignore else -- @preserve -- Bug with vitest coverage where it sees an else branch that doesn't exist */ if ("response" in options) { this.response = options.response; - headers = options.response.headers; } const requestCopy = Object.assign({}, options.request); if (options.request.headers.authorization) { @@ -32703,202 +32045,203 @@ class RequestError extends Error { } requestCopy.url = requestCopy.url.replace(/\bclient_secret=\w+/g, "client_secret=[REDACTED]").replace(/\baccess_token=\w+/g, "access_token=[REDACTED]"); this.request = requestCopy; - Object.defineProperty(this, "code", { - get() { - logOnceCode( - new Deprecation( - "[@octokit/request-error] `error.code` is deprecated, use `error.status`." - ) - ); - return statusCode; - } - }); - Object.defineProperty(this, "headers", { - get() { - logOnceHeaders( - new Deprecation( - "[@octokit/request-error] `error.headers` is deprecated, use `error.response.headers`." - ) - ); - return headers || {}; - } - }); } } -function getBufferResponse(response) { - return response.arrayBuffer(); -} +// pkg/dist-src/index.js -function fetchWrapper(requestOptions) { - const log = requestOptions.request && requestOptions.request.log ? requestOptions.request.log : console; - const parseSuccessResponseBody = requestOptions.request?.parseSuccessResponseBody !== false; - if (isPlainObject(requestOptions.body) || Array.isArray(requestOptions.body)) { - requestOptions.body = JSON.stringify(requestOptions.body); - } - let headers = {}; - let status; - let url; - let { fetch } = globalThis; - if (requestOptions.request?.fetch) { - fetch = requestOptions.request.fetch; +// pkg/dist-src/version.js +var VERSION$6 = "10.0.8"; + +// pkg/dist-src/defaults.js +var defaults_default = { + headers: { + "user-agent": `octokit-request.js/${VERSION$6} ${getUserAgent()}` } +}; + +// pkg/dist-src/is-plain-object.js +function isPlainObject(value) { + if (typeof value !== "object" || value === null) return false; + if (Object.prototype.toString.call(value) !== "[object Object]") return false; + const proto = Object.getPrototypeOf(value); + if (proto === null) return true; + const Ctor = Object.prototype.hasOwnProperty.call(proto, "constructor") && proto.constructor; + return typeof Ctor === "function" && Ctor instanceof Ctor && Function.prototype.call(Ctor) === Function.prototype.call(value); +} +var noop$1 = () => ""; +async function fetchWrapper(requestOptions) { + const fetch = requestOptions.request?.fetch || globalThis.fetch; if (!fetch) { throw new Error( "fetch is not set. Please pass a fetch implementation as new Octokit({ request: { fetch }}). Learn more at https://github.com/octokit/octokit.js/#fetch-missing" ); } - return fetch(requestOptions.url, { - method: requestOptions.method, - body: requestOptions.body, - redirect: requestOptions.request?.redirect, - headers: requestOptions.headers, - signal: requestOptions.request?.signal, - // duplex must be set if request.body is ReadableStream or Async Iterables. - // See https://fetch.spec.whatwg.org/#dom-requestinit-duplex. - ...requestOptions.body && { duplex: "half" } - }).then(async (response) => { - url = response.url; - status = response.status; - for (const keyAndValue of response.headers) { - headers[keyAndValue[0]] = keyAndValue[1]; - } - if ("deprecation" in headers) { - const matches = headers.link && headers.link.match(/<([^<>]+)>; rel="deprecation"/); - const deprecationLink = matches && matches.pop(); - log.warn( - `[@octokit/request] "${requestOptions.method} ${requestOptions.url}" is deprecated. It is scheduled to be removed on ${headers.sunset}${deprecationLink ? `. See ${deprecationLink}` : ""}` - ); - } - if (status === 204 || status === 205) { - return; - } - if (requestOptions.method === "HEAD") { - if (status < 400) { - return; + const log = requestOptions.request?.log || console; + const parseSuccessResponseBody = requestOptions.request?.parseSuccessResponseBody !== false; + const body = isPlainObject(requestOptions.body) || Array.isArray(requestOptions.body) ? JSONStringify(requestOptions.body) : requestOptions.body; + const requestHeaders = Object.fromEntries( + Object.entries(requestOptions.headers).map(([name, value]) => [ + name, + String(value) + ]) + ); + let fetchResponse; + try { + fetchResponse = await fetch(requestOptions.url, { + method: requestOptions.method, + body, + redirect: requestOptions.request?.redirect, + headers: requestHeaders, + signal: requestOptions.request?.signal, + // duplex must be set if request.body is ReadableStream or Async Iterables. + // See https://fetch.spec.whatwg.org/#dom-requestinit-duplex. + ...requestOptions.body && { duplex: "half" } + }); + } catch (error) { + let message = "Unknown Error"; + if (error instanceof Error) { + if (error.name === "AbortError") { + error.status = 500; + throw error; } - throw new RequestError(response.statusText, status, { - response: { - url, - status, - headers, - data: void 0 - }, - request: requestOptions - }); - } - if (status === 304) { - throw new RequestError("Not modified", status, { - response: { - url, - status, - headers, - data: await getResponseData(response) - }, - request: requestOptions - }); - } - if (status >= 400) { - const data = await getResponseData(response); - const error = new RequestError(toErrorMessage(data), status, { - response: { - url, - status, - headers, - data - }, - request: requestOptions - }); - throw error; - } - return parseSuccessResponseBody ? await getResponseData(response) : response.body; - }).then((data) => { - return { - status, - url, - headers, - data - }; - }).catch((error) => { - if (error instanceof RequestError) - throw error; - else if (error.name === "AbortError") - throw error; - let message = error.message; - if (error.name === "TypeError" && "cause" in error) { - if (error.cause instanceof Error) { - message = error.cause.message; - } else if (typeof error.cause === "string") { - message = error.cause; + message = error.message; + if (error.name === "TypeError" && "cause" in error) { + if (error.cause instanceof Error) { + message = error.cause.message; + } else if (typeof error.cause === "string") { + message = error.cause; + } } } - throw new RequestError(message, 500, { + const requestError = new RequestError(message, 500, { request: requestOptions }); - }); + requestError.cause = error; + throw requestError; + } + const status = fetchResponse.status; + const url = fetchResponse.url; + const responseHeaders = {}; + for (const [key, value] of fetchResponse.headers) { + responseHeaders[key] = value; + } + const octokitResponse = { + url, + status, + headers: responseHeaders, + data: "" + }; + if ("deprecation" in responseHeaders) { + const matches = responseHeaders.link && responseHeaders.link.match(/<([^<>]+)>; rel="deprecation"/); + const deprecationLink = matches && matches.pop(); + log.warn( + `[@octokit/request] "${requestOptions.method} ${requestOptions.url}" is deprecated. It is scheduled to be removed on ${responseHeaders.sunset}${deprecationLink ? `. See ${deprecationLink}` : ""}` + ); + } + if (status === 204 || status === 205) { + return octokitResponse; + } + if (requestOptions.method === "HEAD") { + if (status < 400) { + return octokitResponse; + } + throw new RequestError(fetchResponse.statusText, status, { + response: octokitResponse, + request: requestOptions + }); + } + if (status === 304) { + octokitResponse.data = await getResponseData(fetchResponse); + throw new RequestError("Not modified", status, { + response: octokitResponse, + request: requestOptions + }); + } + if (status >= 400) { + octokitResponse.data = await getResponseData(fetchResponse); + throw new RequestError(toErrorMessage(octokitResponse.data), status, { + response: octokitResponse, + request: requestOptions + }); + } + octokitResponse.data = parseSuccessResponseBody ? await getResponseData(fetchResponse) : fetchResponse.body; + return octokitResponse; } async function getResponseData(response) { const contentType = response.headers.get("content-type"); - if (/application\/json/.test(contentType)) { - return response.json().catch(() => response.text()).catch(() => ""); + if (!contentType) { + return response.text().catch(noop$1); } - if (!contentType || /^text\/|charset=utf-8$/.test(contentType)) { - return response.text(); + const mimetype = fastContentTypeParseExports.safeParse(contentType); + if (isJSONResponse(mimetype)) { + let text = ""; + try { + text = await response.text(); + return JSONParse(text); + } catch (err) { + return text; + } + } else if (mimetype.type.startsWith("text/") || mimetype.parameters.charset?.toLowerCase() === "utf-8") { + return response.text().catch(noop$1); + } else { + return response.arrayBuffer().catch( + /* v8 ignore next -- @preserve */ + () => new ArrayBuffer(0) + ); } - return getBufferResponse(response); +} +function isJSONResponse(mimetype) { + return mimetype.type === "application/json" || mimetype.type === "application/scim+json"; } function toErrorMessage(data) { - if (typeof data === "string") + if (typeof data === "string") { return data; - let suffix; - if ("documentation_url" in data) { - suffix = ` - ${data.documentation_url}`; - } else { - suffix = ""; + } + if (data instanceof ArrayBuffer) { + return "Unknown error"; } if ("message" in data) { - if (Array.isArray(data.errors)) { - return `${data.message}: ${data.errors.map(JSON.stringify).join(", ")}${suffix}`; - } - return `${data.message}${suffix}`; + const suffix = "documentation_url" in data ? ` - ${data.documentation_url}` : ""; + return Array.isArray(data.errors) ? `${data.message}: ${data.errors.map((v) => JSON.stringify(v)).join(", ")}${suffix}` : `${data.message}${suffix}`; } return `Unknown error: ${JSON.stringify(data)}`; } +// pkg/dist-src/with-defaults.js function withDefaults$1(oldEndpoint, newDefaults) { - const endpoint = oldEndpoint.defaults(newDefaults); + const endpoint2 = oldEndpoint.defaults(newDefaults); const newApi = function(route, parameters) { - const endpointOptions = endpoint.merge(route, parameters); + const endpointOptions = endpoint2.merge(route, parameters); if (!endpointOptions.request || !endpointOptions.request.hook) { - return fetchWrapper(endpoint.parse(endpointOptions)); + return fetchWrapper(endpoint2.parse(endpointOptions)); } - const request = (route2, parameters2) => { + const request2 = (route2, parameters2) => { return fetchWrapper( - endpoint.parse(endpoint.merge(route2, parameters2)) + endpoint2.parse(endpoint2.merge(route2, parameters2)) ); }; - Object.assign(request, { - endpoint, - defaults: withDefaults$1.bind(null, endpoint) + Object.assign(request2, { + endpoint: endpoint2, + defaults: withDefaults$1.bind(null, endpoint2) }); - return endpointOptions.request.hook(request, endpointOptions); + return endpointOptions.request.hook(request2, endpointOptions); }; return Object.assign(newApi, { - endpoint, - defaults: withDefaults$1.bind(null, endpoint) + endpoint: endpoint2, + defaults: withDefaults$1.bind(null, endpoint2) }); } -const request = withDefaults$1(endpoint, { - headers: { - "user-agent": `octokit-request.js/${VERSION$4} ${getUserAgent()}` - } -}); +// pkg/dist-src/index.js +var request = withDefaults$1(endpoint, defaults_default); +/* v8 ignore next -- @preserve */ +/* v8 ignore else -- @preserve */ // pkg/dist-src/index.js // pkg/dist-src/version.js -var VERSION$3 = "7.1.0"; +var VERSION$5 = "0.0.0-development"; // pkg/dist-src/error.js function _buildMessageForResponseErrors(data) { @@ -32911,13 +32254,15 @@ var GraphqlResponseError = class extends Error { this.request = request2; this.headers = headers; this.response = response; - this.name = "GraphqlResponseError"; this.errors = response.errors; this.data = response.data; if (Error.captureStackTrace) { Error.captureStackTrace(this, this.constructor); } } + name = "GraphqlResponseError"; + errors; + data; }; // pkg/dist-src/graphql.js @@ -32928,7 +32273,8 @@ var NON_VARIABLE_OPTIONS = [ "headers", "request", "query", - "mediaType" + "mediaType", + "operationName" ]; var FORBIDDEN_VARIABLE_OPTIONS = ["query", "method", "url"]; var GHES_V3_SUFFIX_REGEX = /\/api\/v3\/?$/; @@ -32940,8 +32286,7 @@ function graphql(request2, query, options) { ); } for (const key in options) { - if (!FORBIDDEN_VARIABLE_OPTIONS.includes(key)) - continue; + if (!FORBIDDEN_VARIABLE_OPTIONS.includes(key)) continue; return Promise.reject( new Error( `[@octokit/graphql] "${key}" cannot be used as variable name` @@ -32998,7 +32343,7 @@ function withDefaults(request2, newDefaults) { // pkg/dist-src/index.js withDefaults(request, { headers: { - "user-agent": `octokit-graphql.js/${VERSION$3} ${getUserAgent()}` + "user-agent": `octokit-graphql.js/${VERSION$5} ${getUserAgent()}` }, method: "POST", url: "/graphql" @@ -33010,13 +32355,17 @@ function withCustomRequest(customRequest) { }); } -const REGEX_IS_INSTALLATION_LEGACY = /^v1\./; -const REGEX_IS_INSTALLATION = /^ghs_/; -const REGEX_IS_USER_TO_SERVER = /^ghu_/; +// pkg/dist-src/is-jwt.js +var b64url = "(?:[a-zA-Z0-9_-]+)"; +var sep = "\\."; +var jwtRE = new RegExp(`^${b64url}${sep}${b64url}${sep}${b64url}$`); +var isJWT = jwtRE.test.bind(jwtRE); + +// pkg/dist-src/auth.js async function auth(token) { - const isApp = token.split(/\./).length === 3; - const isInstallation = REGEX_IS_INSTALLATION_LEGACY.test(token) || REGEX_IS_INSTALLATION.test(token); - const isUserToServer = REGEX_IS_USER_TO_SERVER.test(token); + const isApp = isJWT(token); + const isInstallation = token.startsWith("v1.") || token.startsWith("ghs_"); + const isUserToServer = token.startsWith("ghu_"); const tokenType = isApp ? "app" : isInstallation ? "installation" : isUserToServer ? "user-to-server" : "oauth"; return { type: "token", @@ -33025,6 +32374,7 @@ async function auth(token) { }; } +// pkg/dist-src/with-authorization-prefix.js function withAuthorizationPrefix(token) { if (token.split(/\./).length === 3) { return `bearer ${token}`; @@ -33032,6 +32382,7 @@ function withAuthorizationPrefix(token) { return `token ${token}`; } +// pkg/dist-src/hook.js async function hook(token, request, route, parameters) { const endpoint = request.endpoint.merge( route, @@ -33041,7 +32392,8 @@ async function hook(token, request, route, parameters) { return request(endpoint); } -const createTokenAuth = function createTokenAuth2(token) { +// pkg/dist-src/index.js +var createTokenAuth = function createTokenAuth2(token) { if (!token) { throw new Error("[@octokit/auth-token] No token passed to createTokenAuth"); } @@ -33056,21 +32408,30 @@ const createTokenAuth = function createTokenAuth2(token) { }); }; -// pkg/dist-src/index.js - -// pkg/dist-src/version.js -var VERSION$2 = "5.2.0"; +const VERSION$4 = "7.0.6"; -// pkg/dist-src/index.js -var noop = () => { +const noop = () => { }; -var consoleWarn = console.warn.bind(console); -var consoleError = console.error.bind(console); -var userAgentTrail = `octokit-core.js/${VERSION$2} ${getUserAgent()}`; -var Octokit = class { - static { - this.VERSION = VERSION$2; +const consoleWarn = console.warn.bind(console); +const consoleError = console.error.bind(console); +function createLogger(logger = {}) { + if (typeof logger.debug !== "function") { + logger.debug = noop; + } + if (typeof logger.info !== "function") { + logger.info = noop; + } + if (typeof logger.warn !== "function") { + logger.warn = consoleWarn; + } + if (typeof logger.error !== "function") { + logger.error = consoleError; } + return logger; +} +const userAgentTrail = `octokit-core.js/${VERSION$4} ${getUserAgent()}`; +let Octokit$1 = class Octokit { + static VERSION = VERSION$4; static defaults(defaults) { const OctokitWithDefaults = class extends this { constructor(...args) { @@ -33093,9 +32454,7 @@ var Octokit = class { }; return OctokitWithDefaults; } - static { - this.plugins = []; - } + static plugins = []; /** * Attach a plugin (or many) to your Octokit instance. * @@ -33105,16 +32464,14 @@ var Octokit = class { static plugin(...newPlugins) { const currentPlugins = this.plugins; const NewOctokit = class extends this { - static { - this.plugins = currentPlugins.concat( - newPlugins.filter((plugin) => !currentPlugins.includes(plugin)) - ); - } + static plugins = currentPlugins.concat( + newPlugins.filter((plugin) => !currentPlugins.includes(plugin)) + ); }; return NewOctokit; } constructor(options = {}) { - const hook = new beforeAfterHookExports.Collection(); + const hook = new Hook.Collection(); const requestDefaults = { baseUrl: request.endpoint.DEFAULTS.baseUrl, headers: {}, @@ -33139,15 +32496,7 @@ var Octokit = class { } this.request = request.defaults(requestDefaults); this.graphql = withCustomRequest(this.request).defaults(requestDefaults); - this.log = Object.assign( - { - debug: noop, - info: noop, - warn: consoleWarn, - error: consoleError - }, - options.log - ); + this.log = createLogger(options.log); this.hook = hook; if (!options.authStrategy) { if (!options.auth) { @@ -33185,16 +32534,167 @@ var Octokit = class { Object.assign(this, classConstructor.plugins[i](this, options)); } } + // assigned during constructor + request; + graphql; + log; + hook; + // TODO: type `octokit.auth` based on passed options.authStrategy + auth; }; -var distWeb$1 = /*#__PURE__*/Object.freeze({ - __proto__: null, - Octokit: Octokit +const VERSION$3 = "6.0.0"; + +function requestLog(octokit) { + octokit.hook.wrap("request", (request, options) => { + octokit.log.debug("request", options); + const start = Date.now(); + const requestOptions = octokit.request.endpoint.parse(options); + const path = requestOptions.url.replace(options.baseUrl, ""); + return request(options).then((response) => { + const requestId = response.headers["x-github-request-id"]; + octokit.log.info( + `${requestOptions.method} ${path} - ${response.status} with id ${requestId} in ${Date.now() - start}ms` + ); + return response; + }).catch((error) => { + const requestId = error.response?.headers["x-github-request-id"] || "UNKNOWN"; + octokit.log.error( + `${requestOptions.method} ${path} - ${error.status} with id ${requestId} in ${Date.now() - start}ms` + ); + throw error; + }); + }); +} +requestLog.VERSION = VERSION$3; + +// pkg/dist-src/version.js +var VERSION$2 = "0.0.0-development"; + +// pkg/dist-src/normalize-paginated-list-response.js +function normalizePaginatedListResponse(response) { + if (!response.data) { + return { + ...response, + data: [] + }; + } + const responseNeedsNormalization = ("total_count" in response.data || "total_commits" in response.data) && !("url" in response.data); + if (!responseNeedsNormalization) return response; + const incompleteResults = response.data.incomplete_results; + const repositorySelection = response.data.repository_selection; + const totalCount = response.data.total_count; + const totalCommits = response.data.total_commits; + delete response.data.incomplete_results; + delete response.data.repository_selection; + delete response.data.total_count; + delete response.data.total_commits; + const namespaceKey = Object.keys(response.data)[0]; + const data = response.data[namespaceKey]; + response.data = data; + if (typeof incompleteResults !== "undefined") { + response.data.incomplete_results = incompleteResults; + } + if (typeof repositorySelection !== "undefined") { + response.data.repository_selection = repositorySelection; + } + response.data.total_count = totalCount; + response.data.total_commits = totalCommits; + return response; +} + +// pkg/dist-src/iterator.js +function iterator(octokit, route, parameters) { + const options = typeof route === "function" ? route.endpoint(parameters) : octokit.request.endpoint(route, parameters); + const requestMethod = typeof route === "function" ? route : octokit.request; + const method = options.method; + const headers = options.headers; + let url = options.url; + return { + [Symbol.asyncIterator]: () => ({ + async next() { + if (!url) return { done: true }; + try { + const response = await requestMethod({ method, url, headers }); + const normalizedResponse = normalizePaginatedListResponse(response); + url = ((normalizedResponse.headers.link || "").match( + /<([^<>]+)>;\s*rel="next"/ + ) || [])[1]; + if (!url && "total_commits" in normalizedResponse.data) { + const parsedUrl = new URL(normalizedResponse.url); + const params = parsedUrl.searchParams; + const page = parseInt(params.get("page") || "1", 10); + const per_page = parseInt(params.get("per_page") || "250", 10); + if (page * per_page < normalizedResponse.data.total_commits) { + params.set("page", String(page + 1)); + url = parsedUrl.toString(); + } + } + return { value: normalizedResponse }; + } catch (error) { + if (error.status !== 409) throw error; + url = ""; + return { + value: { + status: 200, + headers: {}, + data: [] + } + }; + } + } + }) + }; +} + +// pkg/dist-src/paginate.js +function paginate(octokit, route, parameters, mapFn) { + if (typeof parameters === "function") { + mapFn = parameters; + parameters = void 0; + } + return gather( + octokit, + [], + iterator(octokit, route, parameters)[Symbol.asyncIterator](), + mapFn + ); +} +function gather(octokit, results, iterator2, mapFn) { + return iterator2.next().then((result) => { + if (result.done) { + return results; + } + let earlyExit = false; + function done() { + earlyExit = true; + } + results = results.concat( + mapFn ? mapFn(result.value, done) : result.value.data + ); + if (earlyExit) { + return results; + } + return gather(octokit, results, iterator2, mapFn); + }); +} + +// pkg/dist-src/compose-paginate.js +Object.assign(paginate, { + iterator }); -var require$$2 = /*@__PURE__*/getAugmentedNamespace(distWeb$1); +// pkg/dist-src/index.js +function paginateRest(octokit) { + return { + paginate: Object.assign(paginate.bind(null, octokit), { + iterator: iterator.bind(null, octokit) + }) + }; +} +paginateRest.VERSION = VERSION$2; -const VERSION$1 = "10.4.1"; +const VERSION$1 = "17.0.0"; const Endpoints = { actions: { @@ -33204,6 +32704,9 @@ const Endpoints = { addCustomLabelsToSelfHostedRunnerForRepo: [ "POST /repos/{owner}/{repo}/actions/runners/{runner_id}/labels" ], + addRepoAccessToSelfHostedRunnerGroupInOrg: [ + "PUT /orgs/{org}/actions/runner-groups/{runner_group_id}/repositories/{repository_id}" + ], addSelectedRepoToOrgSecret: [ "PUT /orgs/{org}/actions/secrets/{secret_name}/repositories/{repository_id}" ], @@ -33217,10 +32720,11 @@ const Endpoints = { "POST /repos/{owner}/{repo}/actions/runs/{run_id}/cancel" ], createEnvironmentVariable: [ - "POST /repositories/{repository_id}/environments/{environment_name}/variables" + "POST /repos/{owner}/{repo}/environments/{environment_name}/variables" ], + createHostedRunnerForOrg: ["POST /orgs/{org}/actions/hosted-runners"], createOrUpdateEnvironmentSecret: [ - "PUT /repositories/{repository_id}/environments/{environment_name}/secrets/{secret_name}" + "PUT /repos/{owner}/{repo}/environments/{environment_name}/secrets/{secret_name}" ], createOrUpdateOrgSecret: ["PUT /orgs/{org}/actions/secrets/{secret_name}"], createOrUpdateRepoSecret: [ @@ -33250,11 +32754,20 @@ const Endpoints = { deleteArtifact: [ "DELETE /repos/{owner}/{repo}/actions/artifacts/{artifact_id}" ], + deleteCustomImageFromOrg: [ + "DELETE /orgs/{org}/actions/hosted-runners/images/custom/{image_definition_id}" + ], + deleteCustomImageVersionFromOrg: [ + "DELETE /orgs/{org}/actions/hosted-runners/images/custom/{image_definition_id}/versions/{version}" + ], deleteEnvironmentSecret: [ - "DELETE /repositories/{repository_id}/environments/{environment_name}/secrets/{secret_name}" + "DELETE /repos/{owner}/{repo}/environments/{environment_name}/secrets/{secret_name}" ], deleteEnvironmentVariable: [ - "DELETE /repositories/{repository_id}/environments/{environment_name}/variables/{name}" + "DELETE /repos/{owner}/{repo}/environments/{environment_name}/variables/{name}" + ], + deleteHostedRunnerForOrg: [ + "DELETE /orgs/{org}/actions/hosted-runners/{hosted_runner_id}" ], deleteOrgSecret: ["DELETE /orgs/{org}/actions/secrets/{secret_name}"], deleteOrgVariable: ["DELETE /orgs/{org}/actions/variables/{name}"], @@ -33320,17 +32833,23 @@ const Endpoints = { "GET /repos/{owner}/{repo}/actions/permissions/selected-actions" ], getArtifact: ["GET /repos/{owner}/{repo}/actions/artifacts/{artifact_id}"], + getCustomImageForOrg: [ + "GET /orgs/{org}/actions/hosted-runners/images/custom/{image_definition_id}" + ], + getCustomImageVersionForOrg: [ + "GET /orgs/{org}/actions/hosted-runners/images/custom/{image_definition_id}/versions/{version}" + ], getCustomOidcSubClaimForRepo: [ "GET /repos/{owner}/{repo}/actions/oidc/customization/sub" ], getEnvironmentPublicKey: [ - "GET /repositories/{repository_id}/environments/{environment_name}/secrets/public-key" + "GET /repos/{owner}/{repo}/environments/{environment_name}/secrets/public-key" ], getEnvironmentSecret: [ - "GET /repositories/{repository_id}/environments/{environment_name}/secrets/{secret_name}" + "GET /repos/{owner}/{repo}/environments/{environment_name}/secrets/{secret_name}" ], getEnvironmentVariable: [ - "GET /repositories/{repository_id}/environments/{environment_name}/variables/{name}" + "GET /repos/{owner}/{repo}/environments/{environment_name}/variables/{name}" ], getGithubActionsDefaultWorkflowPermissionsOrganization: [ "GET /orgs/{org}/actions/permissions/workflow" @@ -33344,6 +32863,24 @@ const Endpoints = { getGithubActionsPermissionsRepository: [ "GET /repos/{owner}/{repo}/actions/permissions" ], + getHostedRunnerForOrg: [ + "GET /orgs/{org}/actions/hosted-runners/{hosted_runner_id}" + ], + getHostedRunnersGithubOwnedImagesForOrg: [ + "GET /orgs/{org}/actions/hosted-runners/images/github-owned" + ], + getHostedRunnersLimitsForOrg: [ + "GET /orgs/{org}/actions/hosted-runners/limits" + ], + getHostedRunnersMachineSpecsForOrg: [ + "GET /orgs/{org}/actions/hosted-runners/machine-sizes" + ], + getHostedRunnersPartnerImagesForOrg: [ + "GET /orgs/{org}/actions/hosted-runners/images/partner" + ], + getHostedRunnersPlatformsForOrg: [ + "GET /orgs/{org}/actions/hosted-runners/platforms" + ], getJobForWorkflowRun: ["GET /repos/{owner}/{repo}/actions/jobs/{job_id}"], getOrgPublicKey: ["GET /orgs/{org}/actions/secrets/public-key"], getOrgSecret: ["GET /orgs/{org}/actions/secrets/{secret_name}"], @@ -33381,12 +32918,22 @@ const Endpoints = { "GET /repos/{owner}/{repo}/actions/workflows/{workflow_id}/timing" ], listArtifactsForRepo: ["GET /repos/{owner}/{repo}/actions/artifacts"], + listCustomImageVersionsForOrg: [ + "GET /orgs/{org}/actions/hosted-runners/images/custom/{image_definition_id}/versions" + ], + listCustomImagesForOrg: [ + "GET /orgs/{org}/actions/hosted-runners/images/custom" + ], listEnvironmentSecrets: [ - "GET /repositories/{repository_id}/environments/{environment_name}/secrets" + "GET /repos/{owner}/{repo}/environments/{environment_name}/secrets" ], listEnvironmentVariables: [ - "GET /repositories/{repository_id}/environments/{environment_name}/variables" + "GET /repos/{owner}/{repo}/environments/{environment_name}/variables" ], + listGithubHostedRunnersInGroupForOrg: [ + "GET /orgs/{org}/actions/runner-groups/{runner_group_id}/hosted-runners" + ], + listHostedRunnersForOrg: ["GET /orgs/{org}/actions/hosted-runners"], listJobsForWorkflowRun: [ "GET /repos/{owner}/{repo}/actions/runs/{run_id}/jobs" ], @@ -33503,7 +33050,10 @@ const Endpoints = { "PUT /repos/{owner}/{repo}/actions/permissions/access" ], updateEnvironmentVariable: [ - "PATCH /repositories/{repository_id}/environments/{environment_name}/variables/{name}" + "PATCH /repos/{owner}/{repo}/environments/{environment_name}/variables/{name}" + ], + updateHostedRunnerForOrg: [ + "PATCH /orgs/{org}/actions/hosted-runners/{hosted_runner_id}" ], updateOrgVariable: ["PATCH /orgs/{org}/actions/variables/{name}"], updateRepoVariable: [ @@ -33632,6 +33182,18 @@ const Endpoints = { getGithubActionsBillingUser: [ "GET /users/{username}/settings/billing/actions" ], + getGithubBillingPremiumRequestUsageReportOrg: [ + "GET /organizations/{org}/settings/billing/premium_request/usage" + ], + getGithubBillingPremiumRequestUsageReportUser: [ + "GET /users/{username}/settings/billing/premium_request/usage" + ], + getGithubBillingUsageReportOrg: [ + "GET /organizations/{org}/settings/billing/usage" + ], + getGithubBillingUsageReportUser: [ + "GET /users/{username}/settings/billing/usage" + ], getGithubPackagesBillingOrg: ["GET /orgs/{org}/settings/billing/packages"], getGithubPackagesBillingUser: [ "GET /users/{username}/settings/billing/packages" @@ -33643,6 +33205,13 @@ const Endpoints = { "GET /users/{username}/settings/billing/shared-storage" ] }, + campaigns: { + createCampaign: ["POST /orgs/{org}/campaigns"], + deleteCampaign: ["DELETE /orgs/{org}/campaigns/{campaign_number}"], + getCampaignSummary: ["GET /orgs/{org}/campaigns/{campaign_number}"], + listOrgCampaigns: ["GET /orgs/{org}/campaigns"], + updateCampaign: ["PATCH /orgs/{org}/campaigns/{campaign_number}"] + }, checks: { create: ["POST /repos/{owner}/{repo}/check-runs"], createSuite: ["POST /repos/{owner}/{repo}/check-suites"], @@ -33668,9 +33237,21 @@ const Endpoints = { update: ["PATCH /repos/{owner}/{repo}/check-runs/{check_run_id}"] }, codeScanning: { + commitAutofix: [ + "POST /repos/{owner}/{repo}/code-scanning/alerts/{alert_number}/autofix/commits" + ], + createAutofix: [ + "POST /repos/{owner}/{repo}/code-scanning/alerts/{alert_number}/autofix" + ], + createVariantAnalysis: [ + "POST /repos/{owner}/{repo}/code-scanning/codeql/variant-analyses" + ], deleteAnalysis: [ "DELETE /repos/{owner}/{repo}/code-scanning/analyses/{analysis_id}{?confirm_delete}" ], + deleteCodeqlDatabase: [ + "DELETE /repos/{owner}/{repo}/code-scanning/codeql/databases/{language}" + ], getAlert: [ "GET /repos/{owner}/{repo}/code-scanning/alerts/{alert_number}", {}, @@ -33679,11 +33260,20 @@ const Endpoints = { getAnalysis: [ "GET /repos/{owner}/{repo}/code-scanning/analyses/{analysis_id}" ], + getAutofix: [ + "GET /repos/{owner}/{repo}/code-scanning/alerts/{alert_number}/autofix" + ], getCodeqlDatabase: [ "GET /repos/{owner}/{repo}/code-scanning/codeql/databases/{language}" ], getDefaultSetup: ["GET /repos/{owner}/{repo}/code-scanning/default-setup"], getSarif: ["GET /repos/{owner}/{repo}/code-scanning/sarifs/{sarif_id}"], + getVariantAnalysis: [ + "GET /repos/{owner}/{repo}/code-scanning/codeql/variant-analyses/{codeql_variant_analysis_id}" + ], + getVariantAnalysisRepoTask: [ + "GET /repos/{owner}/{repo}/code-scanning/codeql/variant-analyses/{codeql_variant_analysis_id}/repos/{repo_owner}/{repo_name}" + ], listAlertInstances: [ "GET /repos/{owner}/{repo}/code-scanning/alerts/{alert_number}/instances" ], @@ -33706,6 +33296,64 @@ const Endpoints = { ], uploadSarif: ["POST /repos/{owner}/{repo}/code-scanning/sarifs"] }, + codeSecurity: { + attachConfiguration: [ + "POST /orgs/{org}/code-security/configurations/{configuration_id}/attach" + ], + attachEnterpriseConfiguration: [ + "POST /enterprises/{enterprise}/code-security/configurations/{configuration_id}/attach" + ], + createConfiguration: ["POST /orgs/{org}/code-security/configurations"], + createConfigurationForEnterprise: [ + "POST /enterprises/{enterprise}/code-security/configurations" + ], + deleteConfiguration: [ + "DELETE /orgs/{org}/code-security/configurations/{configuration_id}" + ], + deleteConfigurationForEnterprise: [ + "DELETE /enterprises/{enterprise}/code-security/configurations/{configuration_id}" + ], + detachConfiguration: [ + "DELETE /orgs/{org}/code-security/configurations/detach" + ], + getConfiguration: [ + "GET /orgs/{org}/code-security/configurations/{configuration_id}" + ], + getConfigurationForRepository: [ + "GET /repos/{owner}/{repo}/code-security-configuration" + ], + getConfigurationsForEnterprise: [ + "GET /enterprises/{enterprise}/code-security/configurations" + ], + getConfigurationsForOrg: ["GET /orgs/{org}/code-security/configurations"], + getDefaultConfigurations: [ + "GET /orgs/{org}/code-security/configurations/defaults" + ], + getDefaultConfigurationsForEnterprise: [ + "GET /enterprises/{enterprise}/code-security/configurations/defaults" + ], + getRepositoriesForConfiguration: [ + "GET /orgs/{org}/code-security/configurations/{configuration_id}/repositories" + ], + getRepositoriesForEnterpriseConfiguration: [ + "GET /enterprises/{enterprise}/code-security/configurations/{configuration_id}/repositories" + ], + getSingleConfigurationForEnterprise: [ + "GET /enterprises/{enterprise}/code-security/configurations/{configuration_id}" + ], + setConfigurationAsDefault: [ + "PUT /orgs/{org}/code-security/configurations/{configuration_id}/defaults" + ], + setConfigurationAsDefaultForEnterprise: [ + "PUT /enterprises/{enterprise}/code-security/configurations/{configuration_id}/defaults" + ], + updateConfiguration: [ + "PATCH /orgs/{org}/code-security/configurations/{configuration_id}" + ], + updateEnterpriseConfiguration: [ + "PATCH /enterprises/{enterprise}/code-security/configurations/{configuration_id}" + ] + }, codesOfConduct: { getAllCodesOfConduct: ["GET /codes_of_conduct"], getConductCode: ["GET /codes_of_conduct/{key}"] @@ -33836,12 +33484,15 @@ const Endpoints = { cancelCopilotSeatAssignmentForUsers: [ "DELETE /orgs/{org}/copilot/billing/selected_users" ], + copilotMetricsForOrganization: ["GET /orgs/{org}/copilot/metrics"], + copilotMetricsForTeam: ["GET /orgs/{org}/team/{team_slug}/copilot/metrics"], getCopilotOrganizationDetails: ["GET /orgs/{org}/copilot/billing"], getCopilotSeatDetailsForUser: [ "GET /orgs/{org}/members/{username}/copilot" ], listCopilotSeats: ["GET /orgs/{org}/copilot/billing/seats"] }, + credentials: { revoke: ["POST /credentials/revoke"] }, dependabot: { addSelectedRepoToOrgSecret: [ "PUT /orgs/{org}/dependabot/secrets/{secret_name}/repositories/{repository_id}" @@ -33878,11 +33529,20 @@ const Endpoints = { removeSelectedRepoFromOrgSecret: [ "DELETE /orgs/{org}/dependabot/secrets/{secret_name}/repositories/{repository_id}" ], + repositoryAccessForOrg: [ + "GET /organizations/{org}/dependabot/repository-access" + ], + setRepositoryAccessDefaultLevel: [ + "PUT /organizations/{org}/dependabot/repository-access/default-level" + ], setSelectedReposForOrgSecret: [ "PUT /orgs/{org}/dependabot/secrets/{secret_name}/repositories" ], updateAlert: [ "PATCH /repos/{owner}/{repo}/dependabot/alerts/{alert_number}" + ], + updateRepositoryAccessForOrg: [ + "PATCH /organizations/{org}/dependabot/repository-access" ] }, dependencyGraph: { @@ -33895,6 +33555,51 @@ const Endpoints = { exportSbom: ["GET /repos/{owner}/{repo}/dependency-graph/sbom"] }, emojis: { get: ["GET /emojis"] }, + enterpriseTeamMemberships: { + add: [ + "PUT /enterprises/{enterprise}/teams/{enterprise-team}/memberships/{username}" + ], + bulkAdd: [ + "POST /enterprises/{enterprise}/teams/{enterprise-team}/memberships/add" + ], + bulkRemove: [ + "POST /enterprises/{enterprise}/teams/{enterprise-team}/memberships/remove" + ], + get: [ + "GET /enterprises/{enterprise}/teams/{enterprise-team}/memberships/{username}" + ], + list: ["GET /enterprises/{enterprise}/teams/{enterprise-team}/memberships"], + remove: [ + "DELETE /enterprises/{enterprise}/teams/{enterprise-team}/memberships/{username}" + ] + }, + enterpriseTeamOrganizations: { + add: [ + "PUT /enterprises/{enterprise}/teams/{enterprise-team}/organizations/{org}" + ], + bulkAdd: [ + "POST /enterprises/{enterprise}/teams/{enterprise-team}/organizations/add" + ], + bulkRemove: [ + "POST /enterprises/{enterprise}/teams/{enterprise-team}/organizations/remove" + ], + delete: [ + "DELETE /enterprises/{enterprise}/teams/{enterprise-team}/organizations/{org}" + ], + getAssignment: [ + "GET /enterprises/{enterprise}/teams/{enterprise-team}/organizations/{org}" + ], + getAssignments: [ + "GET /enterprises/{enterprise}/teams/{enterprise-team}/organizations" + ] + }, + enterpriseTeams: { + create: ["POST /enterprises/{enterprise}/teams"], + delete: ["DELETE /enterprises/{enterprise}/teams/{team_slug}"], + get: ["GET /enterprises/{enterprise}/teams/{team_slug}"], + list: ["GET /enterprises/{enterprise}/teams"], + update: ["PATCH /enterprises/{enterprise}/teams/{team_slug}"] + }, gists: { checkIsStarred: ["GET /gists/{gist_id}/star"], create: ["POST /gists"], @@ -33936,6 +33641,26 @@ const Endpoints = { getAllTemplates: ["GET /gitignore/templates"], getTemplate: ["GET /gitignore/templates/{name}"] }, + hostedCompute: { + createNetworkConfigurationForOrg: [ + "POST /orgs/{org}/settings/network-configurations" + ], + deleteNetworkConfigurationFromOrg: [ + "DELETE /orgs/{org}/settings/network-configurations/{network_configuration_id}" + ], + getNetworkConfigurationForOrg: [ + "GET /orgs/{org}/settings/network-configurations/{network_configuration_id}" + ], + getNetworkSettingsForOrg: [ + "GET /orgs/{org}/settings/network-settings/{network_settings_id}" + ], + listNetworkConfigurationsForOrg: [ + "GET /orgs/{org}/settings/network-configurations" + ], + updateNetworkConfigurationForOrg: [ + "PATCH /orgs/{org}/settings/network-configurations/{network_configuration_id}" + ] + }, interactions: { getRestrictionsForAuthenticatedUser: ["GET /user/interaction-limits"], getRestrictionsForOrg: ["GET /orgs/{org}/interaction-limits"], @@ -33968,7 +33693,13 @@ const Endpoints = { addAssignees: [ "POST /repos/{owner}/{repo}/issues/{issue_number}/assignees" ], + addBlockedByDependency: [ + "POST /repos/{owner}/{repo}/issues/{issue_number}/dependencies/blocked_by" + ], addLabels: ["POST /repos/{owner}/{repo}/issues/{issue_number}/labels"], + addSubIssue: [ + "POST /repos/{owner}/{repo}/issues/{issue_number}/sub_issues" + ], checkUserCanBeAssigned: ["GET /repos/{owner}/{repo}/assignees/{assignee}"], checkUserCanBeAssignedToIssue: [ "GET /repos/{owner}/{repo}/issues/{issue_number}/assignees/{assignee}" @@ -33991,10 +33722,17 @@ const Endpoints = { getEvent: ["GET /repos/{owner}/{repo}/issues/events/{event_id}"], getLabel: ["GET /repos/{owner}/{repo}/labels/{name}"], getMilestone: ["GET /repos/{owner}/{repo}/milestones/{milestone_number}"], + getParent: ["GET /repos/{owner}/{repo}/issues/{issue_number}/parent"], list: ["GET /issues"], listAssignees: ["GET /repos/{owner}/{repo}/assignees"], listComments: ["GET /repos/{owner}/{repo}/issues/{issue_number}/comments"], listCommentsForRepo: ["GET /repos/{owner}/{repo}/issues/comments"], + listDependenciesBlockedBy: [ + "GET /repos/{owner}/{repo}/issues/{issue_number}/dependencies/blocked_by" + ], + listDependenciesBlocking: [ + "GET /repos/{owner}/{repo}/issues/{issue_number}/dependencies/blocking" + ], listEvents: ["GET /repos/{owner}/{repo}/issues/{issue_number}/events"], listEventsForRepo: ["GET /repos/{owner}/{repo}/issues/events"], listEventsForTimeline: [ @@ -34011,6 +33749,9 @@ const Endpoints = { "GET /repos/{owner}/{repo}/issues/{issue_number}/labels" ], listMilestones: ["GET /repos/{owner}/{repo}/milestones"], + listSubIssues: [ + "GET /repos/{owner}/{repo}/issues/{issue_number}/sub_issues" + ], lock: ["PUT /repos/{owner}/{repo}/issues/{issue_number}/lock"], removeAllLabels: [ "DELETE /repos/{owner}/{repo}/issues/{issue_number}/labels" @@ -34018,9 +33759,18 @@ const Endpoints = { removeAssignees: [ "DELETE /repos/{owner}/{repo}/issues/{issue_number}/assignees" ], + removeDependencyBlockedBy: [ + "DELETE /repos/{owner}/{repo}/issues/{issue_number}/dependencies/blocked_by/{issue_id}" + ], removeLabel: [ "DELETE /repos/{owner}/{repo}/issues/{issue_number}/labels/{name}" ], + removeSubIssue: [ + "DELETE /repos/{owner}/{repo}/issues/{issue_number}/sub_issue" + ], + reprioritizeSubIssue: [ + "PATCH /repos/{owner}/{repo}/issues/{issue_number}/sub_issues/priority" + ], setLabels: ["PUT /repos/{owner}/{repo}/issues/{issue_number}/labels"], unlock: ["DELETE /repos/{owner}/{repo}/issues/{issue_number}/lock"], update: ["PATCH /repos/{owner}/{repo}/issues/{issue_number}"], @@ -34050,13 +33800,6 @@ const Endpoints = { root: ["GET /"] }, migrations: { - cancelImport: [ - "DELETE /repos/{owner}/{repo}/import", - {}, - { - deprecated: "octokit.rest.migrations.cancelImport() is deprecated, see https://docs.github.com/rest/migrations/source-imports#cancel-an-import" - } - ], deleteArchiveForAuthenticatedUser: [ "DELETE /user/migrations/{migration_id}/archive" ], @@ -34069,27 +33812,6 @@ const Endpoints = { getArchiveForAuthenticatedUser: [ "GET /user/migrations/{migration_id}/archive" ], - getCommitAuthors: [ - "GET /repos/{owner}/{repo}/import/authors", - {}, - { - deprecated: "octokit.rest.migrations.getCommitAuthors() is deprecated, see https://docs.github.com/rest/migrations/source-imports#get-commit-authors" - } - ], - getImportStatus: [ - "GET /repos/{owner}/{repo}/import", - {}, - { - deprecated: "octokit.rest.migrations.getImportStatus() is deprecated, see https://docs.github.com/rest/migrations/source-imports#get-an-import-status" - } - ], - getLargeFiles: [ - "GET /repos/{owner}/{repo}/import/large_files", - {}, - { - deprecated: "octokit.rest.migrations.getLargeFiles() is deprecated, see https://docs.github.com/rest/migrations/source-imports#get-large-files" - } - ], getStatusForAuthenticatedUser: ["GET /user/migrations/{migration_id}"], getStatusForOrg: ["GET /orgs/{org}/migrations/{migration_id}"], listForAuthenticatedUser: ["GET /user/migrations"], @@ -34103,41 +33825,13 @@ const Endpoints = { {}, { renamed: ["migrations", "listReposForAuthenticatedUser"] } ], - mapCommitAuthor: [ - "PATCH /repos/{owner}/{repo}/import/authors/{author_id}", - {}, - { - deprecated: "octokit.rest.migrations.mapCommitAuthor() is deprecated, see https://docs.github.com/rest/migrations/source-imports#map-a-commit-author" - } - ], - setLfsPreference: [ - "PATCH /repos/{owner}/{repo}/import/lfs", - {}, - { - deprecated: "octokit.rest.migrations.setLfsPreference() is deprecated, see https://docs.github.com/rest/migrations/source-imports#update-git-lfs-preference" - } - ], startForAuthenticatedUser: ["POST /user/migrations"], startForOrg: ["POST /orgs/{org}/migrations"], - startImport: [ - "PUT /repos/{owner}/{repo}/import", - {}, - { - deprecated: "octokit.rest.migrations.startImport() is deprecated, see https://docs.github.com/rest/migrations/source-imports#start-an-import" - } - ], unlockRepoForAuthenticatedUser: [ "DELETE /user/migrations/{migration_id}/repos/{repo_name}/lock" ], unlockRepoForOrg: [ "DELETE /orgs/{org}/migrations/{migration_id}/repos/{repo_name}/lock" - ], - updateImport: [ - "PATCH /repos/{owner}/{repo}/import", - {}, - { - deprecated: "octokit.rest.migrations.updateImport() is deprecated, see https://docs.github.com/rest/migrations/source-imports#update-an-import" - } ] }, oidc: { @@ -34150,7 +33844,11 @@ const Endpoints = { }, orgs: { addSecurityManagerTeam: [ - "PUT /orgs/{org}/security-managers/teams/{team_slug}" + "PUT /orgs/{org}/security-managers/teams/{team_slug}", + {}, + { + deprecated: "octokit.rest.orgs.addSecurityManagerTeam() is deprecated, see https://docs.github.com/rest/orgs/security-managers#add-a-security-manager-team" + } ], assignTeamToOrgRole: [ "PUT /orgs/{org}/organization-roles/teams/{team_slug}/{role_id}" @@ -34166,32 +33864,69 @@ const Endpoints = { convertMemberToOutsideCollaborator: [ "PUT /orgs/{org}/outside_collaborators/{username}" ], - createCustomOrganizationRole: ["POST /orgs/{org}/organization-roles"], + createArtifactStorageRecord: [ + "POST /orgs/{org}/artifacts/metadata/storage-record" + ], createInvitation: ["POST /orgs/{org}/invitations"], - createOrUpdateCustomProperties: ["PATCH /orgs/{org}/properties/schema"], - createOrUpdateCustomPropertiesValuesForRepos: [ - "PATCH /orgs/{org}/properties/values" + createIssueType: ["POST /orgs/{org}/issue-types"], + createWebhook: ["POST /orgs/{org}/hooks"], + customPropertiesForOrgsCreateOrUpdateOrganizationValues: [ + "PATCH /organizations/{org}/org-properties/values" + ], + customPropertiesForOrgsGetOrganizationValues: [ + "GET /organizations/{org}/org-properties/values" ], - createOrUpdateCustomProperty: [ + customPropertiesForReposCreateOrUpdateOrganizationDefinition: [ "PUT /orgs/{org}/properties/schema/{custom_property_name}" ], - createWebhook: ["POST /orgs/{org}/hooks"], + customPropertiesForReposCreateOrUpdateOrganizationDefinitions: [ + "PATCH /orgs/{org}/properties/schema" + ], + customPropertiesForReposCreateOrUpdateOrganizationValues: [ + "PATCH /orgs/{org}/properties/values" + ], + customPropertiesForReposDeleteOrganizationDefinition: [ + "DELETE /orgs/{org}/properties/schema/{custom_property_name}" + ], + customPropertiesForReposGetOrganizationDefinition: [ + "GET /orgs/{org}/properties/schema/{custom_property_name}" + ], + customPropertiesForReposGetOrganizationDefinitions: [ + "GET /orgs/{org}/properties/schema" + ], + customPropertiesForReposGetOrganizationValues: [ + "GET /orgs/{org}/properties/values" + ], delete: ["DELETE /orgs/{org}"], - deleteCustomOrganizationRole: [ - "DELETE /orgs/{org}/organization-roles/{role_id}" + deleteAttestationsBulk: ["POST /orgs/{org}/attestations/delete-request"], + deleteAttestationsById: [ + "DELETE /orgs/{org}/attestations/{attestation_id}" ], + deleteAttestationsBySubjectDigest: [ + "DELETE /orgs/{org}/attestations/digest/{subject_digest}" + ], + deleteIssueType: ["DELETE /orgs/{org}/issue-types/{issue_type_id}"], deleteWebhook: ["DELETE /orgs/{org}/hooks/{hook_id}"], - enableOrDisableSecurityProductOnAllOrgRepos: [ - "POST /orgs/{org}/{security_product}/{enablement}" + disableSelectedRepositoryImmutableReleasesOrganization: [ + "DELETE /orgs/{org}/settings/immutable-releases/repositories/{repository_id}" + ], + enableSelectedRepositoryImmutableReleasesOrganization: [ + "PUT /orgs/{org}/settings/immutable-releases/repositories/{repository_id}" ], get: ["GET /orgs/{org}"], - getAllCustomProperties: ["GET /orgs/{org}/properties/schema"], - getCustomProperty: [ - "GET /orgs/{org}/properties/schema/{custom_property_name}" + getImmutableReleasesSettings: [ + "GET /orgs/{org}/settings/immutable-releases" + ], + getImmutableReleasesSettingsRepositories: [ + "GET /orgs/{org}/settings/immutable-releases/repositories" ], getMembershipForAuthenticatedUser: ["GET /user/memberships/orgs/{org}"], getMembershipForUser: ["GET /orgs/{org}/memberships/{username}"], getOrgRole: ["GET /orgs/{org}/organization-roles/{role_id}"], + getOrgRulesetHistory: ["GET /orgs/{org}/rulesets/{ruleset_id}/history"], + getOrgRulesetVersion: [ + "GET /orgs/{org}/rulesets/{ruleset_id}/history/{version_id}" + ], getWebhook: ["GET /orgs/{org}/hooks/{hook_id}"], getWebhookConfigForOrg: ["GET /orgs/{org}/hooks/{hook_id}/config"], getWebhookDelivery: [ @@ -34199,12 +33934,20 @@ const Endpoints = { ], list: ["GET /organizations"], listAppInstallations: ["GET /orgs/{org}/installations"], + listArtifactStorageRecords: [ + "GET /orgs/{org}/artifacts/{subject_digest}/metadata/storage-records" + ], + listAttestationRepositories: ["GET /orgs/{org}/attestations/repositories"], + listAttestations: ["GET /orgs/{org}/attestations/{subject_digest}"], + listAttestationsBulk: [ + "POST /orgs/{org}/attestations/bulk-list{?per_page,before,after}" + ], listBlockedUsers: ["GET /orgs/{org}/blocks"], - listCustomPropertiesValuesForRepos: ["GET /orgs/{org}/properties/values"], listFailedInvitations: ["GET /orgs/{org}/failed_invitations"], listForAuthenticatedUser: ["GET /user/orgs"], listForUser: ["GET /users/{username}/orgs"], listInvitationTeams: ["GET /orgs/{org}/invitations/{invitation_id}/teams"], + listIssueTypes: ["GET /orgs/{org}/issue-types"], listMembers: ["GET /orgs/{org}/members"], listMembershipsForAuthenticatedUser: ["GET /user/memberships/orgs"], listOrgRoleTeams: ["GET /orgs/{org}/organization-roles/{role_id}/teams"], @@ -34224,19 +33967,19 @@ const Endpoints = { listPatGrants: ["GET /orgs/{org}/personal-access-tokens"], listPendingInvitations: ["GET /orgs/{org}/invitations"], listPublicMembers: ["GET /orgs/{org}/public_members"], - listSecurityManagerTeams: ["GET /orgs/{org}/security-managers"], + listSecurityManagerTeams: [ + "GET /orgs/{org}/security-managers", + {}, + { + deprecated: "octokit.rest.orgs.listSecurityManagerTeams() is deprecated, see https://docs.github.com/rest/orgs/security-managers#list-security-manager-teams" + } + ], listWebhookDeliveries: ["GET /orgs/{org}/hooks/{hook_id}/deliveries"], listWebhooks: ["GET /orgs/{org}/hooks"], - patchCustomOrganizationRole: [ - "PATCH /orgs/{org}/organization-roles/{role_id}" - ], pingWebhook: ["POST /orgs/{org}/hooks/{hook_id}/pings"], redeliverWebhookDelivery: [ "POST /orgs/{org}/hooks/{hook_id}/deliveries/{delivery_id}/attempts" ], - removeCustomProperty: [ - "DELETE /orgs/{org}/properties/schema/{custom_property_name}" - ], removeMember: ["DELETE /orgs/{org}/members/{username}"], removeMembershipForUser: ["DELETE /orgs/{org}/memberships/{username}"], removeOutsideCollaborator: [ @@ -34246,7 +33989,11 @@ const Endpoints = { "DELETE /orgs/{org}/public_members/{username}" ], removeSecurityManagerTeam: [ - "DELETE /orgs/{org}/security-managers/teams/{team_slug}" + "DELETE /orgs/{org}/security-managers/teams/{team_slug}", + {}, + { + deprecated: "octokit.rest.orgs.removeSecurityManagerTeam() is deprecated, see https://docs.github.com/rest/orgs/security-managers#remove-a-security-manager-team" + } ], reviewPatGrantRequest: [ "POST /orgs/{org}/personal-access-token-requests/{pat_request_id}" @@ -34266,12 +34013,19 @@ const Endpoints = { revokeOrgRoleUser: [ "DELETE /orgs/{org}/organization-roles/users/{username}/{role_id}" ], + setImmutableReleasesSettings: [ + "PUT /orgs/{org}/settings/immutable-releases" + ], + setImmutableReleasesSettingsRepositories: [ + "PUT /orgs/{org}/settings/immutable-releases/repositories" + ], setMembershipForUser: ["PUT /orgs/{org}/memberships/{username}"], setPublicMembershipForAuthenticatedUser: [ "PUT /orgs/{org}/public_members/{username}" ], unblockUser: ["DELETE /orgs/{org}/blocks/{username}"], update: ["PATCH /orgs/{org}"], + updateIssueType: ["PUT /orgs/{org}/issue-types/{issue_type_id}"], updateMembershipForAuthenticatedUser: [ "PATCH /user/memberships/orgs/{org}" ], @@ -34372,36 +34126,57 @@ const Endpoints = { "POST /users/{username}/packages/{package_type}/{package_name}/versions/{package_version_id}/restore" ] }, + privateRegistries: { + createOrgPrivateRegistry: ["POST /orgs/{org}/private-registries"], + deleteOrgPrivateRegistry: [ + "DELETE /orgs/{org}/private-registries/{secret_name}" + ], + getOrgPrivateRegistry: ["GET /orgs/{org}/private-registries/{secret_name}"], + getOrgPublicKey: ["GET /orgs/{org}/private-registries/public-key"], + listOrgPrivateRegistries: ["GET /orgs/{org}/private-registries"], + updateOrgPrivateRegistry: [ + "PATCH /orgs/{org}/private-registries/{secret_name}" + ] + }, projects: { - addCollaborator: ["PUT /projects/{project_id}/collaborators/{username}"], - createCard: ["POST /projects/columns/{column_id}/cards"], - createColumn: ["POST /projects/{project_id}/columns"], - createForAuthenticatedUser: ["POST /user/projects"], - createForOrg: ["POST /orgs/{org}/projects"], - createForRepo: ["POST /repos/{owner}/{repo}/projects"], - delete: ["DELETE /projects/{project_id}"], - deleteCard: ["DELETE /projects/columns/cards/{card_id}"], - deleteColumn: ["DELETE /projects/columns/{column_id}"], - get: ["GET /projects/{project_id}"], - getCard: ["GET /projects/columns/cards/{card_id}"], - getColumn: ["GET /projects/columns/{column_id}"], - getPermissionForUser: [ - "GET /projects/{project_id}/collaborators/{username}/permission" - ], - listCards: ["GET /projects/columns/{column_id}/cards"], - listCollaborators: ["GET /projects/{project_id}/collaborators"], - listColumns: ["GET /projects/{project_id}/columns"], - listForOrg: ["GET /orgs/{org}/projects"], - listForRepo: ["GET /repos/{owner}/{repo}/projects"], - listForUser: ["GET /users/{username}/projects"], - moveCard: ["POST /projects/columns/cards/{card_id}/moves"], - moveColumn: ["POST /projects/columns/{column_id}/moves"], - removeCollaborator: [ - "DELETE /projects/{project_id}/collaborators/{username}" + addItemForOrg: ["POST /orgs/{org}/projectsV2/{project_number}/items"], + addItemForUser: [ + "POST /users/{username}/projectsV2/{project_number}/items" + ], + deleteItemForOrg: [ + "DELETE /orgs/{org}/projectsV2/{project_number}/items/{item_id}" + ], + deleteItemForUser: [ + "DELETE /users/{username}/projectsV2/{project_number}/items/{item_id}" + ], + getFieldForOrg: [ + "GET /orgs/{org}/projectsV2/{project_number}/fields/{field_id}" + ], + getFieldForUser: [ + "GET /users/{username}/projectsV2/{project_number}/fields/{field_id}" + ], + getForOrg: ["GET /orgs/{org}/projectsV2/{project_number}"], + getForUser: ["GET /users/{username}/projectsV2/{project_number}"], + getOrgItem: ["GET /orgs/{org}/projectsV2/{project_number}/items/{item_id}"], + getUserItem: [ + "GET /users/{username}/projectsV2/{project_number}/items/{item_id}" + ], + listFieldsForOrg: ["GET /orgs/{org}/projectsV2/{project_number}/fields"], + listFieldsForUser: [ + "GET /users/{username}/projectsV2/{project_number}/fields" + ], + listForOrg: ["GET /orgs/{org}/projectsV2"], + listForUser: ["GET /users/{username}/projectsV2"], + listItemsForOrg: ["GET /orgs/{org}/projectsV2/{project_number}/items"], + listItemsForUser: [ + "GET /users/{username}/projectsV2/{project_number}/items" + ], + updateItemForOrg: [ + "PATCH /orgs/{org}/projectsV2/{project_number}/items/{item_id}" ], - update: ["PATCH /projects/{project_id}"], - updateCard: ["PATCH /projects/columns/cards/{card_id}"], - updateColumn: ["PATCH /projects/columns/{column_id}"] + updateItemForUser: [ + "PATCH /users/{username}/projectsV2/{project_number}/items/{item_id}" + ] }, pulls: { checkIfMerged: ["GET /repos/{owner}/{repo}/pulls/{pull_number}/merge"], @@ -34563,6 +34338,10 @@ const Endpoints = { "GET /repos/{owner}/{repo}/automated-security-fixes" ], checkCollaborator: ["GET /repos/{owner}/{repo}/collaborators/{username}"], + checkImmutableReleases: ["GET /repos/{owner}/{repo}/immutable-releases"], + checkPrivateVulnerabilityReporting: [ + "GET /repos/{owner}/{repo}/private-vulnerability-reporting" + ], checkVulnerabilityAlerts: [ "GET /repos/{owner}/{repo}/vulnerability-alerts" ], @@ -34571,6 +34350,7 @@ const Endpoints = { compareCommitsWithBasehead: [ "GET /repos/{owner}/{repo}/compare/{basehead}" ], + createAttestation: ["POST /repos/{owner}/{repo}/attestations"], createAutolink: ["POST /repos/{owner}/{repo}/autolinks"], createCommitComment: [ "POST /repos/{owner}/{repo}/commits/{commit_sha}/comments" @@ -34594,9 +34374,6 @@ const Endpoints = { createForAuthenticatedUser: ["POST /user/repos"], createFork: ["POST /repos/{owner}/{repo}/forks"], createInOrg: ["POST /orgs/{org}/repos"], - createOrUpdateCustomPropertiesValues: [ - "PATCH /repos/{owner}/{repo}/properties/values" - ], createOrUpdateEnvironment: [ "PUT /repos/{owner}/{repo}/environments/{environment_name}" ], @@ -34606,11 +34383,16 @@ const Endpoints = { createPagesSite: ["POST /repos/{owner}/{repo}/pages"], createRelease: ["POST /repos/{owner}/{repo}/releases"], createRepoRuleset: ["POST /repos/{owner}/{repo}/rulesets"], - createTagProtection: ["POST /repos/{owner}/{repo}/tags/protection"], createUsingTemplate: [ "POST /repos/{template_owner}/{template_repo}/generate" ], createWebhook: ["POST /repos/{owner}/{repo}/hooks"], + customPropertiesForReposCreateOrUpdateRepositoryValues: [ + "PATCH /repos/{owner}/{repo}/properties/values" + ], + customPropertiesForReposGetRepositoryValues: [ + "GET /repos/{owner}/{repo}/properties/values" + ], declineInvitation: [ "DELETE /user/repository_invitations/{invitation_id}", {}, @@ -34658,9 +34440,6 @@ const Endpoints = { "DELETE /repos/{owner}/{repo}/releases/assets/{asset_id}" ], deleteRepoRuleset: ["DELETE /repos/{owner}/{repo}/rulesets/{ruleset_id}"], - deleteTagProtection: [ - "DELETE /repos/{owner}/{repo}/tags/protection/{tag_protection_id}" - ], deleteWebhook: ["DELETE /repos/{owner}/{repo}/hooks/{hook_id}"], disableAutomatedSecurityFixes: [ "DELETE /repos/{owner}/{repo}/automated-security-fixes" @@ -34668,6 +34447,9 @@ const Endpoints = { disableDeploymentProtectionRule: [ "DELETE /repos/{owner}/{repo}/environments/{environment_name}/deployment_protection_rules/{protection_rule_id}" ], + disableImmutableReleases: [ + "DELETE /repos/{owner}/{repo}/immutable-releases" + ], disablePrivateVulnerabilityReporting: [ "DELETE /repos/{owner}/{repo}/private-vulnerability-reporting" ], @@ -34684,6 +34466,7 @@ const Endpoints = { enableAutomatedSecurityFixes: [ "PUT /repos/{owner}/{repo}/automated-security-fixes" ], + enableImmutableReleases: ["PUT /repos/{owner}/{repo}/immutable-releases"], enablePrivateVulnerabilityReporting: [ "PUT /repos/{owner}/{repo}/private-vulnerability-reporting" ], @@ -34735,7 +34518,6 @@ const Endpoints = { getCustomDeploymentProtectionRule: [ "GET /repos/{owner}/{repo}/environments/{environment_name}/deployment_protection_rules/{protection_rule_id}" ], - getCustomPropertiesValues: ["GET /repos/{owner}/{repo}/properties/values"], getDeployKey: ["GET /repos/{owner}/{repo}/keys/{key_id}"], getDeployment: ["GET /repos/{owner}/{repo}/deployments/{deployment_id}"], getDeploymentBranchPolicy: [ @@ -34774,6 +34556,12 @@ const Endpoints = { ], getRepoRuleSuites: ["GET /repos/{owner}/{repo}/rulesets/rule-suites"], getRepoRuleset: ["GET /repos/{owner}/{repo}/rulesets/{ruleset_id}"], + getRepoRulesetHistory: [ + "GET /repos/{owner}/{repo}/rulesets/{ruleset_id}/history" + ], + getRepoRulesetVersion: [ + "GET /repos/{owner}/{repo}/rulesets/{ruleset_id}/history/{version_id}" + ], getRepoRulesets: ["GET /repos/{owner}/{repo}/rulesets"], getStatusChecksProtection: [ "GET /repos/{owner}/{repo}/branches/{branch}/protection/required_status_checks" @@ -34795,6 +34583,9 @@ const Endpoints = { "GET /repos/{owner}/{repo}/hooks/{hook_id}/deliveries/{delivery_id}" ], listActivities: ["GET /repos/{owner}/{repo}/activity"], + listAttestations: [ + "GET /repos/{owner}/{repo}/attestations/{subject_digest}" + ], listAutolinks: ["GET /repos/{owner}/{repo}/autolinks"], listBranches: ["GET /repos/{owner}/{repo}/branches"], listBranchesForHeadCommit: [ @@ -34837,7 +34628,6 @@ const Endpoints = { "GET /repos/{owner}/{repo}/releases/{release_id}/assets" ], listReleases: ["GET /repos/{owner}/{repo}/releases"], - listTagProtection: ["GET /repos/{owner}/{repo}/tags/protection"], listTags: ["GET /repos/{owner}/{repo}/tags"], listTeams: ["GET /repos/{owner}/{repo}/teams"], listWebhookDeliveries: [ @@ -34952,19 +34742,26 @@ const Endpoints = { users: ["GET /search/users"] }, secretScanning: { + createPushProtectionBypass: [ + "POST /repos/{owner}/{repo}/secret-scanning/push-protection-bypasses" + ], getAlert: [ "GET /repos/{owner}/{repo}/secret-scanning/alerts/{alert_number}" ], - listAlertsForEnterprise: [ - "GET /enterprises/{enterprise}/secret-scanning/alerts" - ], + getScanHistory: ["GET /repos/{owner}/{repo}/secret-scanning/scan-history"], listAlertsForOrg: ["GET /orgs/{org}/secret-scanning/alerts"], listAlertsForRepo: ["GET /repos/{owner}/{repo}/secret-scanning/alerts"], listLocationsForAlert: [ "GET /repos/{owner}/{repo}/secret-scanning/alerts/{alert_number}/locations" ], + listOrgPatternConfigs: [ + "GET /orgs/{org}/secret-scanning/pattern-configurations" + ], updateAlert: [ "PATCH /repos/{owner}/{repo}/secret-scanning/alerts/{alert_number}" + ], + updateOrgPatternConfigs: [ + "PATCH /orgs/{org}/secret-scanning/pattern-configurations" ] }, securityAdvisories: { @@ -34995,15 +34792,9 @@ const Endpoints = { addOrUpdateMembershipForUserInOrg: [ "PUT /orgs/{org}/teams/{team_slug}/memberships/{username}" ], - addOrUpdateProjectPermissionsInOrg: [ - "PUT /orgs/{org}/teams/{team_slug}/projects/{project_id}" - ], addOrUpdateRepoPermissionsInOrg: [ "PUT /orgs/{org}/teams/{team_slug}/repos/{owner}/{repo}" ], - checkPermissionsForProjectInOrg: [ - "GET /orgs/{org}/teams/{team_slug}/projects/{project_id}" - ], checkPermissionsForRepoInOrg: [ "GET /orgs/{org}/teams/{team_slug}/repos/{owner}/{repo}" ], @@ -35040,14 +34831,10 @@ const Endpoints = { listPendingInvitationsInOrg: [ "GET /orgs/{org}/teams/{team_slug}/invitations" ], - listProjectsInOrg: ["GET /orgs/{org}/teams/{team_slug}/projects"], listReposInOrg: ["GET /orgs/{org}/teams/{team_slug}/repos"], removeMembershipForUserInOrg: [ "DELETE /orgs/{org}/teams/{team_slug}/memberships/{username}" ], - removeProjectInOrg: [ - "DELETE /orgs/{org}/teams/{team_slug}/projects/{project_id}" - ], removeRepoInOrg: [ "DELETE /orgs/{org}/teams/{team_slug}/repos/{owner}/{repo}" ], @@ -35084,6 +34871,15 @@ const Endpoints = { ], createPublicSshKeyForAuthenticatedUser: ["POST /user/keys"], createSshSigningKeyForAuthenticatedUser: ["POST /user/ssh_signing_keys"], + deleteAttestationsBulk: [ + "POST /users/{username}/attestations/delete-request" + ], + deleteAttestationsById: [ + "DELETE /users/{username}/attestations/{attestation_id}" + ], + deleteAttestationsBySubjectDigest: [ + "DELETE /users/{username}/attestations/digest/{subject_digest}" + ], deleteEmailForAuthenticated: [ "DELETE /user/emails", {}, @@ -35108,6 +34904,7 @@ const Endpoints = { ], follow: ["PUT /user/following/{username}"], getAuthenticated: ["GET /user"], + getById: ["GET /user/{account_id}"], getByUsername: ["GET /users/{username}"], getContextForUser: ["GET /users/{username}/hovercard"], getGpgKeyForAuthenticated: [ @@ -35126,6 +34923,10 @@ const Endpoints = { "GET /user/ssh_signing_keys/{ssh_signing_key_id}" ], list: ["GET /users"], + listAttestations: ["GET /users/{username}/attestations/{subject_digest}"], + listAttestationsBulk: [ + "POST /users/{username}/attestations/bulk-list{?per_page,before,after}" + ], listBlockedByAuthenticated: [ "GET /user/blocks", {}, @@ -35324,506 +35125,144 @@ function legacyRestEndpointMethods(octokit) { } legacyRestEndpointMethods.VERSION = VERSION$1; -var distSrc = /*#__PURE__*/Object.freeze({ - __proto__: null, - legacyRestEndpointMethods: legacyRestEndpointMethods, - restEndpointMethods: restEndpointMethods -}); - -var require$$3 = /*@__PURE__*/getAugmentedNamespace(distSrc); - -// pkg/dist-src/version.js -var VERSION = "9.2.2"; +const VERSION = "22.0.1"; -// pkg/dist-src/normalize-paginated-list-response.js -function normalizePaginatedListResponse(response) { - if (!response.data) { - return { - ...response, - data: [] - }; - } - const responseNeedsNormalization = "total_count" in response.data && !("url" in response.data); - if (!responseNeedsNormalization) - return response; - const incompleteResults = response.data.incomplete_results; - const repositorySelection = response.data.repository_selection; - const totalCount = response.data.total_count; - delete response.data.incomplete_results; - delete response.data.repository_selection; - delete response.data.total_count; - const namespaceKey = Object.keys(response.data)[0]; - const data = response.data[namespaceKey]; - response.data = data; - if (typeof incompleteResults !== "undefined") { - response.data.incomplete_results = incompleteResults; - } - if (typeof repositorySelection !== "undefined") { - response.data.repository_selection = repositorySelection; +const Octokit = Octokit$1.plugin(requestLog, legacyRestEndpointMethods, paginateRest).defaults( + { + userAgent: `octokit-rest.js/${VERSION}` } - response.data.total_count = totalCount; - return response; -} +); -// pkg/dist-src/iterator.js -function iterator(octokit, route, parameters) { - const options = typeof route === "function" ? route.endpoint(parameters) : octokit.request.endpoint(route, parameters); - const requestMethod = typeof route === "function" ? route : octokit.request; - const method = options.method; - const headers = options.headers; - let url = options.url; - return { - [Symbol.asyncIterator]: () => ({ - async next() { - if (!url) - return { done: true }; - try { - const response = await requestMethod({ method, url, headers }); - const normalizedResponse = normalizePaginatedListResponse(response); - url = ((normalizedResponse.headers.link || "").match( - /<([^<>]+)>;\s*rel="next"/ - ) || [])[1]; - return { value: normalizedResponse }; - } catch (error) { - if (error.status !== 409) - throw error; - url = ""; - return { - value: { - status: 200, - headers: {}, - data: [] +class Context { + /** + * Hydrate the context from the environment + */ + constructor() { + var _a, _b, _c; + this.payload = {}; + if (process.env.GITHUB_EVENT_PATH) { + if (existsSync(process.env.GITHUB_EVENT_PATH)) { + this.payload = JSON.parse(readFileSync(process.env.GITHUB_EVENT_PATH, { encoding: 'utf8' })); + } + else { + const path = process.env.GITHUB_EVENT_PATH; + process.stdout.write(`GITHUB_EVENT_PATH ${path} does not exist${EOL}`); } - }; } - } - }) - }; -} - -// pkg/dist-src/paginate.js -function paginate(octokit, route, parameters, mapFn) { - if (typeof parameters === "function") { - mapFn = parameters; - parameters = void 0; - } - return gather( - octokit, - [], - iterator(octokit, route, parameters)[Symbol.asyncIterator](), - mapFn - ); -} -function gather(octokit, results, iterator2, mapFn) { - return iterator2.next().then((result) => { - if (result.done) { - return results; - } - let earlyExit = false; - function done() { - earlyExit = true; - } - results = results.concat( - mapFn ? mapFn(result.value, done) : result.value.data - ); - if (earlyExit) { - return results; + this.eventName = process.env.GITHUB_EVENT_NAME; + this.sha = process.env.GITHUB_SHA; + this.ref = process.env.GITHUB_REF; + this.workflow = process.env.GITHUB_WORKFLOW; + this.action = process.env.GITHUB_ACTION; + this.actor = process.env.GITHUB_ACTOR; + this.job = process.env.GITHUB_JOB; + this.runAttempt = parseInt(process.env.GITHUB_RUN_ATTEMPT, 10); + this.runNumber = parseInt(process.env.GITHUB_RUN_NUMBER, 10); + this.runId = parseInt(process.env.GITHUB_RUN_ID, 10); + this.apiUrl = (_a = process.env.GITHUB_API_URL) !== null && _a !== void 0 ? _a : `https://api.github.com`; + this.serverUrl = (_b = process.env.GITHUB_SERVER_URL) !== null && _b !== void 0 ? _b : `https://github.com`; + this.graphqlUrl = + (_c = process.env.GITHUB_GRAPHQL_URL) !== null && _c !== void 0 ? _c : `https://api.github.com/graphql`; + } + get issue() { + const payload = this.payload; + return Object.assign(Object.assign({}, this.repo), { number: (payload.issue || payload.pull_request || payload).number }); + } + get repo() { + if (process.env.GITHUB_REPOSITORY) { + const [owner, repo] = process.env.GITHUB_REPOSITORY.split('/'); + return { owner, repo }; + } + if (this.payload.repository) { + return { + owner: this.payload.repository.owner.login, + repo: this.payload.repository.name + }; + } + throw new Error("context.repo requires a GITHUB_REPOSITORY environment variable like 'owner/repo'"); } - return gather(octokit, results, iterator2, mapFn); - }); } -// pkg/dist-src/compose-paginate.js -var composePaginateRest = Object.assign(paginate, { - iterator -}); +var libExports$1 = requireLib$1(); -// pkg/dist-src/generated/paginating-endpoints.js -var paginatingEndpoints = [ - "GET /advisories", - "GET /app/hook/deliveries", - "GET /app/installation-requests", - "GET /app/installations", - "GET /assignments/{assignment_id}/accepted_assignments", - "GET /classrooms", - "GET /classrooms/{classroom_id}/assignments", - "GET /enterprises/{enterprise}/dependabot/alerts", - "GET /enterprises/{enterprise}/secret-scanning/alerts", - "GET /events", - "GET /gists", - "GET /gists/public", - "GET /gists/starred", - "GET /gists/{gist_id}/comments", - "GET /gists/{gist_id}/commits", - "GET /gists/{gist_id}/forks", - "GET /installation/repositories", - "GET /issues", - "GET /licenses", - "GET /marketplace_listing/plans", - "GET /marketplace_listing/plans/{plan_id}/accounts", - "GET /marketplace_listing/stubbed/plans", - "GET /marketplace_listing/stubbed/plans/{plan_id}/accounts", - "GET /networks/{owner}/{repo}/events", - "GET /notifications", - "GET /organizations", - "GET /orgs/{org}/actions/cache/usage-by-repository", - "GET /orgs/{org}/actions/permissions/repositories", - "GET /orgs/{org}/actions/runners", - "GET /orgs/{org}/actions/secrets", - "GET /orgs/{org}/actions/secrets/{secret_name}/repositories", - "GET /orgs/{org}/actions/variables", - "GET /orgs/{org}/actions/variables/{name}/repositories", - "GET /orgs/{org}/blocks", - "GET /orgs/{org}/code-scanning/alerts", - "GET /orgs/{org}/codespaces", - "GET /orgs/{org}/codespaces/secrets", - "GET /orgs/{org}/codespaces/secrets/{secret_name}/repositories", - "GET /orgs/{org}/copilot/billing/seats", - "GET /orgs/{org}/dependabot/alerts", - "GET /orgs/{org}/dependabot/secrets", - "GET /orgs/{org}/dependabot/secrets/{secret_name}/repositories", - "GET /orgs/{org}/events", - "GET /orgs/{org}/failed_invitations", - "GET /orgs/{org}/hooks", - "GET /orgs/{org}/hooks/{hook_id}/deliveries", - "GET /orgs/{org}/installations", - "GET /orgs/{org}/invitations", - "GET /orgs/{org}/invitations/{invitation_id}/teams", - "GET /orgs/{org}/issues", - "GET /orgs/{org}/members", - "GET /orgs/{org}/members/{username}/codespaces", - "GET /orgs/{org}/migrations", - "GET /orgs/{org}/migrations/{migration_id}/repositories", - "GET /orgs/{org}/organization-roles/{role_id}/teams", - "GET /orgs/{org}/organization-roles/{role_id}/users", - "GET /orgs/{org}/outside_collaborators", - "GET /orgs/{org}/packages", - "GET /orgs/{org}/packages/{package_type}/{package_name}/versions", - "GET /orgs/{org}/personal-access-token-requests", - "GET /orgs/{org}/personal-access-token-requests/{pat_request_id}/repositories", - "GET /orgs/{org}/personal-access-tokens", - "GET /orgs/{org}/personal-access-tokens/{pat_id}/repositories", - "GET /orgs/{org}/projects", - "GET /orgs/{org}/properties/values", - "GET /orgs/{org}/public_members", - "GET /orgs/{org}/repos", - "GET /orgs/{org}/rulesets", - "GET /orgs/{org}/rulesets/rule-suites", - "GET /orgs/{org}/secret-scanning/alerts", - "GET /orgs/{org}/security-advisories", - "GET /orgs/{org}/teams", - "GET /orgs/{org}/teams/{team_slug}/discussions", - "GET /orgs/{org}/teams/{team_slug}/discussions/{discussion_number}/comments", - "GET /orgs/{org}/teams/{team_slug}/discussions/{discussion_number}/comments/{comment_number}/reactions", - "GET /orgs/{org}/teams/{team_slug}/discussions/{discussion_number}/reactions", - "GET /orgs/{org}/teams/{team_slug}/invitations", - "GET /orgs/{org}/teams/{team_slug}/members", - "GET /orgs/{org}/teams/{team_slug}/projects", - "GET /orgs/{org}/teams/{team_slug}/repos", - "GET /orgs/{org}/teams/{team_slug}/teams", - "GET /projects/columns/{column_id}/cards", - "GET /projects/{project_id}/collaborators", - "GET /projects/{project_id}/columns", - "GET /repos/{owner}/{repo}/actions/artifacts", - "GET /repos/{owner}/{repo}/actions/caches", - "GET /repos/{owner}/{repo}/actions/organization-secrets", - "GET /repos/{owner}/{repo}/actions/organization-variables", - "GET /repos/{owner}/{repo}/actions/runners", - "GET /repos/{owner}/{repo}/actions/runs", - "GET /repos/{owner}/{repo}/actions/runs/{run_id}/artifacts", - "GET /repos/{owner}/{repo}/actions/runs/{run_id}/attempts/{attempt_number}/jobs", - "GET /repos/{owner}/{repo}/actions/runs/{run_id}/jobs", - "GET /repos/{owner}/{repo}/actions/secrets", - "GET /repos/{owner}/{repo}/actions/variables", - "GET /repos/{owner}/{repo}/actions/workflows", - "GET /repos/{owner}/{repo}/actions/workflows/{workflow_id}/runs", - "GET /repos/{owner}/{repo}/activity", - "GET /repos/{owner}/{repo}/assignees", - "GET /repos/{owner}/{repo}/branches", - "GET /repos/{owner}/{repo}/check-runs/{check_run_id}/annotations", - "GET /repos/{owner}/{repo}/check-suites/{check_suite_id}/check-runs", - "GET /repos/{owner}/{repo}/code-scanning/alerts", - "GET /repos/{owner}/{repo}/code-scanning/alerts/{alert_number}/instances", - "GET /repos/{owner}/{repo}/code-scanning/analyses", - "GET /repos/{owner}/{repo}/codespaces", - "GET /repos/{owner}/{repo}/codespaces/devcontainers", - "GET /repos/{owner}/{repo}/codespaces/secrets", - "GET /repos/{owner}/{repo}/collaborators", - "GET /repos/{owner}/{repo}/comments", - "GET /repos/{owner}/{repo}/comments/{comment_id}/reactions", - "GET /repos/{owner}/{repo}/commits", - "GET /repos/{owner}/{repo}/commits/{commit_sha}/comments", - "GET /repos/{owner}/{repo}/commits/{commit_sha}/pulls", - "GET /repos/{owner}/{repo}/commits/{ref}/check-runs", - "GET /repos/{owner}/{repo}/commits/{ref}/check-suites", - "GET /repos/{owner}/{repo}/commits/{ref}/status", - "GET /repos/{owner}/{repo}/commits/{ref}/statuses", - "GET /repos/{owner}/{repo}/contributors", - "GET /repos/{owner}/{repo}/dependabot/alerts", - "GET /repos/{owner}/{repo}/dependabot/secrets", - "GET /repos/{owner}/{repo}/deployments", - "GET /repos/{owner}/{repo}/deployments/{deployment_id}/statuses", - "GET /repos/{owner}/{repo}/environments", - "GET /repos/{owner}/{repo}/environments/{environment_name}/deployment-branch-policies", - "GET /repos/{owner}/{repo}/environments/{environment_name}/deployment_protection_rules/apps", - "GET /repos/{owner}/{repo}/events", - "GET /repos/{owner}/{repo}/forks", - "GET /repos/{owner}/{repo}/hooks", - "GET /repos/{owner}/{repo}/hooks/{hook_id}/deliveries", - "GET /repos/{owner}/{repo}/invitations", - "GET /repos/{owner}/{repo}/issues", - "GET /repos/{owner}/{repo}/issues/comments", - "GET /repos/{owner}/{repo}/issues/comments/{comment_id}/reactions", - "GET /repos/{owner}/{repo}/issues/events", - "GET /repos/{owner}/{repo}/issues/{issue_number}/comments", - "GET /repos/{owner}/{repo}/issues/{issue_number}/events", - "GET /repos/{owner}/{repo}/issues/{issue_number}/labels", - "GET /repos/{owner}/{repo}/issues/{issue_number}/reactions", - "GET /repos/{owner}/{repo}/issues/{issue_number}/timeline", - "GET /repos/{owner}/{repo}/keys", - "GET /repos/{owner}/{repo}/labels", - "GET /repos/{owner}/{repo}/milestones", - "GET /repos/{owner}/{repo}/milestones/{milestone_number}/labels", - "GET /repos/{owner}/{repo}/notifications", - "GET /repos/{owner}/{repo}/pages/builds", - "GET /repos/{owner}/{repo}/projects", - "GET /repos/{owner}/{repo}/pulls", - "GET /repos/{owner}/{repo}/pulls/comments", - "GET /repos/{owner}/{repo}/pulls/comments/{comment_id}/reactions", - "GET /repos/{owner}/{repo}/pulls/{pull_number}/comments", - "GET /repos/{owner}/{repo}/pulls/{pull_number}/commits", - "GET /repos/{owner}/{repo}/pulls/{pull_number}/files", - "GET /repos/{owner}/{repo}/pulls/{pull_number}/reviews", - "GET /repos/{owner}/{repo}/pulls/{pull_number}/reviews/{review_id}/comments", - "GET /repos/{owner}/{repo}/releases", - "GET /repos/{owner}/{repo}/releases/{release_id}/assets", - "GET /repos/{owner}/{repo}/releases/{release_id}/reactions", - "GET /repos/{owner}/{repo}/rules/branches/{branch}", - "GET /repos/{owner}/{repo}/rulesets", - "GET /repos/{owner}/{repo}/rulesets/rule-suites", - "GET /repos/{owner}/{repo}/secret-scanning/alerts", - "GET /repos/{owner}/{repo}/secret-scanning/alerts/{alert_number}/locations", - "GET /repos/{owner}/{repo}/security-advisories", - "GET /repos/{owner}/{repo}/stargazers", - "GET /repos/{owner}/{repo}/subscribers", - "GET /repos/{owner}/{repo}/tags", - "GET /repos/{owner}/{repo}/teams", - "GET /repos/{owner}/{repo}/topics", - "GET /repositories", - "GET /repositories/{repository_id}/environments/{environment_name}/secrets", - "GET /repositories/{repository_id}/environments/{environment_name}/variables", - "GET /search/code", - "GET /search/commits", - "GET /search/issues", - "GET /search/labels", - "GET /search/repositories", - "GET /search/topics", - "GET /search/users", - "GET /teams/{team_id}/discussions", - "GET /teams/{team_id}/discussions/{discussion_number}/comments", - "GET /teams/{team_id}/discussions/{discussion_number}/comments/{comment_number}/reactions", - "GET /teams/{team_id}/discussions/{discussion_number}/reactions", - "GET /teams/{team_id}/invitations", - "GET /teams/{team_id}/members", - "GET /teams/{team_id}/projects", - "GET /teams/{team_id}/repos", - "GET /teams/{team_id}/teams", - "GET /user/blocks", - "GET /user/codespaces", - "GET /user/codespaces/secrets", - "GET /user/emails", - "GET /user/followers", - "GET /user/following", - "GET /user/gpg_keys", - "GET /user/installations", - "GET /user/installations/{installation_id}/repositories", - "GET /user/issues", - "GET /user/keys", - "GET /user/marketplace_purchases", - "GET /user/marketplace_purchases/stubbed", - "GET /user/memberships/orgs", - "GET /user/migrations", - "GET /user/migrations/{migration_id}/repositories", - "GET /user/orgs", - "GET /user/packages", - "GET /user/packages/{package_type}/{package_name}/versions", - "GET /user/public_emails", - "GET /user/repos", - "GET /user/repository_invitations", - "GET /user/social_accounts", - "GET /user/ssh_signing_keys", - "GET /user/starred", - "GET /user/subscriptions", - "GET /user/teams", - "GET /users", - "GET /users/{username}/events", - "GET /users/{username}/events/orgs/{org}", - "GET /users/{username}/events/public", - "GET /users/{username}/followers", - "GET /users/{username}/following", - "GET /users/{username}/gists", - "GET /users/{username}/gpg_keys", - "GET /users/{username}/keys", - "GET /users/{username}/orgs", - "GET /users/{username}/packages", - "GET /users/{username}/projects", - "GET /users/{username}/received_events", - "GET /users/{username}/received_events/public", - "GET /users/{username}/repos", - "GET /users/{username}/social_accounts", - "GET /users/{username}/ssh_signing_keys", - "GET /users/{username}/starred", - "GET /users/{username}/subscriptions" -]; +var undiciExports = requireUndici(); -// pkg/dist-src/paginating-endpoints.js -function isPaginatingEndpoint(arg) { - if (typeof arg === "string") { - return paginatingEndpoints.includes(arg); - } else { - return false; - } +var __awaiter = (undefined && undefined.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +function getAuthString(token, options) { + if (!token && !options.auth) { + throw new Error('Parameter token or opts.auth is required'); + } + else if (token && options.auth) { + throw new Error('Parameters token and opts.auth may not both be specified'); + } + return typeof options.auth === 'string' ? options.auth : `token ${token}`; } - -// pkg/dist-src/index.js -function paginateRest(octokit) { - return { - paginate: Object.assign(paginate.bind(null, octokit), { - iterator: iterator.bind(null, octokit) - }) - }; +function getProxyAgent(destinationUrl) { + const hc = new libExports$1.HttpClient(); + return hc.getAgent(destinationUrl); } -paginateRest.VERSION = VERSION; - -var distWeb = /*#__PURE__*/Object.freeze({ - __proto__: null, - composePaginateRest: composePaginateRest, - isPaginatingEndpoint: isPaginatingEndpoint, - paginateRest: paginateRest, - paginatingEndpoints: paginatingEndpoints -}); - -var require$$4 = /*@__PURE__*/getAugmentedNamespace(distWeb); - -var hasRequiredUtils$1; - -function requireUtils$1 () { - if (hasRequiredUtils$1) return utils$2; - hasRequiredUtils$1 = 1; - (function (exports$1) { - var __createBinding = (utils$2 && utils$2.__createBinding) || (Object.create ? (function(o, m, k, k2) { - if (k2 === undefined) k2 = k; - var desc = Object.getOwnPropertyDescriptor(m, k); - if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { - desc = { enumerable: true, get: function() { return m[k]; } }; - } - Object.defineProperty(o, k2, desc); - }) : (function(o, m, k, k2) { - if (k2 === undefined) k2 = k; - o[k2] = m[k]; - })); - var __setModuleDefault = (utils$2 && utils$2.__setModuleDefault) || (Object.create ? (function(o, v) { - Object.defineProperty(o, "default", { enumerable: true, value: v }); - }) : function(o, v) { - o["default"] = v; - }); - var __importStar = (utils$2 && utils$2.__importStar) || function (mod) { - if (mod && mod.__esModule) return mod; - var result = {}; - if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); - __setModuleDefault(result, mod); - return result; - }; - Object.defineProperty(exports$1, "__esModule", { value: true }); - exports$1.getOctokitOptions = exports$1.GitHub = exports$1.defaults = exports$1.context = void 0; - const Context = __importStar(requireContext()); - const Utils = __importStar(requireUtils$2()); - // octokit + plugins - const core_1 = require$$2; - const plugin_rest_endpoint_methods_1 = require$$3; - const plugin_paginate_rest_1 = require$$4; - exports$1.context = new Context.Context(); - const baseUrl = Utils.getApiBaseUrl(); - exports$1.defaults = { - baseUrl, - request: { - agent: Utils.getProxyAgent(baseUrl), - fetch: Utils.getProxyFetch(baseUrl) - } - }; - exports$1.GitHub = core_1.Octokit.plugin(plugin_rest_endpoint_methods_1.restEndpointMethods, plugin_paginate_rest_1.paginateRest).defaults(exports$1.defaults); - /** - * Convience function to correctly format Octokit Options to pass into the constructor. - * - * @param token the repo PAT or GITHUB_TOKEN - * @param options other options to set - */ - function getOctokitOptions(token, options) { - const opts = Object.assign({}, options || {}); // Shallow clone - don't mutate the object provided by the caller - // Auth - const auth = Utils.getAuthString(token, opts); - if (auth) { - opts.auth = auth; - } - return opts; - } - exports$1.getOctokitOptions = getOctokitOptions; - - } (utils$2)); - return utils$2; +function getProxyAgentDispatcher(destinationUrl) { + const hc = new libExports$1.HttpClient(); + return hc.getAgentDispatcher(destinationUrl); +} +function getProxyFetch(destinationUrl) { + const httpDispatcher = getProxyAgentDispatcher(destinationUrl); + const proxyFetch = (url, opts) => __awaiter(this, void 0, void 0, function* () { + return undiciExports.fetch(url, Object.assign(Object.assign({}, opts), { dispatcher: httpDispatcher })); + }); + return proxyFetch; +} +function getApiBaseUrl() { + return process.env['GITHUB_API_URL'] || 'https://api.github.com'; } -var hasRequiredGithub; - -function requireGithub () { - if (hasRequiredGithub) return github; - hasRequiredGithub = 1; - var __createBinding = (github && github.__createBinding) || (Object.create ? (function(o, m, k, k2) { - if (k2 === undefined) k2 = k; - var desc = Object.getOwnPropertyDescriptor(m, k); - if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { - desc = { enumerable: true, get: function() { return m[k]; } }; - } - Object.defineProperty(o, k2, desc); - }) : (function(o, m, k, k2) { - if (k2 === undefined) k2 = k; - o[k2] = m[k]; - })); - var __setModuleDefault = (github && github.__setModuleDefault) || (Object.create ? (function(o, v) { - Object.defineProperty(o, "default", { enumerable: true, value: v }); - }) : function(o, v) { - o["default"] = v; - }); - var __importStar = (github && github.__importStar) || function (mod) { - if (mod && mod.__esModule) return mod; - var result = {}; - if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); - __setModuleDefault(result, mod); - return result; - }; - Object.defineProperty(github, "__esModule", { value: true }); - github.getOctokit = github.context = void 0; - const Context = __importStar(requireContext()); - const utils_1 = requireUtils$1(); - github.context = new Context.Context(); - /** - * Returns a hydrated octokit ready to use for GitHub Actions - * - * @param token the repo PAT or GITHUB_TOKEN - * @param options other options to set - */ - function getOctokit(token, options, ...additionalPlugins) { - const GitHubWithPlugins = utils_1.GitHub.plugin(...additionalPlugins); - return new GitHubWithPlugins((0, utils_1.getOctokitOptions)(token, options)); - } - github.getOctokit = getOctokit; - - return github; +new Context(); +const baseUrl = getApiBaseUrl(); +const defaults = { + baseUrl, + request: { + agent: getProxyAgent(baseUrl), + fetch: getProxyFetch(baseUrl) + } +}; +const GitHub = Octokit$1.plugin(restEndpointMethods, paginateRest).defaults(defaults); +/** + * Convience function to correctly format Octokit Options to pass into the constructor. + * + * @param token the repo PAT or GITHUB_TOKEN + * @param options other options to set + */ +function getOctokitOptions(token, options) { + const opts = Object.assign({}, options || {}); // Shallow clone - don't mutate the object provided by the caller + // Auth + const auth = getAuthString(token, opts); + if (auth) { + opts.auth = auth; + } + return opts; } -var githubExports = requireGithub(); +const context = new Context(); +/** + * Returns a hydrated octokit ready to use for GitHub Actions + * + * @param token the repo PAT or GITHUB_TOKEN + * @param options other options to set + */ +function getOctokit(token, options, ...additionalPlugins) { + const GitHubWithPlugins = GitHub.plugin(...additionalPlugins); + return new GitHubWithPlugins(getOctokitOptions(token, options)); +} -const COMMENT_IDENTIFIER = ``; +const COMMENT_IDENTIFIER = ``; /** * Gets the comment ID that contains the previous validator result comment, if @@ -35833,7 +35272,7 @@ const COMMENT_IDENTIFIER = `