diff --git a/.gitattributes b/.gitattributes index a6344aac8c09253b3b630fb776ae94478aa0275b..621b918814f355f99623457d46a8a997c110f2b1 100644 --- a/.gitattributes +++ b/.gitattributes @@ -11,6 +11,7 @@ *.mlmodel filter=lfs diff=lfs merge=lfs -text *.model filter=lfs diff=lfs merge=lfs -text *.msgpack filter=lfs diff=lfs merge=lfs -text +*.node filter=lfs diff=lfs merge=lfs -text *.npy filter=lfs diff=lfs merge=lfs -text *.npz filter=lfs diff=lfs merge=lfs -text *.onnx filter=lfs diff=lfs merge=lfs -text diff --git a/node_modules/.bin/msw b/node_modules/.bin/msw new file mode 120000 index 0000000000000000000000000000000000000000..63485abf5a1cb580cc1cd462bc67eb4bfea388c4 --- /dev/null +++ b/node_modules/.bin/msw @@ -0,0 +1 @@ +../msw/cli/index.js \ No newline at end of file diff --git a/node_modules/.bin/node-gyp-build b/node_modules/.bin/node-gyp-build new file mode 120000 index 0000000000000000000000000000000000000000..671c6ebcea1d4e99e0367e96b313158ea9f9e1db --- /dev/null +++ b/node_modules/.bin/node-gyp-build @@ -0,0 +1 @@ +../node-gyp-build/bin.js \ No newline at end of file diff --git a/node_modules/.bin/node-gyp-build-optional b/node_modules/.bin/node-gyp-build-optional new file mode 120000 index 0000000000000000000000000000000000000000..46d347e6b1399b9bd08d727dbd1dd927b7086fd2 --- /dev/null +++ b/node_modules/.bin/node-gyp-build-optional @@ -0,0 +1 @@ +../node-gyp-build/optional.js \ No newline at end of file diff --git a/node_modules/.bin/node-gyp-build-test b/node_modules/.bin/node-gyp-build-test new file mode 120000 index 0000000000000000000000000000000000000000..d11de1becd5ee3b6a20f1e0ace8d64214eafeb15 --- /dev/null +++ b/node_modules/.bin/node-gyp-build-test @@ -0,0 +1 @@ +../node-gyp-build/build-test.js \ No newline at end of file diff --git a/node_modules/.bin/tsc b/node_modules/.bin/tsc new file mode 120000 index 0000000000000000000000000000000000000000..0863208a6a1fe7ba964993a1a398794c4021ae19 --- /dev/null +++ b/node_modules/.bin/tsc @@ -0,0 +1 @@ +../typescript/bin/tsc \ No newline at end of file diff --git a/node_modules/.bin/tsserver b/node_modules/.bin/tsserver new file mode 120000 index 0000000000000000000000000000000000000000..f8f8f1a0c33562942ab214430b7878ee378cfdd8 --- /dev/null +++ b/node_modules/.bin/tsserver @@ -0,0 +1 @@ +../typescript/bin/tsserver \ No newline at end of file diff --git a/node_modules/.package-lock.json b/node_modules/.package-lock.json new file mode 100644 index 0000000000000000000000000000000000000000..576ae21c9237966c66c18821f9cd573fa5e201bf --- /dev/null +++ b/node_modules/.package-lock.json @@ -0,0 +1,726 @@ +{ + "name": "app", + "lockfileVersion": 3, + "requires": true, + "packages": { + "node_modules/@bundled-es-modules/cookie": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@bundled-es-modules/cookie/-/cookie-2.0.1.tgz", + "integrity": "sha512-8o+5fRPLNbjbdGRRmJj3h6Hh1AQJf2dk3qQ/5ZFb+PXkRNiSoMGGUKlsgLfrxneb72axVJyIYji64E2+nNfYyw==", + "license": "ISC", + "dependencies": { + "cookie": "^0.7.2" + } + }, + "node_modules/@bundled-es-modules/statuses": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@bundled-es-modules/statuses/-/statuses-1.0.1.tgz", + "integrity": "sha512-yn7BklA5acgcBr+7w064fGV+SGIFySjCKpqjcWgBAIfrAkY+4GQTJJHQMeT3V/sgz23VTEVV8TtOmkvJAhFVfg==", + "license": "ISC", + "dependencies": { + "statuses": "^2.0.1" + } + }, + "node_modules/@bundled-es-modules/tough-cookie": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/@bundled-es-modules/tough-cookie/-/tough-cookie-0.1.6.tgz", + "integrity": "sha512-dvMHbL464C0zI+Yqxbz6kZ5TOEp7GLW+pry/RWndAR8MJQAXZ2rPmIs8tziTZjeIyhSNZgZbCePtfSbdWqStJw==", + "license": "ISC", + "dependencies": { + "@types/tough-cookie": "^4.0.5", + "tough-cookie": "^4.1.4" + } + }, + "node_modules/@gradio/client": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@gradio/client/-/client-1.14.1.tgz", + "integrity": "sha512-0ey5deyei0bXOCl2+ghfPWnOCnteDdp5rdlKyq7mq0PDYMwjsonS1VhMaoNo0Yks01KDTe7rrdvYOUXueDn9Cg==", + "license": "ISC", + "dependencies": { + "@types/eventsource": "^1.1.15", + "bufferutil": "^4.0.7", + "eventsource": "^2.0.2", + "fetch-event-stream": "^0.1.5", + "msw": "^2.2.1", + "semiver": "^1.1.0", + "textlinestream": "^1.1.1", + "typescript": "^5.0.0", + "ws": "^8.13.0" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@inquirer/confirm": { + "version": "5.1.9", + "resolved": "https://registry.npmjs.org/@inquirer/confirm/-/confirm-5.1.9.tgz", + "integrity": "sha512-NgQCnHqFTjF7Ys2fsqK2WtnA8X1kHyInyG+nMIuHowVTIgIuS10T4AznI/PvbqSpJqjCUqNBlKGh1v3bwLFL4w==", + "license": "MIT", + "dependencies": { + "@inquirer/core": "^10.1.10", + "@inquirer/type": "^3.0.6" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/core": { + "version": "10.1.10", + "resolved": "https://registry.npmjs.org/@inquirer/core/-/core-10.1.10.tgz", + "integrity": "sha512-roDaKeY1PYY0aCqhRmXihrHjoSW2A00pV3Ke5fTpMCkzcGF64R8e0lw3dK+eLEHwS4vB5RnW1wuQmvzoRul8Mw==", + "license": "MIT", + "dependencies": { + "@inquirer/figures": "^1.0.11", + "@inquirer/type": "^3.0.6", + "ansi-escapes": "^4.3.2", + "cli-width": "^4.1.0", + "mute-stream": "^2.0.0", + "signal-exit": "^4.1.0", + "wrap-ansi": "^6.2.0", + "yoctocolors-cjs": "^2.1.2" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/figures": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@inquirer/figures/-/figures-1.0.11.tgz", + "integrity": "sha512-eOg92lvrn/aRUqbxRyvpEWnrvRuTYRifixHkYVpJiygTgVSBIHDqLh0SrMQXkafvULg3ck11V7xvR+zcgvpHFw==", + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/@inquirer/type": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/@inquirer/type/-/type-3.0.6.tgz", + "integrity": "sha512-/mKVCtVpyBu3IDarv0G+59KC4stsD5mDsGpYh+GKs1NZT88Jh52+cuoA1AtLk2Q0r/quNl+1cSUyLRHBFeD0XA==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@mswjs/interceptors": { + "version": "0.37.6", + "resolved": "https://registry.npmjs.org/@mswjs/interceptors/-/interceptors-0.37.6.tgz", + "integrity": "sha512-wK+5pLK5XFmgtH3aQ2YVvA3HohS3xqV/OxuVOdNx9Wpnz7VE/fnC+e1A7ln6LFYeck7gOJ/dsZV6OLplOtAJ2w==", + "license": "MIT", + "dependencies": { + "@open-draft/deferred-promise": "^2.2.0", + "@open-draft/logger": "^0.3.0", + "@open-draft/until": "^2.0.0", + "is-node-process": "^1.2.0", + "outvariant": "^1.4.3", + "strict-event-emitter": "^0.5.1" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@open-draft/deferred-promise": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@open-draft/deferred-promise/-/deferred-promise-2.2.0.tgz", + "integrity": "sha512-CecwLWx3rhxVQF6V4bAgPS5t+So2sTbPgAzafKkVizyi7tlwpcFpdFqq+wqF2OwNBmqFuu6tOyouTuxgpMfzmA==", + "license": "MIT" + }, + "node_modules/@open-draft/logger": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@open-draft/logger/-/logger-0.3.0.tgz", + "integrity": "sha512-X2g45fzhxH238HKO4xbSr7+wBS8Fvw6ixhTDuvLd5mqh6bJJCFAPwU9mPDxbcrRtfxv4u5IHCEH77BmxvXmmxQ==", + "license": "MIT", + "dependencies": { + "is-node-process": "^1.2.0", + "outvariant": "^1.4.0" + } + }, + "node_modules/@open-draft/until": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@open-draft/until/-/until-2.1.0.tgz", + "integrity": "sha512-U69T3ItWHvLwGg5eJ0n3I62nWuE6ilHlmz7zM0npLBRvPRd7e6NYmg54vvRtP5mZG7kZqZCFVdsTWo7BPtBujg==", + "license": "MIT" + }, + "node_modules/@types/cookie": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.6.0.tgz", + "integrity": "sha512-4Kh9a6B2bQciAhf7FSuMRRkUWecJgJu9nPnx3yzpsfXX/c50REIqpHY4C82bXP90qrLtXtkDxTZosYO3UpOwlA==", + "license": "MIT" + }, + "node_modules/@types/eventsource": { + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/@types/eventsource/-/eventsource-1.1.15.tgz", + "integrity": "sha512-XQmGcbnxUNa06HR3VBVkc9+A2Vpi9ZyLJcdS5dwaQQ/4ZMWFO+5c90FnMUpbtMZwB/FChoYHwuVg8TvkECacTA==", + "license": "MIT" + }, + "node_modules/@types/statuses": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@types/statuses/-/statuses-2.0.5.tgz", + "integrity": "sha512-jmIUGWrAiwu3dZpxntxieC+1n/5c3mjrImkmOSQ2NC5uP6cYO4aAZDdSmRcI5C1oiTmqlZGHC+/NmJrKogbP5A==", + "license": "MIT" + }, + "node_modules/@types/tough-cookie": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/@types/tough-cookie/-/tough-cookie-4.0.5.tgz", + "integrity": "sha512-/Ad8+nIOV7Rl++6f1BdKxFSMgmoqEoYbHRpPcx3JEfv8VRsQe9Z4mCXeJBzxs7mbHY/XOZZuXlRNfhpVPbs6ZA==", + "license": "MIT" + }, + "node_modules/ansi-escapes": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", + "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", + "license": "MIT", + "dependencies": { + "type-fest": "^0.21.3" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ansi-escapes/node_modules/type-fest": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", + "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/bufferutil": { + "version": "4.0.9", + "resolved": "https://registry.npmjs.org/bufferutil/-/bufferutil-4.0.9.tgz", + "integrity": "sha512-WDtdLmJvAuNNPzByAYpRo2rF1Mmradw6gvWsQKf63476DDXmomT9zUiGypLcG4ibIM67vhAj8jJRdbmEws2Aqw==", + "hasInstallScript": true, + "license": "MIT", + "dependencies": { + "node-gyp-build": "^4.3.0" + }, + "engines": { + "node": ">=6.14.2" + } + }, + "node_modules/cli-width": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-4.1.0.tgz", + "integrity": "sha512-ouuZd4/dm2Sw5Gmqy6bGyNNNe1qt9RpmxveLSO7KcgsTnU7RXfsw+/bukWGo1abgBiMAic068rclZsO4IWmmxQ==", + "license": "ISC", + "engines": { + "node": ">= 12" + } + }, + "node_modules/cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "license": "ISC", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/cliui/node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "license": "MIT" + }, + "node_modules/cookie": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz", + "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "license": "MIT" + }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/eventsource": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/eventsource/-/eventsource-2.0.2.tgz", + "integrity": "sha512-IzUmBGPR3+oUG9dUeXynyNmf91/3zUSJg1lCktzKw47OXuhco54U3r9B7O4XX+Rb1Itm9OZ2b0RkTs10bICOxA==", + "license": "MIT", + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/fetch-event-stream": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/fetch-event-stream/-/fetch-event-stream-0.1.5.tgz", + "integrity": "sha512-V1PWovkspxQfssq/NnxoEyQo1DV+MRK/laPuPblIZmSjMN8P5u46OhlFQznSr9p/t0Sp8Uc6SbM3yCMfr0KU8g==", + "license": "MIT" + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "license": "ISC", + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/graphql": { + "version": "16.10.0", + "resolved": "https://registry.npmjs.org/graphql/-/graphql-16.10.0.tgz", + "integrity": "sha512-AjqGKbDGUFRKIRCP9tCKiIGHyriz2oHEbPIbEtcSLSs4YjReZOIPQQWek4+6hjw62H9QShXHyaGivGiYVLeYFQ==", + "license": "MIT", + "engines": { + "node": "^12.22.0 || ^14.16.0 || ^16.0.0 || >=17.0.0" + } + }, + "node_modules/headers-polyfill": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/headers-polyfill/-/headers-polyfill-4.0.3.tgz", + "integrity": "sha512-IScLbePpkvO846sIwOtOTDjutRMWdXdJmXdMvk6gCBHxFO8d+QKOQedyZSxFTTFYRSmlgSTDtXqqq4pcenBXLQ==", + "license": "MIT" + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-node-process": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/is-node-process/-/is-node-process-1.2.0.tgz", + "integrity": "sha512-Vg4o6/fqPxIjtxgUH5QLJhwZ7gW5diGCVlXpuUfELC62CuxM1iHcRe51f2W1FDy04Ai4KJkagKjx3XaqyfRKXw==", + "license": "MIT" + }, + "node_modules/msw": { + "version": "2.7.3", + "resolved": "https://registry.npmjs.org/msw/-/msw-2.7.3.tgz", + "integrity": "sha512-+mycXv8l2fEAjFZ5sjrtjJDmm2ceKGjrNbBr1durRg6VkU9fNUE/gsmQ51hWbHqs+l35W1iM+ZsmOD9Fd6lspw==", + "hasInstallScript": true, + "license": "MIT", + "dependencies": { + "@bundled-es-modules/cookie": "^2.0.1", + "@bundled-es-modules/statuses": "^1.0.1", + "@bundled-es-modules/tough-cookie": "^0.1.6", + "@inquirer/confirm": "^5.0.0", + "@mswjs/interceptors": "^0.37.0", + "@open-draft/deferred-promise": "^2.2.0", + "@open-draft/until": "^2.1.0", + "@types/cookie": "^0.6.0", + "@types/statuses": "^2.0.4", + "graphql": "^16.8.1", + "headers-polyfill": "^4.0.2", + "is-node-process": "^1.2.0", + "outvariant": "^1.4.3", + "path-to-regexp": "^6.3.0", + "picocolors": "^1.1.1", + "strict-event-emitter": "^0.5.1", + "type-fest": "^4.26.1", + "yargs": "^17.7.2" + }, + "bin": { + "msw": "cli/index.js" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/mswjs" + }, + "peerDependencies": { + "typescript": ">= 4.8.x" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/mute-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-2.0.0.tgz", + "integrity": "sha512-WWdIxpyjEn+FhQJQQv9aQAYlHoNVdzIzUySNV1gHUPDSdZJ3yZn7pAAbQcV7B56Mvu881q9FZV+0Vx2xC44VWA==", + "license": "ISC", + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/node-gyp-build": { + "version": "4.8.4", + "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.8.4.tgz", + "integrity": "sha512-LA4ZjwlnUblHVgq0oBF3Jl/6h/Nvs5fzBLwdEF4nuxnFdsfajde4WfxtJr3CaiH+F6ewcIB/q4jQ4UzPyid+CQ==", + "license": "MIT", + "bin": { + "node-gyp-build": "bin.js", + "node-gyp-build-optional": "optional.js", + "node-gyp-build-test": "build-test.js" + } + }, + "node_modules/outvariant": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/outvariant/-/outvariant-1.4.3.tgz", + "integrity": "sha512-+Sl2UErvtsoajRDKCE5/dBz4DIvHXQQnAxtQTF04OJxY0+DyZXSo5P5Bb7XYWOh81syohlYL24hbDwxedPUJCA==", + "license": "MIT" + }, + "node_modules/path-to-regexp": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-6.3.0.tgz", + "integrity": "sha512-Yhpw4T9C6hPpgPeA28us07OJeqZ5EzQTkbfwuhsUg0c237RomFoETJgmp2sa3F/41gfLE6G5cqcYwznmeEeOlQ==", + "license": "MIT" + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "license": "ISC" + }, + "node_modules/psl": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.15.0.tgz", + "integrity": "sha512-JZd3gMVBAVQkSs6HdNZo9Sdo0LNcQeMNP3CozBJb3JYC/QUYZTnKxP+f8oWRX4rHP5EurWxqAHTSwUCjlNKa1w==", + "license": "MIT", + "dependencies": { + "punycode": "^2.3.1" + }, + "funding": { + "url": "https://github.com/sponsors/lupomontero" + } + }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/querystringify": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz", + "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==", + "license": "MIT" + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/requires-port": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", + "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==", + "license": "MIT" + }, + "node_modules/semiver": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/semiver/-/semiver-1.1.0.tgz", + "integrity": "sha512-QNI2ChmuioGC1/xjyYwyZYADILWyW6AmS1UH6gDj/SFUUUS4MBAWs/7mxnkRPc/F4iHezDP+O8t0dO8WHiEOdg==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "license": "ISC", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/strict-event-emitter": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/strict-event-emitter/-/strict-event-emitter-0.5.1.tgz", + "integrity": "sha512-vMgjE/GGEPEFnhFub6pa4FmJBRBVOLpIII2hvCZ8Kzb7K0hlHo7mQv6xYrBvCL2LtAIBwFUK8wvuJgTVSQ5MFQ==", + "license": "MIT" + }, + "node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/textlinestream": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/textlinestream/-/textlinestream-1.1.1.tgz", + "integrity": "sha512-iBHbi7BQxrFmwZUQJsT0SjNzlLLsXhvW/kg7EyOMVMBIrlnj/qYofwo1LVLZi+3GbUEo96Iu2eqToI2+lZoAEQ==", + "license": "MIT" + }, + "node_modules/tough-cookie": { + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.4.tgz", + "integrity": "sha512-Loo5UUvLD9ScZ6jh8beX1T6sO1w2/MpCRpEP7V280GKMVUQ0Jzar2U3UJPsrdbziLEMMhu3Ujnq//rhiFuIeag==", + "license": "BSD-3-Clause", + "dependencies": { + "psl": "^1.1.33", + "punycode": "^2.1.1", + "universalify": "^0.2.0", + "url-parse": "^1.5.3" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/type-fest": { + "version": "4.39.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.39.1.tgz", + "integrity": "sha512-uW9qzd66uyHYxwyVBYiwS4Oi0qZyUqwjU+Oevr6ZogYiXt99EOYtwvzMSLw1c3lYo2HzJsep/NB23iEVEgjG/w==", + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/typescript": { + "version": "5.8.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.3.tgz", + "integrity": "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==", + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/universalify": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.2.0.tgz", + "integrity": "sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==", + "license": "MIT", + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/url-parse": { + "version": "1.5.10", + "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz", + "integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==", + "license": "MIT", + "dependencies": { + "querystringify": "^2.1.1", + "requires-port": "^1.0.0" + } + }, + "node_modules/wrap-ansi": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", + "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/ws": { + "version": "8.18.1", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.1.tgz", + "integrity": "sha512-RKW2aJZMXeMxVpnZ6bck+RswznaxmzdULiBr6KY7XkTnW8uvt0iT9H5DkHUChXrc+uurzwa0rVI16n/Xzjdz1w==", + "license": "MIT", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "license": "ISC", + "engines": { + "node": ">=10" + } + }, + "node_modules/yargs": { + "version": "17.7.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", + "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", + "license": "MIT", + "dependencies": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/yoctocolors-cjs": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/yoctocolors-cjs/-/yoctocolors-cjs-2.1.2.tgz", + "integrity": "sha512-cYVsTjKl8b+FrnidjibDWskAv7UKOfcwaVZdp/it9n1s9fU3IkgDbhdIRKCW4JDsAlECJY0ytoVPT3sK6kideA==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + } + } +} diff --git a/node_modules/@bundled-es-modules/cookie/README.md b/node_modules/@bundled-es-modules/cookie/README.md new file mode 100644 index 0000000000000000000000000000000000000000..ce9e73f92a90fbb2257a4bb88ab0d833ba418644 --- /dev/null +++ b/node_modules/@bundled-es-modules/cookie/README.md @@ -0,0 +1,18 @@ +# cookie + +This is a mirror of [cookie](https://www.npmjs.com/package/cookie), bundled and exposed as ES module. + +## Install + +``` +npm install @bundled-es-modules/cookie +``` + +## Use + +```html + +``` \ No newline at end of file diff --git a/node_modules/@bundled-es-modules/cookie/index-cjs.cjs b/node_modules/@bundled-es-modules/cookie/index-cjs.cjs new file mode 100644 index 0000000000000000000000000000000000000000..2faa2bc9d1d061bc9f9b93052e0145fc3aec16b9 --- /dev/null +++ b/node_modules/@bundled-es-modules/cookie/index-cjs.cjs @@ -0,0 +1,2 @@ +const cookie = require('cookie'); +module.exports = cookie; \ No newline at end of file diff --git a/node_modules/@bundled-es-modules/cookie/index-esm.js b/node_modules/@bundled-es-modules/cookie/index-esm.js new file mode 100644 index 0000000000000000000000000000000000000000..761dadcdc04614f8fa846538a84fa361ee60cea9 --- /dev/null +++ b/node_modules/@bundled-es-modules/cookie/index-esm.js @@ -0,0 +1,208 @@ +var __create = Object.create; +var __defProp = Object.defineProperty; +var __getOwnPropDesc = Object.getOwnPropertyDescriptor; +var __getOwnPropNames = Object.getOwnPropertyNames; +var __getProtoOf = Object.getPrototypeOf; +var __hasOwnProp = Object.prototype.hasOwnProperty; +var __commonJS = (cb, mod) => function __require() { + return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports; +}; +var __copyProps = (to, from, except, desc) => { + if (from && typeof from === "object" || typeof from === "function") { + for (let key of __getOwnPropNames(from)) + if (!__hasOwnProp.call(to, key) && key !== except) + __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); + } + return to; +}; +var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( + // If the importer is in node compatibility mode or this is not an ESM + // file that has been converted to a CommonJS file using a Babel- + // compatible transform (i.e. "__esModule" has not been set), then set + // "default" to the CommonJS "module.exports" for node compatibility. + isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, + mod +)); + +// node_modules/cookie/index.js +var require_cookie = __commonJS({ + "node_modules/cookie/index.js"(exports) { + "use strict"; + exports.parse = parse; + exports.serialize = serialize; + var __toString = Object.prototype.toString; + var __hasOwnProperty = Object.prototype.hasOwnProperty; + var cookieNameRegExp = /^[!#$%&'*+\-.^_`|~0-9A-Za-z]+$/; + var cookieValueRegExp = /^("?)[\u0021\u0023-\u002B\u002D-\u003A\u003C-\u005B\u005D-\u007E]*\1$/; + var domainValueRegExp = /^([.]?[a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?)([.][a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?)*$/i; + var pathValueRegExp = /^[\u0020-\u003A\u003D-\u007E]*$/; + function parse(str, opt) { + if (typeof str !== "string") { + throw new TypeError("argument str must be a string"); + } + var obj = {}; + var len = str.length; + if (len < 2) return obj; + var dec = opt && opt.decode || decode; + var index = 0; + var eqIdx = 0; + var endIdx = 0; + do { + eqIdx = str.indexOf("=", index); + if (eqIdx === -1) break; + endIdx = str.indexOf(";", index); + if (endIdx === -1) { + endIdx = len; + } else if (eqIdx > endIdx) { + index = str.lastIndexOf(";", eqIdx - 1) + 1; + continue; + } + var keyStartIdx = startIndex(str, index, eqIdx); + var keyEndIdx = endIndex(str, eqIdx, keyStartIdx); + var key = str.slice(keyStartIdx, keyEndIdx); + if (!__hasOwnProperty.call(obj, key)) { + var valStartIdx = startIndex(str, eqIdx + 1, endIdx); + var valEndIdx = endIndex(str, endIdx, valStartIdx); + if (str.charCodeAt(valStartIdx) === 34 && str.charCodeAt(valEndIdx - 1) === 34) { + valStartIdx++; + valEndIdx--; + } + var val = str.slice(valStartIdx, valEndIdx); + obj[key] = tryDecode(val, dec); + } + index = endIdx + 1; + } while (index < len); + return obj; + } + function startIndex(str, index, max) { + do { + var code = str.charCodeAt(index); + if (code !== 32 && code !== 9) return index; + } while (++index < max); + return max; + } + function endIndex(str, index, min) { + while (index > min) { + var code = str.charCodeAt(--index); + if (code !== 32 && code !== 9) return index + 1; + } + return min; + } + function serialize(name, val, opt) { + var enc = opt && opt.encode || encodeURIComponent; + if (typeof enc !== "function") { + throw new TypeError("option encode is invalid"); + } + if (!cookieNameRegExp.test(name)) { + throw new TypeError("argument name is invalid"); + } + var value = enc(val); + if (!cookieValueRegExp.test(value)) { + throw new TypeError("argument val is invalid"); + } + var str = name + "=" + value; + if (!opt) return str; + if (null != opt.maxAge) { + var maxAge = Math.floor(opt.maxAge); + if (!isFinite(maxAge)) { + throw new TypeError("option maxAge is invalid"); + } + str += "; Max-Age=" + maxAge; + } + if (opt.domain) { + if (!domainValueRegExp.test(opt.domain)) { + throw new TypeError("option domain is invalid"); + } + str += "; Domain=" + opt.domain; + } + if (opt.path) { + if (!pathValueRegExp.test(opt.path)) { + throw new TypeError("option path is invalid"); + } + str += "; Path=" + opt.path; + } + if (opt.expires) { + var expires = opt.expires; + if (!isDate(expires) || isNaN(expires.valueOf())) { + throw new TypeError("option expires is invalid"); + } + str += "; Expires=" + expires.toUTCString(); + } + if (opt.httpOnly) { + str += "; HttpOnly"; + } + if (opt.secure) { + str += "; Secure"; + } + if (opt.partitioned) { + str += "; Partitioned"; + } + if (opt.priority) { + var priority = typeof opt.priority === "string" ? opt.priority.toLowerCase() : opt.priority; + switch (priority) { + case "low": + str += "; Priority=Low"; + break; + case "medium": + str += "; Priority=Medium"; + break; + case "high": + str += "; Priority=High"; + break; + default: + throw new TypeError("option priority is invalid"); + } + } + if (opt.sameSite) { + var sameSite = typeof opt.sameSite === "string" ? opt.sameSite.toLowerCase() : opt.sameSite; + switch (sameSite) { + case true: + str += "; SameSite=Strict"; + break; + case "lax": + str += "; SameSite=Lax"; + break; + case "strict": + str += "; SameSite=Strict"; + break; + case "none": + str += "; SameSite=None"; + break; + default: + throw new TypeError("option sameSite is invalid"); + } + } + return str; + } + function decode(str) { + return str.indexOf("%") !== -1 ? decodeURIComponent(str) : str; + } + function isDate(val) { + return __toString.call(val) === "[object Date]"; + } + function tryDecode(str, decode2) { + try { + return decode2(str); + } catch (e) { + return str; + } + } + } +}); + +// source.js +var import_cookie = __toESM(require_cookie(), 1); +var source_default = import_cookie.default; +export { + source_default as default +}; +/*! Bundled license information: + +cookie/index.js: + (*! + * cookie + * Copyright(c) 2012-2014 Roman Shtylman + * Copyright(c) 2015 Douglas Christopher Wilson + * MIT Licensed + *) +*/ diff --git a/node_modules/@bundled-es-modules/cookie/package.json b/node_modules/@bundled-es-modules/cookie/package.json new file mode 100644 index 0000000000000000000000000000000000000000..52deeea0b3a25106c5e3b4ee3166cc3e0f5b380e --- /dev/null +++ b/node_modules/@bundled-es-modules/cookie/package.json @@ -0,0 +1,34 @@ +{ + "name": "@bundled-es-modules/cookie", + "version": "2.0.1", + "description": "mirror of cookie, bundled and exposed as ES module", + "author": "Pascal Schilp ", + "main": "index-esm.js", + "type": "module", + "repository": { + "type": "git", + "url": "https://github.com/bundled-es-modules/cookie" + }, + "exports": { + ".": { + "import": "./index-esm.js", + "require": "./index-cjs.cjs" + } + }, + "scripts": { + "dev": "node --watch dev.js", + "build": "esbuild source.js --bundle --format=esm --outfile=index-esm.js" + }, + "keywords": [], + "files": [ + "index-esm.js", + "index-cjs.cjs" + ], + "license": "ISC", + "dependencies": { + "cookie": "^0.7.2" + }, + "devDependencies": { + "esbuild": "^0.24.0" + } +} diff --git a/node_modules/@bundled-es-modules/statuses/README.md b/node_modules/@bundled-es-modules/statuses/README.md new file mode 100644 index 0000000000000000000000000000000000000000..dac56919fc8f94b8e6df2918da9b3b65dd981c30 --- /dev/null +++ b/node_modules/@bundled-es-modules/statuses/README.md @@ -0,0 +1,17 @@ +# statuses + +This is a mirror of [statuses](https://www.npmjs.com/package/statuses), bundled and exposed as ES module. + +## Install + +``` +npm install @bundled-es-modules/statuses +``` + +## Use + +```html + +``` \ No newline at end of file diff --git a/node_modules/@bundled-es-modules/statuses/index-cjs.cjs b/node_modules/@bundled-es-modules/statuses/index-cjs.cjs new file mode 100644 index 0000000000000000000000000000000000000000..274452e87289edc1f2dfb43638ded397893e7d6f --- /dev/null +++ b/node_modules/@bundled-es-modules/statuses/index-cjs.cjs @@ -0,0 +1,2 @@ +const status = require('statuses'); +module.exports = status; \ No newline at end of file diff --git a/node_modules/@bundled-es-modules/statuses/index-esm.js b/node_modules/@bundled-es-modules/statuses/index-esm.js new file mode 100644 index 0000000000000000000000000000000000000000..872044aeb0872b7e46105f21ec32f1cd76521ede --- /dev/null +++ b/node_modules/@bundled-es-modules/statuses/index-esm.js @@ -0,0 +1,184 @@ +var __create = Object.create; +var __defProp = Object.defineProperty; +var __getOwnPropDesc = Object.getOwnPropertyDescriptor; +var __getOwnPropNames = Object.getOwnPropertyNames; +var __getProtoOf = Object.getPrototypeOf; +var __hasOwnProp = Object.prototype.hasOwnProperty; +var __commonJS = (cb, mod) => function __require() { + return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports; +}; +var __copyProps = (to, from, except, desc) => { + if (from && typeof from === "object" || typeof from === "function") { + for (let key of __getOwnPropNames(from)) + if (!__hasOwnProp.call(to, key) && key !== except) + __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); + } + return to; +}; +var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( + // If the importer is in node compatibility mode or this is not an ESM + // file that has been converted to a CommonJS file using a Babel- + // compatible transform (i.e. "__esModule" has not been set), then set + // "default" to the CommonJS "module.exports" for node compatibility. + isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, + mod +)); + +// node_modules/statuses/codes.json +var require_codes = __commonJS({ + "node_modules/statuses/codes.json"(exports, module) { + module.exports = { + "100": "Continue", + "101": "Switching Protocols", + "102": "Processing", + "103": "Early Hints", + "200": "OK", + "201": "Created", + "202": "Accepted", + "203": "Non-Authoritative Information", + "204": "No Content", + "205": "Reset Content", + "206": "Partial Content", + "207": "Multi-Status", + "208": "Already Reported", + "226": "IM Used", + "300": "Multiple Choices", + "301": "Moved Permanently", + "302": "Found", + "303": "See Other", + "304": "Not Modified", + "305": "Use Proxy", + "307": "Temporary Redirect", + "308": "Permanent Redirect", + "400": "Bad Request", + "401": "Unauthorized", + "402": "Payment Required", + "403": "Forbidden", + "404": "Not Found", + "405": "Method Not Allowed", + "406": "Not Acceptable", + "407": "Proxy Authentication Required", + "408": "Request Timeout", + "409": "Conflict", + "410": "Gone", + "411": "Length Required", + "412": "Precondition Failed", + "413": "Payload Too Large", + "414": "URI Too Long", + "415": "Unsupported Media Type", + "416": "Range Not Satisfiable", + "417": "Expectation Failed", + "418": "I'm a Teapot", + "421": "Misdirected Request", + "422": "Unprocessable Entity", + "423": "Locked", + "424": "Failed Dependency", + "425": "Too Early", + "426": "Upgrade Required", + "428": "Precondition Required", + "429": "Too Many Requests", + "431": "Request Header Fields Too Large", + "451": "Unavailable For Legal Reasons", + "500": "Internal Server Error", + "501": "Not Implemented", + "502": "Bad Gateway", + "503": "Service Unavailable", + "504": "Gateway Timeout", + "505": "HTTP Version Not Supported", + "506": "Variant Also Negotiates", + "507": "Insufficient Storage", + "508": "Loop Detected", + "509": "Bandwidth Limit Exceeded", + "510": "Not Extended", + "511": "Network Authentication Required" + }; + } +}); + +// node_modules/statuses/index.js +var require_statuses = __commonJS({ + "node_modules/statuses/index.js"(exports, module) { + "use strict"; + var codes = require_codes(); + module.exports = status2; + status2.message = codes; + status2.code = createMessageToStatusCodeMap(codes); + status2.codes = createStatusCodeList(codes); + status2.redirect = { + 300: true, + 301: true, + 302: true, + 303: true, + 305: true, + 307: true, + 308: true + }; + status2.empty = { + 204: true, + 205: true, + 304: true + }; + status2.retry = { + 502: true, + 503: true, + 504: true + }; + function createMessageToStatusCodeMap(codes2) { + var map = {}; + Object.keys(codes2).forEach(function forEachCode(code) { + var message = codes2[code]; + var status3 = Number(code); + map[message.toLowerCase()] = status3; + }); + return map; + } + function createStatusCodeList(codes2) { + return Object.keys(codes2).map(function mapCode(code) { + return Number(code); + }); + } + function getStatusCode(message) { + var msg = message.toLowerCase(); + if (!Object.prototype.hasOwnProperty.call(status2.code, msg)) { + throw new Error('invalid status message: "' + message + '"'); + } + return status2.code[msg]; + } + function getStatusMessage(code) { + if (!Object.prototype.hasOwnProperty.call(status2.message, code)) { + throw new Error("invalid status code: " + code); + } + return status2.message[code]; + } + function status2(code) { + if (typeof code === "number") { + return getStatusMessage(code); + } + if (typeof code !== "string") { + throw new TypeError("code must be a number or string"); + } + var n = parseInt(code, 10); + if (!isNaN(n)) { + return getStatusMessage(n); + } + return getStatusCode(code); + } + } +}); + +// source.js +var import_statuses = __toESM(require_statuses(), 1); +var source_default = import_statuses.default; +export { + source_default as default +}; +/*! Bundled license information: + +statuses/index.js: + (*! + * statuses + * Copyright(c) 2014 Jonathan Ong + * Copyright(c) 2016 Douglas Christopher Wilson + * MIT Licensed + *) +*/ diff --git a/node_modules/@bundled-es-modules/statuses/package.json b/node_modules/@bundled-es-modules/statuses/package.json new file mode 100644 index 0000000000000000000000000000000000000000..d39bd67d652b4641548050bad2ae3d6400693f56 --- /dev/null +++ b/node_modules/@bundled-es-modules/statuses/package.json @@ -0,0 +1,30 @@ +{ + "name": "@bundled-es-modules/statuses", + "version": "1.0.1", + "description": "mirror of statuses, bundled and exposed as ES module", + "author": "Pascal Schilp ", + "main": "index-esm.js", + "type": "module", + "exports": { + ".": { + "import": "./index-esm.js", + "require": "./index-cjs.cjs" + } + }, + "scripts": { + "dev": "node dev.js", + "build": "esbuild source.js --bundle --format=esm --outfile=index-esm.js" + }, + "keywords": [], + "files": [ + "index-esm.js", + "index-cjs.cjs" + ], + "license": "ISC", + "dependencies": { + "statuses": "^2.0.1" + }, + "devDependencies": { + "esbuild": "^0.17.17" + } +} diff --git a/node_modules/@bundled-es-modules/tough-cookie/index-cjs.cjs b/node_modules/@bundled-es-modules/tough-cookie/index-cjs.cjs new file mode 100644 index 0000000000000000000000000000000000000000..537c2a5401d95c0708acdcde61767f9e3ff9536a --- /dev/null +++ b/node_modules/@bundled-es-modules/tough-cookie/index-cjs.cjs @@ -0,0 +1,2 @@ +const toughCookie = require('tough-cookie') +module.exports = toughCookie diff --git a/node_modules/@bundled-es-modules/tough-cookie/index-esm.js b/node_modules/@bundled-es-modules/tough-cookie/index-esm.js new file mode 100644 index 0000000000000000000000000000000000000000..b211d70dac7b3a440008bc4c540ad7c6d2fddde5 --- /dev/null +++ b/node_modules/@bundled-es-modules/tough-cookie/index-esm.js @@ -0,0 +1,12042 @@ +var __create = Object.create; +var __defProp = Object.defineProperty; +var __getOwnPropDesc = Object.getOwnPropertyDescriptor; +var __getOwnPropNames = Object.getOwnPropertyNames; +var __getProtoOf = Object.getPrototypeOf; +var __hasOwnProp = Object.prototype.hasOwnProperty; +var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, { + get: (a, b) => (typeof require !== "undefined" ? require : a)[b] +}) : x)(function(x) { + if (typeof require !== "undefined") return require.apply(this, arguments); + throw Error('Dynamic require of "' + x + '" is not supported'); +}); +var __commonJS = (cb, mod) => function __require2() { + return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports; +}; +var __copyProps = (to, from, except, desc) => { + if (from && typeof from === "object" || typeof from === "function") { + for (let key of __getOwnPropNames(from)) + if (!__hasOwnProp.call(to, key) && key !== except) + __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); + } + return to; +}; +var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( + // If the importer is in node compatibility mode or this is not an ESM + // file that has been converted to a CommonJS file using a Babel- + // compatible transform (i.e. "__esModule" has not been set), then set + // "default" to the CommonJS "module.exports" for node compatibility. + isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, + mod +)); + +// node_modules/punycode/punycode.js +var require_punycode = __commonJS({ + "node_modules/punycode/punycode.js"(exports, module) { + "use strict"; + var maxInt = 2147483647; + var base = 36; + var tMin = 1; + var tMax = 26; + var skew = 38; + var damp = 700; + var initialBias = 72; + var initialN = 128; + var delimiter = "-"; + var regexPunycode = /^xn--/; + var regexNonASCII = /[^\0-\x7F]/; + var regexSeparators = /[\x2E\u3002\uFF0E\uFF61]/g; + var errors = { + "overflow": "Overflow: input needs wider integers to process", + "not-basic": "Illegal input >= 0x80 (not a basic code point)", + "invalid-input": "Invalid input" + }; + var baseMinusTMin = base - tMin; + var floor = Math.floor; + var stringFromCharCode = String.fromCharCode; + function error(type) { + throw new RangeError(errors[type]); + } + function map(array, callback) { + const result = []; + let length = array.length; + while (length--) { + result[length] = callback(array[length]); + } + return result; + } + function mapDomain(domain, callback) { + const parts = domain.split("@"); + let result = ""; + if (parts.length > 1) { + result = parts[0] + "@"; + domain = parts[1]; + } + domain = domain.replace(regexSeparators, "."); + const labels = domain.split("."); + const encoded = map(labels, callback).join("."); + return result + encoded; + } + function ucs2decode(string) { + const output = []; + let counter = 0; + const length = string.length; + while (counter < length) { + const value = string.charCodeAt(counter++); + if (value >= 55296 && value <= 56319 && counter < length) { + const extra = string.charCodeAt(counter++); + if ((extra & 64512) == 56320) { + output.push(((value & 1023) << 10) + (extra & 1023) + 65536); + } else { + output.push(value); + counter--; + } + } else { + output.push(value); + } + } + return output; + } + var ucs2encode = (codePoints) => String.fromCodePoint(...codePoints); + var basicToDigit = function(codePoint) { + if (codePoint >= 48 && codePoint < 58) { + return 26 + (codePoint - 48); + } + if (codePoint >= 65 && codePoint < 91) { + return codePoint - 65; + } + if (codePoint >= 97 && codePoint < 123) { + return codePoint - 97; + } + return base; + }; + var digitToBasic = function(digit, flag) { + return digit + 22 + 75 * (digit < 26) - ((flag != 0) << 5); + }; + var adapt = function(delta, numPoints, firstTime) { + let k = 0; + delta = firstTime ? floor(delta / damp) : delta >> 1; + delta += floor(delta / numPoints); + for (; delta > baseMinusTMin * tMax >> 1; k += base) { + delta = floor(delta / baseMinusTMin); + } + return floor(k + (baseMinusTMin + 1) * delta / (delta + skew)); + }; + var decode = function(input) { + const output = []; + const inputLength = input.length; + let i = 0; + let n = initialN; + let bias = initialBias; + let basic = input.lastIndexOf(delimiter); + if (basic < 0) { + basic = 0; + } + for (let j = 0; j < basic; ++j) { + if (input.charCodeAt(j) >= 128) { + error("not-basic"); + } + output.push(input.charCodeAt(j)); + } + for (let index = basic > 0 ? basic + 1 : 0; index < inputLength; ) { + const oldi = i; + for (let w = 1, k = base; ; k += base) { + if (index >= inputLength) { + error("invalid-input"); + } + const digit = basicToDigit(input.charCodeAt(index++)); + if (digit >= base) { + error("invalid-input"); + } + if (digit > floor((maxInt - i) / w)) { + error("overflow"); + } + i += digit * w; + const t = k <= bias ? tMin : k >= bias + tMax ? tMax : k - bias; + if (digit < t) { + break; + } + const baseMinusT = base - t; + if (w > floor(maxInt / baseMinusT)) { + error("overflow"); + } + w *= baseMinusT; + } + const out = output.length + 1; + bias = adapt(i - oldi, out, oldi == 0); + if (floor(i / out) > maxInt - n) { + error("overflow"); + } + n += floor(i / out); + i %= out; + output.splice(i++, 0, n); + } + return String.fromCodePoint(...output); + }; + var encode = function(input) { + const output = []; + input = ucs2decode(input); + const inputLength = input.length; + let n = initialN; + let delta = 0; + let bias = initialBias; + for (const currentValue of input) { + if (currentValue < 128) { + output.push(stringFromCharCode(currentValue)); + } + } + const basicLength = output.length; + let handledCPCount = basicLength; + if (basicLength) { + output.push(delimiter); + } + while (handledCPCount < inputLength) { + let m = maxInt; + for (const currentValue of input) { + if (currentValue >= n && currentValue < m) { + m = currentValue; + } + } + const handledCPCountPlusOne = handledCPCount + 1; + if (m - n > floor((maxInt - delta) / handledCPCountPlusOne)) { + error("overflow"); + } + delta += (m - n) * handledCPCountPlusOne; + n = m; + for (const currentValue of input) { + if (currentValue < n && ++delta > maxInt) { + error("overflow"); + } + if (currentValue === n) { + let q = delta; + for (let k = base; ; k += base) { + const t = k <= bias ? tMin : k >= bias + tMax ? tMax : k - bias; + if (q < t) { + break; + } + const qMinusT = q - t; + const baseMinusT = base - t; + output.push( + stringFromCharCode(digitToBasic(t + qMinusT % baseMinusT, 0)) + ); + q = floor(qMinusT / baseMinusT); + } + output.push(stringFromCharCode(digitToBasic(q, 0))); + bias = adapt(delta, handledCPCountPlusOne, handledCPCount === basicLength); + delta = 0; + ++handledCPCount; + } + } + ++delta; + ++n; + } + return output.join(""); + }; + var toUnicode = function(input) { + return mapDomain(input, function(string) { + return regexPunycode.test(string) ? decode(string.slice(4).toLowerCase()) : string; + }); + }; + var toASCII = function(input) { + return mapDomain(input, function(string) { + return regexNonASCII.test(string) ? "xn--" + encode(string) : string; + }); + }; + var punycode = { + /** + * A string representing the current Punycode.js version number. + * @memberOf punycode + * @type String + */ + "version": "2.3.1", + /** + * An object of methods to convert from JavaScript's internal character + * representation (UCS-2) to Unicode code points, and back. + * @see + * @memberOf punycode + * @type Object + */ + "ucs2": { + "decode": ucs2decode, + "encode": ucs2encode + }, + "decode": decode, + "encode": encode, + "toASCII": toASCII, + "toUnicode": toUnicode + }; + module.exports = punycode; + } +}); + +// node_modules/requires-port/index.js +var require_requires_port = __commonJS({ + "node_modules/requires-port/index.js"(exports, module) { + "use strict"; + module.exports = function required(port, protocol) { + protocol = protocol.split(":")[0]; + port = +port; + if (!port) return false; + switch (protocol) { + case "http": + case "ws": + return port !== 80; + case "https": + case "wss": + return port !== 443; + case "ftp": + return port !== 21; + case "gopher": + return port !== 70; + case "file": + return false; + } + return port !== 0; + }; + } +}); + +// node_modules/querystringify/index.js +var require_querystringify = __commonJS({ + "node_modules/querystringify/index.js"(exports) { + "use strict"; + var has = Object.prototype.hasOwnProperty; + var undef; + function decode(input) { + try { + return decodeURIComponent(input.replace(/\+/g, " ")); + } catch (e) { + return null; + } + } + function encode(input) { + try { + return encodeURIComponent(input); + } catch (e) { + return null; + } + } + function querystring(query) { + var parser = /([^=?#&]+)=?([^&]*)/g, result = {}, part; + while (part = parser.exec(query)) { + var key = decode(part[1]), value = decode(part[2]); + if (key === null || value === null || key in result) continue; + result[key] = value; + } + return result; + } + function querystringify(obj, prefix) { + prefix = prefix || ""; + var pairs = [], value, key; + if ("string" !== typeof prefix) prefix = "?"; + for (key in obj) { + if (has.call(obj, key)) { + value = obj[key]; + if (!value && (value === null || value === undef || isNaN(value))) { + value = ""; + } + key = encode(key); + value = encode(value); + if (key === null || value === null) continue; + pairs.push(key + "=" + value); + } + } + return pairs.length ? prefix + pairs.join("&") : ""; + } + exports.stringify = querystringify; + exports.parse = querystring; + } +}); + +// node_modules/url-parse/index.js +var require_url_parse = __commonJS({ + "node_modules/url-parse/index.js"(exports, module) { + "use strict"; + var required = require_requires_port(); + var qs = require_querystringify(); + var controlOrWhitespace = /^[\x00-\x20\u00a0\u1680\u2000-\u200a\u2028\u2029\u202f\u205f\u3000\ufeff]+/; + var CRHTLF = /[\n\r\t]/g; + var slashes = /^[A-Za-z][A-Za-z0-9+-.]*:\/\//; + var port = /:\d+$/; + var protocolre = /^([a-z][a-z0-9.+-]*:)?(\/\/)?([\\/]+)?([\S\s]*)/i; + var windowsDriveLetter = /^[a-zA-Z]:/; + function trimLeft(str) { + return (str ? str : "").toString().replace(controlOrWhitespace, ""); + } + var rules = [ + ["#", "hash"], + // Extract from the back. + ["?", "query"], + // Extract from the back. + function sanitize(address, url) { + return isSpecial(url.protocol) ? address.replace(/\\/g, "/") : address; + }, + ["/", "pathname"], + // Extract from the back. + ["@", "auth", 1], + // Extract from the front. + [NaN, "host", void 0, 1, 1], + // Set left over value. + [/:(\d*)$/, "port", void 0, 1], + // RegExp the back. + [NaN, "hostname", void 0, 1, 1] + // Set left over. + ]; + var ignore = { hash: 1, query: 1 }; + function lolcation(loc) { + var globalVar; + if (typeof window !== "undefined") globalVar = window; + else if (typeof global !== "undefined") globalVar = global; + else if (typeof self !== "undefined") globalVar = self; + else globalVar = {}; + var location = globalVar.location || {}; + loc = loc || location; + var finaldestination = {}, type = typeof loc, key; + if ("blob:" === loc.protocol) { + finaldestination = new Url(unescape(loc.pathname), {}); + } else if ("string" === type) { + finaldestination = new Url(loc, {}); + for (key in ignore) delete finaldestination[key]; + } else if ("object" === type) { + for (key in loc) { + if (key in ignore) continue; + finaldestination[key] = loc[key]; + } + if (finaldestination.slashes === void 0) { + finaldestination.slashes = slashes.test(loc.href); + } + } + return finaldestination; + } + function isSpecial(scheme) { + return scheme === "file:" || scheme === "ftp:" || scheme === "http:" || scheme === "https:" || scheme === "ws:" || scheme === "wss:"; + } + function extractProtocol(address, location) { + address = trimLeft(address); + address = address.replace(CRHTLF, ""); + location = location || {}; + var match = protocolre.exec(address); + var protocol = match[1] ? match[1].toLowerCase() : ""; + var forwardSlashes = !!match[2]; + var otherSlashes = !!match[3]; + var slashesCount = 0; + var rest; + if (forwardSlashes) { + if (otherSlashes) { + rest = match[2] + match[3] + match[4]; + slashesCount = match[2].length + match[3].length; + } else { + rest = match[2] + match[4]; + slashesCount = match[2].length; + } + } else { + if (otherSlashes) { + rest = match[3] + match[4]; + slashesCount = match[3].length; + } else { + rest = match[4]; + } + } + if (protocol === "file:") { + if (slashesCount >= 2) { + rest = rest.slice(2); + } + } else if (isSpecial(protocol)) { + rest = match[4]; + } else if (protocol) { + if (forwardSlashes) { + rest = rest.slice(2); + } + } else if (slashesCount >= 2 && isSpecial(location.protocol)) { + rest = match[4]; + } + return { + protocol, + slashes: forwardSlashes || isSpecial(protocol), + slashesCount, + rest + }; + } + function resolve(relative, base) { + if (relative === "") return base; + var path = (base || "/").split("/").slice(0, -1).concat(relative.split("/")), i = path.length, last = path[i - 1], unshift = false, up = 0; + while (i--) { + if (path[i] === ".") { + path.splice(i, 1); + } else if (path[i] === "..") { + path.splice(i, 1); + up++; + } else if (up) { + if (i === 0) unshift = true; + path.splice(i, 1); + up--; + } + } + if (unshift) path.unshift(""); + if (last === "." || last === "..") path.push(""); + return path.join("/"); + } + function Url(address, location, parser) { + address = trimLeft(address); + address = address.replace(CRHTLF, ""); + if (!(this instanceof Url)) { + return new Url(address, location, parser); + } + var relative, extracted, parse, instruction, index, key, instructions = rules.slice(), type = typeof location, url = this, i = 0; + if ("object" !== type && "string" !== type) { + parser = location; + location = null; + } + if (parser && "function" !== typeof parser) parser = qs.parse; + location = lolcation(location); + extracted = extractProtocol(address || "", location); + relative = !extracted.protocol && !extracted.slashes; + url.slashes = extracted.slashes || relative && location.slashes; + url.protocol = extracted.protocol || location.protocol || ""; + address = extracted.rest; + if (extracted.protocol === "file:" && (extracted.slashesCount !== 2 || windowsDriveLetter.test(address)) || !extracted.slashes && (extracted.protocol || extracted.slashesCount < 2 || !isSpecial(url.protocol))) { + instructions[3] = [/(.*)/, "pathname"]; + } + for (; i < instructions.length; i++) { + instruction = instructions[i]; + if (typeof instruction === "function") { + address = instruction(address, url); + continue; + } + parse = instruction[0]; + key = instruction[1]; + if (parse !== parse) { + url[key] = address; + } else if ("string" === typeof parse) { + index = parse === "@" ? address.lastIndexOf(parse) : address.indexOf(parse); + if (~index) { + if ("number" === typeof instruction[2]) { + url[key] = address.slice(0, index); + address = address.slice(index + instruction[2]); + } else { + url[key] = address.slice(index); + address = address.slice(0, index); + } + } + } else if (index = parse.exec(address)) { + url[key] = index[1]; + address = address.slice(0, index.index); + } + url[key] = url[key] || (relative && instruction[3] ? location[key] || "" : ""); + if (instruction[4]) url[key] = url[key].toLowerCase(); + } + if (parser) url.query = parser(url.query); + if (relative && location.slashes && url.pathname.charAt(0) !== "/" && (url.pathname !== "" || location.pathname !== "")) { + url.pathname = resolve(url.pathname, location.pathname); + } + if (url.pathname.charAt(0) !== "/" && isSpecial(url.protocol)) { + url.pathname = "/" + url.pathname; + } + if (!required(url.port, url.protocol)) { + url.host = url.hostname; + url.port = ""; + } + url.username = url.password = ""; + if (url.auth) { + index = url.auth.indexOf(":"); + if (~index) { + url.username = url.auth.slice(0, index); + url.username = encodeURIComponent(decodeURIComponent(url.username)); + url.password = url.auth.slice(index + 1); + url.password = encodeURIComponent(decodeURIComponent(url.password)); + } else { + url.username = encodeURIComponent(decodeURIComponent(url.auth)); + } + url.auth = url.password ? url.username + ":" + url.password : url.username; + } + url.origin = url.protocol !== "file:" && isSpecial(url.protocol) && url.host ? url.protocol + "//" + url.host : "null"; + url.href = url.toString(); + } + function set(part, value, fn) { + var url = this; + switch (part) { + case "query": + if ("string" === typeof value && value.length) { + value = (fn || qs.parse)(value); + } + url[part] = value; + break; + case "port": + url[part] = value; + if (!required(value, url.protocol)) { + url.host = url.hostname; + url[part] = ""; + } else if (value) { + url.host = url.hostname + ":" + value; + } + break; + case "hostname": + url[part] = value; + if (url.port) value += ":" + url.port; + url.host = value; + break; + case "host": + url[part] = value; + if (port.test(value)) { + value = value.split(":"); + url.port = value.pop(); + url.hostname = value.join(":"); + } else { + url.hostname = value; + url.port = ""; + } + break; + case "protocol": + url.protocol = value.toLowerCase(); + url.slashes = !fn; + break; + case "pathname": + case "hash": + if (value) { + var char = part === "pathname" ? "/" : "#"; + url[part] = value.charAt(0) !== char ? char + value : value; + } else { + url[part] = value; + } + break; + case "username": + case "password": + url[part] = encodeURIComponent(value); + break; + case "auth": + var index = value.indexOf(":"); + if (~index) { + url.username = value.slice(0, index); + url.username = encodeURIComponent(decodeURIComponent(url.username)); + url.password = value.slice(index + 1); + url.password = encodeURIComponent(decodeURIComponent(url.password)); + } else { + url.username = encodeURIComponent(decodeURIComponent(value)); + } + } + for (var i = 0; i < rules.length; i++) { + var ins = rules[i]; + if (ins[4]) url[ins[1]] = url[ins[1]].toLowerCase(); + } + url.auth = url.password ? url.username + ":" + url.password : url.username; + url.origin = url.protocol !== "file:" && isSpecial(url.protocol) && url.host ? url.protocol + "//" + url.host : "null"; + url.href = url.toString(); + return url; + } + function toString(stringify) { + if (!stringify || "function" !== typeof stringify) stringify = qs.stringify; + var query, url = this, host = url.host, protocol = url.protocol; + if (protocol && protocol.charAt(protocol.length - 1) !== ":") protocol += ":"; + var result = protocol + (url.protocol && url.slashes || isSpecial(url.protocol) ? "//" : ""); + if (url.username) { + result += url.username; + if (url.password) result += ":" + url.password; + result += "@"; + } else if (url.password) { + result += ":" + url.password; + result += "@"; + } else if (url.protocol !== "file:" && isSpecial(url.protocol) && !host && url.pathname !== "/") { + result += "@"; + } + if (host[host.length - 1] === ":" || port.test(url.hostname) && !url.port) { + host += ":"; + } + result += host + url.pathname; + query = "object" === typeof url.query ? stringify(url.query) : url.query; + if (query) result += "?" !== query.charAt(0) ? "?" + query : query; + if (url.hash) result += url.hash; + return result; + } + Url.prototype = { set, toString }; + Url.extractProtocol = extractProtocol; + Url.location = lolcation; + Url.trimLeft = trimLeft; + Url.qs = qs; + module.exports = Url; + } +}); + +// node_modules/psl/data/rules.json +var require_rules = __commonJS({ + "node_modules/psl/data/rules.json"(exports, module) { + module.exports = [ + "ac", + "com.ac", + "edu.ac", + "gov.ac", + "net.ac", + "mil.ac", + "org.ac", + "ad", + "nom.ad", + "ae", + "co.ae", + "net.ae", + "org.ae", + "sch.ae", + "ac.ae", + "gov.ae", + "mil.ae", + "aero", + "accident-investigation.aero", + "accident-prevention.aero", + "aerobatic.aero", + "aeroclub.aero", + "aerodrome.aero", + "agents.aero", + "aircraft.aero", + "airline.aero", + "airport.aero", + "air-surveillance.aero", + "airtraffic.aero", + "air-traffic-control.aero", + "ambulance.aero", + "amusement.aero", + "association.aero", + "author.aero", + "ballooning.aero", + "broker.aero", + "caa.aero", + "cargo.aero", + "catering.aero", + "certification.aero", + "championship.aero", + "charter.aero", + "civilaviation.aero", + "club.aero", + "conference.aero", + "consultant.aero", + "consulting.aero", + "control.aero", + "council.aero", + "crew.aero", + "design.aero", + "dgca.aero", + "educator.aero", + "emergency.aero", + "engine.aero", + "engineer.aero", + "entertainment.aero", + "equipment.aero", + "exchange.aero", + "express.aero", + "federation.aero", + "flight.aero", + "fuel.aero", + "gliding.aero", + "government.aero", + "groundhandling.aero", + "group.aero", + "hanggliding.aero", + "homebuilt.aero", + "insurance.aero", + "journal.aero", + "journalist.aero", + "leasing.aero", + "logistics.aero", + "magazine.aero", + "maintenance.aero", + "media.aero", + "microlight.aero", + "modelling.aero", + "navigation.aero", + "parachuting.aero", + "paragliding.aero", + "passenger-association.aero", + "pilot.aero", + "press.aero", + "production.aero", + "recreation.aero", + "repbody.aero", + "res.aero", + "research.aero", + "rotorcraft.aero", + "safety.aero", + "scientist.aero", + "services.aero", + "show.aero", + "skydiving.aero", + "software.aero", + "student.aero", + "trader.aero", + "trading.aero", + "trainer.aero", + "union.aero", + "workinggroup.aero", + "works.aero", + "af", + "gov.af", + "com.af", + "org.af", + "net.af", + "edu.af", + "ag", + "com.ag", + "org.ag", + "net.ag", + "co.ag", + "nom.ag", + "ai", + "off.ai", + "com.ai", + "net.ai", + "org.ai", + "al", + "com.al", + "edu.al", + "gov.al", + "mil.al", + "net.al", + "org.al", + "am", + "co.am", + "com.am", + "commune.am", + "net.am", + "org.am", + "ao", + "ed.ao", + "gv.ao", + "og.ao", + "co.ao", + "pb.ao", + "it.ao", + "aq", + "ar", + "bet.ar", + "com.ar", + "coop.ar", + "edu.ar", + "gob.ar", + "gov.ar", + "int.ar", + "mil.ar", + "musica.ar", + "mutual.ar", + "net.ar", + "org.ar", + "senasa.ar", + "tur.ar", + "arpa", + "e164.arpa", + "in-addr.arpa", + "ip6.arpa", + "iris.arpa", + "uri.arpa", + "urn.arpa", + "as", + "gov.as", + "asia", + "at", + "ac.at", + "co.at", + "gv.at", + "or.at", + "sth.ac.at", + "au", + "com.au", + "net.au", + "org.au", + "edu.au", + "gov.au", + "asn.au", + "id.au", + "info.au", + "conf.au", + "oz.au", + "act.au", + "nsw.au", + "nt.au", + "qld.au", + "sa.au", + "tas.au", + "vic.au", + "wa.au", + "act.edu.au", + "catholic.edu.au", + "nsw.edu.au", + "nt.edu.au", + "qld.edu.au", + "sa.edu.au", + "tas.edu.au", + "vic.edu.au", + "wa.edu.au", + "qld.gov.au", + "sa.gov.au", + "tas.gov.au", + "vic.gov.au", + "wa.gov.au", + "schools.nsw.edu.au", + "aw", + "com.aw", + "ax", + "az", + "com.az", + "net.az", + "int.az", + "gov.az", + "org.az", + "edu.az", + "info.az", + "pp.az", + "mil.az", + "name.az", + "pro.az", + "biz.az", + "ba", + "com.ba", + "edu.ba", + "gov.ba", + "mil.ba", + "net.ba", + "org.ba", + "bb", + "biz.bb", + "co.bb", + "com.bb", + "edu.bb", + "gov.bb", + "info.bb", + "net.bb", + "org.bb", + "store.bb", + "tv.bb", + "*.bd", + "be", + "ac.be", + "bf", + "gov.bf", + "bg", + "a.bg", + "b.bg", + "c.bg", + "d.bg", + "e.bg", + "f.bg", + "g.bg", + "h.bg", + "i.bg", + "j.bg", + "k.bg", + "l.bg", + "m.bg", + "n.bg", + "o.bg", + "p.bg", + "q.bg", + "r.bg", + "s.bg", + "t.bg", + "u.bg", + "v.bg", + "w.bg", + "x.bg", + "y.bg", + "z.bg", + "0.bg", + "1.bg", + "2.bg", + "3.bg", + "4.bg", + "5.bg", + "6.bg", + "7.bg", + "8.bg", + "9.bg", + "bh", + "com.bh", + "edu.bh", + "net.bh", + "org.bh", + "gov.bh", + "bi", + "co.bi", + "com.bi", + "edu.bi", + "or.bi", + "org.bi", + "biz", + "bj", + "asso.bj", + "barreau.bj", + "gouv.bj", + "bm", + "com.bm", + "edu.bm", + "gov.bm", + "net.bm", + "org.bm", + "bn", + "com.bn", + "edu.bn", + "gov.bn", + "net.bn", + "org.bn", + "bo", + "com.bo", + "edu.bo", + "gob.bo", + "int.bo", + "org.bo", + "net.bo", + "mil.bo", + "tv.bo", + "web.bo", + "academia.bo", + "agro.bo", + "arte.bo", + "blog.bo", + "bolivia.bo", + "ciencia.bo", + "cooperativa.bo", + "democracia.bo", + "deporte.bo", + "ecologia.bo", + "economia.bo", + "empresa.bo", + "indigena.bo", + "industria.bo", + "info.bo", + "medicina.bo", + "movimiento.bo", + "musica.bo", + "natural.bo", + "nombre.bo", + "noticias.bo", + "patria.bo", + "politica.bo", + "profesional.bo", + "plurinacional.bo", + "pueblo.bo", + "revista.bo", + "salud.bo", + "tecnologia.bo", + "tksat.bo", + "transporte.bo", + "wiki.bo", + "br", + "9guacu.br", + "abc.br", + "adm.br", + "adv.br", + "agr.br", + "aju.br", + "am.br", + "anani.br", + "aparecida.br", + "app.br", + "arq.br", + "art.br", + "ato.br", + "b.br", + "barueri.br", + "belem.br", + "bhz.br", + "bib.br", + "bio.br", + "blog.br", + "bmd.br", + "boavista.br", + "bsb.br", + "campinagrande.br", + "campinas.br", + "caxias.br", + "cim.br", + "cng.br", + "cnt.br", + "com.br", + "contagem.br", + "coop.br", + "coz.br", + "cri.br", + "cuiaba.br", + "curitiba.br", + "def.br", + "des.br", + "det.br", + "dev.br", + "ecn.br", + "eco.br", + "edu.br", + "emp.br", + "enf.br", + "eng.br", + "esp.br", + "etc.br", + "eti.br", + "far.br", + "feira.br", + "flog.br", + "floripa.br", + "fm.br", + "fnd.br", + "fortal.br", + "fot.br", + "foz.br", + "fst.br", + "g12.br", + "geo.br", + "ggf.br", + "goiania.br", + "gov.br", + "ac.gov.br", + "al.gov.br", + "am.gov.br", + "ap.gov.br", + "ba.gov.br", + "ce.gov.br", + "df.gov.br", + "es.gov.br", + "go.gov.br", + "ma.gov.br", + "mg.gov.br", + "ms.gov.br", + "mt.gov.br", + "pa.gov.br", + "pb.gov.br", + "pe.gov.br", + "pi.gov.br", + "pr.gov.br", + "rj.gov.br", + "rn.gov.br", + "ro.gov.br", + "rr.gov.br", + "rs.gov.br", + "sc.gov.br", + "se.gov.br", + "sp.gov.br", + "to.gov.br", + "gru.br", + "imb.br", + "ind.br", + "inf.br", + "jab.br", + "jampa.br", + "jdf.br", + "joinville.br", + "jor.br", + "jus.br", + "leg.br", + "lel.br", + "log.br", + "londrina.br", + "macapa.br", + "maceio.br", + "manaus.br", + "maringa.br", + "mat.br", + "med.br", + "mil.br", + "morena.br", + "mp.br", + "mus.br", + "natal.br", + "net.br", + "niteroi.br", + "*.nom.br", + "not.br", + "ntr.br", + "odo.br", + "ong.br", + "org.br", + "osasco.br", + "palmas.br", + "poa.br", + "ppg.br", + "pro.br", + "psc.br", + "psi.br", + "pvh.br", + "qsl.br", + "radio.br", + "rec.br", + "recife.br", + "rep.br", + "ribeirao.br", + "rio.br", + "riobranco.br", + "riopreto.br", + "salvador.br", + "sampa.br", + "santamaria.br", + "santoandre.br", + "saobernardo.br", + "saogonca.br", + "seg.br", + "sjc.br", + "slg.br", + "slz.br", + "sorocaba.br", + "srv.br", + "taxi.br", + "tc.br", + "tec.br", + "teo.br", + "the.br", + "tmp.br", + "trd.br", + "tur.br", + "tv.br", + "udi.br", + "vet.br", + "vix.br", + "vlog.br", + "wiki.br", + "zlg.br", + "bs", + "com.bs", + "net.bs", + "org.bs", + "edu.bs", + "gov.bs", + "bt", + "com.bt", + "edu.bt", + "gov.bt", + "net.bt", + "org.bt", + "bv", + "bw", + "co.bw", + "org.bw", + "by", + "gov.by", + "mil.by", + "com.by", + "of.by", + "bz", + "com.bz", + "net.bz", + "org.bz", + "edu.bz", + "gov.bz", + "ca", + "ab.ca", + "bc.ca", + "mb.ca", + "nb.ca", + "nf.ca", + "nl.ca", + "ns.ca", + "nt.ca", + "nu.ca", + "on.ca", + "pe.ca", + "qc.ca", + "sk.ca", + "yk.ca", + "gc.ca", + "cat", + "cc", + "cd", + "gov.cd", + "cf", + "cg", + "ch", + "ci", + "org.ci", + "or.ci", + "com.ci", + "co.ci", + "edu.ci", + "ed.ci", + "ac.ci", + "net.ci", + "go.ci", + "asso.ci", + "a\xE9roport.ci", + "int.ci", + "presse.ci", + "md.ci", + "gouv.ci", + "*.ck", + "!www.ck", + "cl", + "co.cl", + "gob.cl", + "gov.cl", + "mil.cl", + "cm", + "co.cm", + "com.cm", + "gov.cm", + "net.cm", + "cn", + "ac.cn", + "com.cn", + "edu.cn", + "gov.cn", + "net.cn", + "org.cn", + "mil.cn", + "\u516C\u53F8.cn", + "\u7F51\u7EDC.cn", + "\u7DB2\u7D61.cn", + "ah.cn", + "bj.cn", + "cq.cn", + "fj.cn", + "gd.cn", + "gs.cn", + "gz.cn", + "gx.cn", + "ha.cn", + "hb.cn", + "he.cn", + "hi.cn", + "hl.cn", + "hn.cn", + "jl.cn", + "js.cn", + "jx.cn", + "ln.cn", + "nm.cn", + "nx.cn", + "qh.cn", + "sc.cn", + "sd.cn", + "sh.cn", + "sn.cn", + "sx.cn", + "tj.cn", + "xj.cn", + "xz.cn", + "yn.cn", + "zj.cn", + "hk.cn", + "mo.cn", + "tw.cn", + "co", + "arts.co", + "com.co", + "edu.co", + "firm.co", + "gov.co", + "info.co", + "int.co", + "mil.co", + "net.co", + "nom.co", + "org.co", + "rec.co", + "web.co", + "com", + "coop", + "cr", + "ac.cr", + "co.cr", + "ed.cr", + "fi.cr", + "go.cr", + "or.cr", + "sa.cr", + "cu", + "com.cu", + "edu.cu", + "org.cu", + "net.cu", + "gov.cu", + "inf.cu", + "cv", + "com.cv", + "edu.cv", + "int.cv", + "nome.cv", + "org.cv", + "cw", + "com.cw", + "edu.cw", + "net.cw", + "org.cw", + "cx", + "gov.cx", + "cy", + "ac.cy", + "biz.cy", + "com.cy", + "ekloges.cy", + "gov.cy", + "ltd.cy", + "mil.cy", + "net.cy", + "org.cy", + "press.cy", + "pro.cy", + "tm.cy", + "cz", + "de", + "dj", + "dk", + "dm", + "com.dm", + "net.dm", + "org.dm", + "edu.dm", + "gov.dm", + "do", + "art.do", + "com.do", + "edu.do", + "gob.do", + "gov.do", + "mil.do", + "net.do", + "org.do", + "sld.do", + "web.do", + "dz", + "art.dz", + "asso.dz", + "com.dz", + "edu.dz", + "gov.dz", + "org.dz", + "net.dz", + "pol.dz", + "soc.dz", + "tm.dz", + "ec", + "com.ec", + "info.ec", + "net.ec", + "fin.ec", + "k12.ec", + "med.ec", + "pro.ec", + "org.ec", + "edu.ec", + "gov.ec", + "gob.ec", + "mil.ec", + "edu", + "ee", + "edu.ee", + "gov.ee", + "riik.ee", + "lib.ee", + "med.ee", + "com.ee", + "pri.ee", + "aip.ee", + "org.ee", + "fie.ee", + "eg", + "com.eg", + "edu.eg", + "eun.eg", + "gov.eg", + "mil.eg", + "name.eg", + "net.eg", + "org.eg", + "sci.eg", + "*.er", + "es", + "com.es", + "nom.es", + "org.es", + "gob.es", + "edu.es", + "et", + "com.et", + "gov.et", + "org.et", + "edu.et", + "biz.et", + "name.et", + "info.et", + "net.et", + "eu", + "fi", + "aland.fi", + "fj", + "ac.fj", + "biz.fj", + "com.fj", + "gov.fj", + "info.fj", + "mil.fj", + "name.fj", + "net.fj", + "org.fj", + "pro.fj", + "*.fk", + "com.fm", + "edu.fm", + "net.fm", + "org.fm", + "fm", + "fo", + "fr", + "asso.fr", + "com.fr", + "gouv.fr", + "nom.fr", + "prd.fr", + "tm.fr", + "aeroport.fr", + "avocat.fr", + "avoues.fr", + "cci.fr", + "chambagri.fr", + "chirurgiens-dentistes.fr", + "experts-comptables.fr", + "geometre-expert.fr", + "greta.fr", + "huissier-justice.fr", + "medecin.fr", + "notaires.fr", + "pharmacien.fr", + "port.fr", + "veterinaire.fr", + "ga", + "gb", + "edu.gd", + "gov.gd", + "gd", + "ge", + "com.ge", + "edu.ge", + "gov.ge", + "org.ge", + "mil.ge", + "net.ge", + "pvt.ge", + "gf", + "gg", + "co.gg", + "net.gg", + "org.gg", + "gh", + "com.gh", + "edu.gh", + "gov.gh", + "org.gh", + "mil.gh", + "gi", + "com.gi", + "ltd.gi", + "gov.gi", + "mod.gi", + "edu.gi", + "org.gi", + "gl", + "co.gl", + "com.gl", + "edu.gl", + "net.gl", + "org.gl", + "gm", + "gn", + "ac.gn", + "com.gn", + "edu.gn", + "gov.gn", + "org.gn", + "net.gn", + "gov", + "gp", + "com.gp", + "net.gp", + "mobi.gp", + "edu.gp", + "org.gp", + "asso.gp", + "gq", + "gr", + "com.gr", + "edu.gr", + "net.gr", + "org.gr", + "gov.gr", + "gs", + "gt", + "com.gt", + "edu.gt", + "gob.gt", + "ind.gt", + "mil.gt", + "net.gt", + "org.gt", + "gu", + "com.gu", + "edu.gu", + "gov.gu", + "guam.gu", + "info.gu", + "net.gu", + "org.gu", + "web.gu", + "gw", + "gy", + "co.gy", + "com.gy", + "edu.gy", + "gov.gy", + "net.gy", + "org.gy", + "hk", + "com.hk", + "edu.hk", + "gov.hk", + "idv.hk", + "net.hk", + "org.hk", + "\u516C\u53F8.hk", + "\u6559\u80B2.hk", + "\u654E\u80B2.hk", + "\u653F\u5E9C.hk", + "\u500B\u4EBA.hk", + "\u4E2A\uFFFD\uFFFD.hk", + "\u7B87\u4EBA.hk", + "\u7DB2\u7EDC.hk", + "\u7F51\u7EDC.hk", + "\u7EC4\u7E54.hk", + "\u7DB2\u7D61.hk", + "\u7F51\u7D61.hk", + "\u7EC4\u7EC7.hk", + "\u7D44\u7E54.hk", + "\u7D44\u7EC7.hk", + "hm", + "hn", + "com.hn", + "edu.hn", + "org.hn", + "net.hn", + "mil.hn", + "gob.hn", + "hr", + "iz.hr", + "from.hr", + "name.hr", + "com.hr", + "ht", + "com.ht", + "shop.ht", + "firm.ht", + "info.ht", + "adult.ht", + "net.ht", + "pro.ht", + "org.ht", + "med.ht", + "art.ht", + "coop.ht", + "pol.ht", + "asso.ht", + "edu.ht", + "rel.ht", + "gouv.ht", + "perso.ht", + "hu", + "co.hu", + "info.hu", + "org.hu", + "priv.hu", + "sport.hu", + "tm.hu", + "2000.hu", + "agrar.hu", + "bolt.hu", + "casino.hu", + "city.hu", + "erotica.hu", + "erotika.hu", + "film.hu", + "forum.hu", + "games.hu", + "hotel.hu", + "ingatlan.hu", + "jogasz.hu", + "konyvelo.hu", + "lakas.hu", + "media.hu", + "news.hu", + "reklam.hu", + "sex.hu", + "shop.hu", + "suli.hu", + "szex.hu", + "tozsde.hu", + "utazas.hu", + "video.hu", + "id", + "ac.id", + "biz.id", + "co.id", + "desa.id", + "go.id", + "mil.id", + "my.id", + "net.id", + "or.id", + "ponpes.id", + "sch.id", + "web.id", + "ie", + "gov.ie", + "il", + "ac.il", + "co.il", + "gov.il", + "idf.il", + "k12.il", + "muni.il", + "net.il", + "org.il", + "im", + "ac.im", + "co.im", + "com.im", + "ltd.co.im", + "net.im", + "org.im", + "plc.co.im", + "tt.im", + "tv.im", + "in", + "co.in", + "firm.in", + "net.in", + "org.in", + "gen.in", + "ind.in", + "nic.in", + "ac.in", + "edu.in", + "res.in", + "gov.in", + "mil.in", + "info", + "int", + "eu.int", + "io", + "com.io", + "iq", + "gov.iq", + "edu.iq", + "mil.iq", + "com.iq", + "org.iq", + "net.iq", + "ir", + "ac.ir", + "co.ir", + "gov.ir", + "id.ir", + "net.ir", + "org.ir", + "sch.ir", + "\u0627\u06CC\u0631\u0627\u0646.ir", + "\u0627\u064A\u0631\u0627\u0646.ir", + "is", + "net.is", + "com.is", + "edu.is", + "gov.is", + "org.is", + "int.is", + "it", + "gov.it", + "edu.it", + "abr.it", + "abruzzo.it", + "aosta-valley.it", + "aostavalley.it", + "bas.it", + "basilicata.it", + "cal.it", + "calabria.it", + "cam.it", + "campania.it", + "emilia-romagna.it", + "emiliaromagna.it", + "emr.it", + "friuli-v-giulia.it", + "friuli-ve-giulia.it", + "friuli-vegiulia.it", + "friuli-venezia-giulia.it", + "friuli-veneziagiulia.it", + "friuli-vgiulia.it", + "friuliv-giulia.it", + "friulive-giulia.it", + "friulivegiulia.it", + "friulivenezia-giulia.it", + "friuliveneziagiulia.it", + "friulivgiulia.it", + "fvg.it", + "laz.it", + "lazio.it", + "lig.it", + "liguria.it", + "lom.it", + "lombardia.it", + "lombardy.it", + "lucania.it", + "mar.it", + "marche.it", + "mol.it", + "molise.it", + "piedmont.it", + "piemonte.it", + "pmn.it", + "pug.it", + "puglia.it", + "sar.it", + "sardegna.it", + "sardinia.it", + "sic.it", + "sicilia.it", + "sicily.it", + "taa.it", + "tos.it", + "toscana.it", + "trentin-sud-tirol.it", + "trentin-s\xFCd-tirol.it", + "trentin-sudtirol.it", + "trentin-s\xFCdtirol.it", + "trentin-sued-tirol.it", + "trentin-suedtirol.it", + "trentino-a-adige.it", + "trentino-aadige.it", + "trentino-alto-adige.it", + "trentino-altoadige.it", + "trentino-s-tirol.it", + "trentino-stirol.it", + "trentino-sud-tirol.it", + "trentino-s\xFCd-tirol.it", + "trentino-sudtirol.it", + "trentino-s\xFCdtirol.it", + "trentino-sued-tirol.it", + "trentino-suedtirol.it", + "trentino.it", + "trentinoa-adige.it", + "trentinoaadige.it", + "trentinoalto-adige.it", + "trentinoaltoadige.it", + "trentinos-tirol.it", + "trentinostirol.it", + "trentinosud-tirol.it", + "trentinos\xFCd-tirol.it", + "trentinosudtirol.it", + "trentinos\xFCdtirol.it", + "trentinosued-tirol.it", + "trentinosuedtirol.it", + "trentinsud-tirol.it", + "trentins\xFCd-tirol.it", + "trentinsudtirol.it", + "trentins\xFCdtirol.it", + "trentinsued-tirol.it", + "trentinsuedtirol.it", + "tuscany.it", + "umb.it", + "umbria.it", + "val-d-aosta.it", + "val-daosta.it", + "vald-aosta.it", + "valdaosta.it", + "valle-aosta.it", + "valle-d-aosta.it", + "valle-daosta.it", + "valleaosta.it", + "valled-aosta.it", + "valledaosta.it", + "vallee-aoste.it", + "vall\xE9e-aoste.it", + "vallee-d-aoste.it", + "vall\xE9e-d-aoste.it", + "valleeaoste.it", + "vall\xE9eaoste.it", + "valleedaoste.it", + "vall\xE9edaoste.it", + "vao.it", + "vda.it", + "ven.it", + "veneto.it", + "ag.it", + "agrigento.it", + "al.it", + "alessandria.it", + "alto-adige.it", + "altoadige.it", + "an.it", + "ancona.it", + "andria-barletta-trani.it", + "andria-trani-barletta.it", + "andriabarlettatrani.it", + "andriatranibarletta.it", + "ao.it", + "aosta.it", + "aoste.it", + "ap.it", + "aq.it", + "aquila.it", + "ar.it", + "arezzo.it", + "ascoli-piceno.it", + "ascolipiceno.it", + "asti.it", + "at.it", + "av.it", + "avellino.it", + "ba.it", + "balsan-sudtirol.it", + "balsan-s\xFCdtirol.it", + "balsan-suedtirol.it", + "balsan.it", + "bari.it", + "barletta-trani-andria.it", + "barlettatraniandria.it", + "belluno.it", + "benevento.it", + "bergamo.it", + "bg.it", + "bi.it", + "biella.it", + "bl.it", + "bn.it", + "bo.it", + "bologna.it", + "bolzano-altoadige.it", + "bolzano.it", + "bozen-sudtirol.it", + "bozen-s\xFCdtirol.it", + "bozen-suedtirol.it", + "bozen.it", + "br.it", + "brescia.it", + "brindisi.it", + "bs.it", + "bt.it", + "bulsan-sudtirol.it", + "bulsan-s\xFCdtirol.it", + "bulsan-suedtirol.it", + "bulsan.it", + "bz.it", + "ca.it", + "cagliari.it", + "caltanissetta.it", + "campidano-medio.it", + "campidanomedio.it", + "campobasso.it", + "carbonia-iglesias.it", + "carboniaiglesias.it", + "carrara-massa.it", + "carraramassa.it", + "caserta.it", + "catania.it", + "catanzaro.it", + "cb.it", + "ce.it", + "cesena-forli.it", + "cesena-forl\xEC.it", + "cesenaforli.it", + "cesenaforl\xEC.it", + "ch.it", + "chieti.it", + "ci.it", + "cl.it", + "cn.it", + "co.it", + "como.it", + "cosenza.it", + "cr.it", + "cremona.it", + "crotone.it", + "cs.it", + "ct.it", + "cuneo.it", + "cz.it", + "dell-ogliastra.it", + "dellogliastra.it", + "en.it", + "enna.it", + "fc.it", + "fe.it", + "fermo.it", + "ferrara.it", + "fg.it", + "fi.it", + "firenze.it", + "florence.it", + "fm.it", + "foggia.it", + "forli-cesena.it", + "forl\xEC-cesena.it", + "forlicesena.it", + "forl\xECcesena.it", + "fr.it", + "frosinone.it", + "ge.it", + "genoa.it", + "genova.it", + "go.it", + "gorizia.it", + "gr.it", + "grosseto.it", + "iglesias-carbonia.it", + "iglesiascarbonia.it", + "im.it", + "imperia.it", + "is.it", + "isernia.it", + "kr.it", + "la-spezia.it", + "laquila.it", + "laspezia.it", + "latina.it", + "lc.it", + "le.it", + "lecce.it", + "lecco.it", + "li.it", + "livorno.it", + "lo.it", + "lodi.it", + "lt.it", + "lu.it", + "lucca.it", + "macerata.it", + "mantova.it", + "massa-carrara.it", + "massacarrara.it", + "matera.it", + "mb.it", + "mc.it", + "me.it", + "medio-campidano.it", + "mediocampidano.it", + "messina.it", + "mi.it", + "milan.it", + "milano.it", + "mn.it", + "mo.it", + "modena.it", + "monza-brianza.it", + "monza-e-della-brianza.it", + "monza.it", + "monzabrianza.it", + "monzaebrianza.it", + "monzaedellabrianza.it", + "ms.it", + "mt.it", + "na.it", + "naples.it", + "napoli.it", + "no.it", + "novara.it", + "nu.it", + "nuoro.it", + "og.it", + "ogliastra.it", + "olbia-tempio.it", + "olbiatempio.it", + "or.it", + "oristano.it", + "ot.it", + "pa.it", + "padova.it", + "padua.it", + "palermo.it", + "parma.it", + "pavia.it", + "pc.it", + "pd.it", + "pe.it", + "perugia.it", + "pesaro-urbino.it", + "pesarourbino.it", + "pescara.it", + "pg.it", + "pi.it", + "piacenza.it", + "pisa.it", + "pistoia.it", + "pn.it", + "po.it", + "pordenone.it", + "potenza.it", + "pr.it", + "prato.it", + "pt.it", + "pu.it", + "pv.it", + "pz.it", + "ra.it", + "ragusa.it", + "ravenna.it", + "rc.it", + "re.it", + "reggio-calabria.it", + "reggio-emilia.it", + "reggiocalabria.it", + "reggioemilia.it", + "rg.it", + "ri.it", + "rieti.it", + "rimini.it", + "rm.it", + "rn.it", + "ro.it", + "roma.it", + "rome.it", + "rovigo.it", + "sa.it", + "salerno.it", + "sassari.it", + "savona.it", + "si.it", + "siena.it", + "siracusa.it", + "so.it", + "sondrio.it", + "sp.it", + "sr.it", + "ss.it", + "suedtirol.it", + "s\xFCdtirol.it", + "sv.it", + "ta.it", + "taranto.it", + "te.it", + "tempio-olbia.it", + "tempioolbia.it", + "teramo.it", + "terni.it", + "tn.it", + "to.it", + "torino.it", + "tp.it", + "tr.it", + "trani-andria-barletta.it", + "trani-barletta-andria.it", + "traniandriabarletta.it", + "tranibarlettaandria.it", + "trapani.it", + "trento.it", + "treviso.it", + "trieste.it", + "ts.it", + "turin.it", + "tv.it", + "ud.it", + "udine.it", + "urbino-pesaro.it", + "urbinopesaro.it", + "va.it", + "varese.it", + "vb.it", + "vc.it", + "ve.it", + "venezia.it", + "venice.it", + "verbania.it", + "vercelli.it", + "verona.it", + "vi.it", + "vibo-valentia.it", + "vibovalentia.it", + "vicenza.it", + "viterbo.it", + "vr.it", + "vs.it", + "vt.it", + "vv.it", + "je", + "co.je", + "net.je", + "org.je", + "*.jm", + "jo", + "com.jo", + "org.jo", + "net.jo", + "edu.jo", + "sch.jo", + "gov.jo", + "mil.jo", + "name.jo", + "jobs", + "jp", + "ac.jp", + "ad.jp", + "co.jp", + "ed.jp", + "go.jp", + "gr.jp", + "lg.jp", + "ne.jp", + "or.jp", + "aichi.jp", + "akita.jp", + "aomori.jp", + "chiba.jp", + "ehime.jp", + "fukui.jp", + "fukuoka.jp", + "fukushima.jp", + "gifu.jp", + "gunma.jp", + "hiroshima.jp", + "hokkaido.jp", + "hyogo.jp", + "ibaraki.jp", + "ishikawa.jp", + "iwate.jp", + "kagawa.jp", + "kagoshima.jp", + "kanagawa.jp", + "kochi.jp", + "kumamoto.jp", + "kyoto.jp", + "mie.jp", + "miyagi.jp", + "miyazaki.jp", + "nagano.jp", + "nagasaki.jp", + "nara.jp", + "niigata.jp", + "oita.jp", + "okayama.jp", + "okinawa.jp", + "osaka.jp", + "saga.jp", + "saitama.jp", + "shiga.jp", + "shimane.jp", + "shizuoka.jp", + "tochigi.jp", + "tokushima.jp", + "tokyo.jp", + "tottori.jp", + "toyama.jp", + "wakayama.jp", + "yamagata.jp", + "yamaguchi.jp", + "yamanashi.jp", + "\u6803\u6728.jp", + "\u611B\u77E5.jp", + "\u611B\u5A9B.jp", + "\u5175\u5EAB.jp", + "\u718A\u672C.jp", + "\u8328\u57CE.jp", + "\u5317\u6D77\u9053.jp", + "\u5343\u8449.jp", + "\u548C\u6B4C\u5C71.jp", + "\u9577\u5D0E.jp", + "\u9577\u91CE.jp", + "\u65B0\u6F5F.jp", + "\u9752\u68EE.jp", + "\u9759\u5CA1.jp", + "\u6771\u4EAC.jp", + "\u77F3\u5DDD.jp", + "\u57FC\u7389.jp", + "\u4E09\u91CD.jp", + "\u4EAC\u90FD.jp", + "\u4F50\u8CC0.jp", + "\u5927\u5206.jp", + "\u5927\u962A.jp", + "\u5948\u826F.jp", + "\u5BAE\u57CE.jp", + "\u5BAE\u5D0E.jp", + "\u5BCC\u5C71.jp", + "\u5C71\u53E3.jp", + "\u5C71\u5F62.jp", + "\u5C71\u68A8.jp", + "\u5CA9\u624B.jp", + "\u5C90\u961C.jp", + "\u5CA1\u5C71.jp", + "\u5CF6\u6839.jp", + "\u5E83\u5CF6.jp", + "\u5FB3\u5CF6.jp", + "\u6C96\u7E04.jp", + "\u6ECB\u8CC0.jp", + "\u795E\u5948\u5DDD.jp", + "\u798F\u4E95.jp", + "\u798F\u5CA1.jp", + "\u798F\u5CF6.jp", + "\u79CB\u7530.jp", + "\u7FA4\u99AC.jp", + "\u9999\u5DDD.jp", + "\u9AD8\u77E5.jp", + "\u9CE5\u53D6.jp", + "\u9E7F\u5150\u5CF6.jp", + "*.kawasaki.jp", + "*.kitakyushu.jp", + "*.kobe.jp", + "*.nagoya.jp", + "*.sapporo.jp", + "*.sendai.jp", + "*.yokohama.jp", + "!city.kawasaki.jp", + "!city.kitakyushu.jp", + "!city.kobe.jp", + "!city.nagoya.jp", + "!city.sapporo.jp", + "!city.sendai.jp", + "!city.yokohama.jp", + "aisai.aichi.jp", + "ama.aichi.jp", + "anjo.aichi.jp", + "asuke.aichi.jp", + "chiryu.aichi.jp", + "chita.aichi.jp", + "fuso.aichi.jp", + "gamagori.aichi.jp", + "handa.aichi.jp", + "hazu.aichi.jp", + "hekinan.aichi.jp", + "higashiura.aichi.jp", + "ichinomiya.aichi.jp", + "inazawa.aichi.jp", + "inuyama.aichi.jp", + "isshiki.aichi.jp", + "iwakura.aichi.jp", + "kanie.aichi.jp", + "kariya.aichi.jp", + "kasugai.aichi.jp", + "kira.aichi.jp", + "kiyosu.aichi.jp", + "komaki.aichi.jp", + "konan.aichi.jp", + "kota.aichi.jp", + "mihama.aichi.jp", + "miyoshi.aichi.jp", + "nishio.aichi.jp", + "nisshin.aichi.jp", + "obu.aichi.jp", + "oguchi.aichi.jp", + "oharu.aichi.jp", + "okazaki.aichi.jp", + "owariasahi.aichi.jp", + "seto.aichi.jp", + "shikatsu.aichi.jp", + "shinshiro.aichi.jp", + "shitara.aichi.jp", + "tahara.aichi.jp", + "takahama.aichi.jp", + "tobishima.aichi.jp", + "toei.aichi.jp", + "togo.aichi.jp", + "tokai.aichi.jp", + "tokoname.aichi.jp", + "toyoake.aichi.jp", + "toyohashi.aichi.jp", + "toyokawa.aichi.jp", + "toyone.aichi.jp", + "toyota.aichi.jp", + "tsushima.aichi.jp", + "yatomi.aichi.jp", + "akita.akita.jp", + "daisen.akita.jp", + "fujisato.akita.jp", + "gojome.akita.jp", + "hachirogata.akita.jp", + "happou.akita.jp", + "higashinaruse.akita.jp", + "honjo.akita.jp", + "honjyo.akita.jp", + "ikawa.akita.jp", + "kamikoani.akita.jp", + "kamioka.akita.jp", + "katagami.akita.jp", + "kazuno.akita.jp", + "kitaakita.akita.jp", + "kosaka.akita.jp", + "kyowa.akita.jp", + "misato.akita.jp", + "mitane.akita.jp", + "moriyoshi.akita.jp", + "nikaho.akita.jp", + "noshiro.akita.jp", + "odate.akita.jp", + "oga.akita.jp", + "ogata.akita.jp", + "semboku.akita.jp", + "yokote.akita.jp", + "yurihonjo.akita.jp", + "aomori.aomori.jp", + "gonohe.aomori.jp", + "hachinohe.aomori.jp", + "hashikami.aomori.jp", + "hiranai.aomori.jp", + "hirosaki.aomori.jp", + "itayanagi.aomori.jp", + "kuroishi.aomori.jp", + "misawa.aomori.jp", + "mutsu.aomori.jp", + "nakadomari.aomori.jp", + "noheji.aomori.jp", + "oirase.aomori.jp", + "owani.aomori.jp", + "rokunohe.aomori.jp", + "sannohe.aomori.jp", + "shichinohe.aomori.jp", + "shingo.aomori.jp", + "takko.aomori.jp", + "towada.aomori.jp", + "tsugaru.aomori.jp", + "tsuruta.aomori.jp", + "abiko.chiba.jp", + "asahi.chiba.jp", + "chonan.chiba.jp", + "chosei.chiba.jp", + "choshi.chiba.jp", + "chuo.chiba.jp", + "funabashi.chiba.jp", + "futtsu.chiba.jp", + "hanamigawa.chiba.jp", + "ichihara.chiba.jp", + "ichikawa.chiba.jp", + "ichinomiya.chiba.jp", + "inzai.chiba.jp", + "isumi.chiba.jp", + "kamagaya.chiba.jp", + "kamogawa.chiba.jp", + "kashiwa.chiba.jp", + "katori.chiba.jp", + "katsuura.chiba.jp", + "kimitsu.chiba.jp", + "kisarazu.chiba.jp", + "kozaki.chiba.jp", + "kujukuri.chiba.jp", + "kyonan.chiba.jp", + "matsudo.chiba.jp", + "midori.chiba.jp", + "mihama.chiba.jp", + "minamiboso.chiba.jp", + "mobara.chiba.jp", + "mutsuzawa.chiba.jp", + "nagara.chiba.jp", + "nagareyama.chiba.jp", + "narashino.chiba.jp", + "narita.chiba.jp", + "noda.chiba.jp", + "oamishirasato.chiba.jp", + "omigawa.chiba.jp", + "onjuku.chiba.jp", + "otaki.chiba.jp", + "sakae.chiba.jp", + "sakura.chiba.jp", + "shimofusa.chiba.jp", + "shirako.chiba.jp", + "shiroi.chiba.jp", + "shisui.chiba.jp", + "sodegaura.chiba.jp", + "sosa.chiba.jp", + "tako.chiba.jp", + "tateyama.chiba.jp", + "togane.chiba.jp", + "tohnosho.chiba.jp", + "tomisato.chiba.jp", + "urayasu.chiba.jp", + "yachimata.chiba.jp", + "yachiyo.chiba.jp", + "yokaichiba.chiba.jp", + "yokoshibahikari.chiba.jp", + "yotsukaido.chiba.jp", + "ainan.ehime.jp", + "honai.ehime.jp", + "ikata.ehime.jp", + "imabari.ehime.jp", + "iyo.ehime.jp", + "kamijima.ehime.jp", + "kihoku.ehime.jp", + "kumakogen.ehime.jp", + "masaki.ehime.jp", + "matsuno.ehime.jp", + "matsuyama.ehime.jp", + "namikata.ehime.jp", + "niihama.ehime.jp", + "ozu.ehime.jp", + "saijo.ehime.jp", + "seiyo.ehime.jp", + "shikokuchuo.ehime.jp", + "tobe.ehime.jp", + "toon.ehime.jp", + "uchiko.ehime.jp", + "uwajima.ehime.jp", + "yawatahama.ehime.jp", + "echizen.fukui.jp", + "eiheiji.fukui.jp", + "fukui.fukui.jp", + "ikeda.fukui.jp", + "katsuyama.fukui.jp", + "mihama.fukui.jp", + "minamiechizen.fukui.jp", + "obama.fukui.jp", + "ohi.fukui.jp", + "ono.fukui.jp", + "sabae.fukui.jp", + "sakai.fukui.jp", + "takahama.fukui.jp", + "tsuruga.fukui.jp", + "wakasa.fukui.jp", + "ashiya.fukuoka.jp", + "buzen.fukuoka.jp", + "chikugo.fukuoka.jp", + "chikuho.fukuoka.jp", + "chikujo.fukuoka.jp", + "chikushino.fukuoka.jp", + "chikuzen.fukuoka.jp", + "chuo.fukuoka.jp", + "dazaifu.fukuoka.jp", + "fukuchi.fukuoka.jp", + "hakata.fukuoka.jp", + "higashi.fukuoka.jp", + "hirokawa.fukuoka.jp", + "hisayama.fukuoka.jp", + "iizuka.fukuoka.jp", + "inatsuki.fukuoka.jp", + "kaho.fukuoka.jp", + "kasuga.fukuoka.jp", + "kasuya.fukuoka.jp", + "kawara.fukuoka.jp", + "keisen.fukuoka.jp", + "koga.fukuoka.jp", + "kurate.fukuoka.jp", + "kurogi.fukuoka.jp", + "kurume.fukuoka.jp", + "minami.fukuoka.jp", + "miyako.fukuoka.jp", + "miyama.fukuoka.jp", + "miyawaka.fukuoka.jp", + "mizumaki.fukuoka.jp", + "munakata.fukuoka.jp", + "nakagawa.fukuoka.jp", + "nakama.fukuoka.jp", + "nishi.fukuoka.jp", + "nogata.fukuoka.jp", + "ogori.fukuoka.jp", + "okagaki.fukuoka.jp", + "okawa.fukuoka.jp", + "oki.fukuoka.jp", + "omuta.fukuoka.jp", + "onga.fukuoka.jp", + "onojo.fukuoka.jp", + "oto.fukuoka.jp", + "saigawa.fukuoka.jp", + "sasaguri.fukuoka.jp", + "shingu.fukuoka.jp", + "shinyoshitomi.fukuoka.jp", + "shonai.fukuoka.jp", + "soeda.fukuoka.jp", + "sue.fukuoka.jp", + "tachiarai.fukuoka.jp", + "tagawa.fukuoka.jp", + "takata.fukuoka.jp", + "toho.fukuoka.jp", + "toyotsu.fukuoka.jp", + "tsuiki.fukuoka.jp", + "ukiha.fukuoka.jp", + "umi.fukuoka.jp", + "usui.fukuoka.jp", + "yamada.fukuoka.jp", + "yame.fukuoka.jp", + "yanagawa.fukuoka.jp", + "yukuhashi.fukuoka.jp", + "aizubange.fukushima.jp", + "aizumisato.fukushima.jp", + "aizuwakamatsu.fukushima.jp", + "asakawa.fukushima.jp", + "bandai.fukushima.jp", + "date.fukushima.jp", + "fukushima.fukushima.jp", + "furudono.fukushima.jp", + "futaba.fukushima.jp", + "hanawa.fukushima.jp", + "higashi.fukushima.jp", + "hirata.fukushima.jp", + "hirono.fukushima.jp", + "iitate.fukushima.jp", + "inawashiro.fukushima.jp", + "ishikawa.fukushima.jp", + "iwaki.fukushima.jp", + "izumizaki.fukushima.jp", + "kagamiishi.fukushima.jp", + "kaneyama.fukushima.jp", + "kawamata.fukushima.jp", + "kitakata.fukushima.jp", + "kitashiobara.fukushima.jp", + "koori.fukushima.jp", + "koriyama.fukushima.jp", + "kunimi.fukushima.jp", + "miharu.fukushima.jp", + "mishima.fukushima.jp", + "namie.fukushima.jp", + "nango.fukushima.jp", + "nishiaizu.fukushima.jp", + "nishigo.fukushima.jp", + "okuma.fukushima.jp", + "omotego.fukushima.jp", + "ono.fukushima.jp", + "otama.fukushima.jp", + "samegawa.fukushima.jp", + "shimogo.fukushima.jp", + "shirakawa.fukushima.jp", + "showa.fukushima.jp", + "soma.fukushima.jp", + "sukagawa.fukushima.jp", + "taishin.fukushima.jp", + "tamakawa.fukushima.jp", + "tanagura.fukushima.jp", + "tenei.fukushima.jp", + "yabuki.fukushima.jp", + "yamato.fukushima.jp", + "yamatsuri.fukushima.jp", + "yanaizu.fukushima.jp", + "yugawa.fukushima.jp", + "anpachi.gifu.jp", + "ena.gifu.jp", + "gifu.gifu.jp", + "ginan.gifu.jp", + "godo.gifu.jp", + "gujo.gifu.jp", + "hashima.gifu.jp", + "hichiso.gifu.jp", + "hida.gifu.jp", + "higashishirakawa.gifu.jp", + "ibigawa.gifu.jp", + "ikeda.gifu.jp", + "kakamigahara.gifu.jp", + "kani.gifu.jp", + "kasahara.gifu.jp", + "kasamatsu.gifu.jp", + "kawaue.gifu.jp", + "kitagata.gifu.jp", + "mino.gifu.jp", + "minokamo.gifu.jp", + "mitake.gifu.jp", + "mizunami.gifu.jp", + "motosu.gifu.jp", + "nakatsugawa.gifu.jp", + "ogaki.gifu.jp", + "sakahogi.gifu.jp", + "seki.gifu.jp", + "sekigahara.gifu.jp", + "shirakawa.gifu.jp", + "tajimi.gifu.jp", + "takayama.gifu.jp", + "tarui.gifu.jp", + "toki.gifu.jp", + "tomika.gifu.jp", + "wanouchi.gifu.jp", + "yamagata.gifu.jp", + "yaotsu.gifu.jp", + "yoro.gifu.jp", + "annaka.gunma.jp", + "chiyoda.gunma.jp", + "fujioka.gunma.jp", + "higashiagatsuma.gunma.jp", + "isesaki.gunma.jp", + "itakura.gunma.jp", + "kanna.gunma.jp", + "kanra.gunma.jp", + "katashina.gunma.jp", + "kawaba.gunma.jp", + "kiryu.gunma.jp", + "kusatsu.gunma.jp", + "maebashi.gunma.jp", + "meiwa.gunma.jp", + "midori.gunma.jp", + "minakami.gunma.jp", + "naganohara.gunma.jp", + "nakanojo.gunma.jp", + "nanmoku.gunma.jp", + "numata.gunma.jp", + "oizumi.gunma.jp", + "ora.gunma.jp", + "ota.gunma.jp", + "shibukawa.gunma.jp", + "shimonita.gunma.jp", + "shinto.gunma.jp", + "showa.gunma.jp", + "takasaki.gunma.jp", + "takayama.gunma.jp", + "tamamura.gunma.jp", + "tatebayashi.gunma.jp", + "tomioka.gunma.jp", + "tsukiyono.gunma.jp", + "tsumagoi.gunma.jp", + "ueno.gunma.jp", + "yoshioka.gunma.jp", + "asaminami.hiroshima.jp", + "daiwa.hiroshima.jp", + "etajima.hiroshima.jp", + "fuchu.hiroshima.jp", + "fukuyama.hiroshima.jp", + "hatsukaichi.hiroshima.jp", + "higashihiroshima.hiroshima.jp", + "hongo.hiroshima.jp", + "jinsekikogen.hiroshima.jp", + "kaita.hiroshima.jp", + "kui.hiroshima.jp", + "kumano.hiroshima.jp", + "kure.hiroshima.jp", + "mihara.hiroshima.jp", + "miyoshi.hiroshima.jp", + "naka.hiroshima.jp", + "onomichi.hiroshima.jp", + "osakikamijima.hiroshima.jp", + "otake.hiroshima.jp", + "saka.hiroshima.jp", + "sera.hiroshima.jp", + "seranishi.hiroshima.jp", + "shinichi.hiroshima.jp", + "shobara.hiroshima.jp", + "takehara.hiroshima.jp", + "abashiri.hokkaido.jp", + "abira.hokkaido.jp", + "aibetsu.hokkaido.jp", + "akabira.hokkaido.jp", + "akkeshi.hokkaido.jp", + "asahikawa.hokkaido.jp", + "ashibetsu.hokkaido.jp", + "ashoro.hokkaido.jp", + "assabu.hokkaido.jp", + "atsuma.hokkaido.jp", + "bibai.hokkaido.jp", + "biei.hokkaido.jp", + "bifuka.hokkaido.jp", + "bihoro.hokkaido.jp", + "biratori.hokkaido.jp", + "chippubetsu.hokkaido.jp", + "chitose.hokkaido.jp", + "date.hokkaido.jp", + "ebetsu.hokkaido.jp", + "embetsu.hokkaido.jp", + "eniwa.hokkaido.jp", + "erimo.hokkaido.jp", + "esan.hokkaido.jp", + "esashi.hokkaido.jp", + "fukagawa.hokkaido.jp", + "fukushima.hokkaido.jp", + "furano.hokkaido.jp", + "furubira.hokkaido.jp", + "haboro.hokkaido.jp", + "hakodate.hokkaido.jp", + "hamatonbetsu.hokkaido.jp", + "hidaka.hokkaido.jp", + "higashikagura.hokkaido.jp", + "higashikawa.hokkaido.jp", + "hiroo.hokkaido.jp", + "hokuryu.hokkaido.jp", + "hokuto.hokkaido.jp", + "honbetsu.hokkaido.jp", + "horokanai.hokkaido.jp", + "horonobe.hokkaido.jp", + "ikeda.hokkaido.jp", + "imakane.hokkaido.jp", + "ishikari.hokkaido.jp", + "iwamizawa.hokkaido.jp", + "iwanai.hokkaido.jp", + "kamifurano.hokkaido.jp", + "kamikawa.hokkaido.jp", + "kamishihoro.hokkaido.jp", + "kamisunagawa.hokkaido.jp", + "kamoenai.hokkaido.jp", + "kayabe.hokkaido.jp", + "kembuchi.hokkaido.jp", + "kikonai.hokkaido.jp", + "kimobetsu.hokkaido.jp", + "kitahiroshima.hokkaido.jp", + "kitami.hokkaido.jp", + "kiyosato.hokkaido.jp", + "koshimizu.hokkaido.jp", + "kunneppu.hokkaido.jp", + "kuriyama.hokkaido.jp", + "kuromatsunai.hokkaido.jp", + "kushiro.hokkaido.jp", + "kutchan.hokkaido.jp", + "kyowa.hokkaido.jp", + "mashike.hokkaido.jp", + "matsumae.hokkaido.jp", + "mikasa.hokkaido.jp", + "minamifurano.hokkaido.jp", + "mombetsu.hokkaido.jp", + "moseushi.hokkaido.jp", + "mukawa.hokkaido.jp", + "muroran.hokkaido.jp", + "naie.hokkaido.jp", + "nakagawa.hokkaido.jp", + "nakasatsunai.hokkaido.jp", + "nakatombetsu.hokkaido.jp", + "nanae.hokkaido.jp", + "nanporo.hokkaido.jp", + "nayoro.hokkaido.jp", + "nemuro.hokkaido.jp", + "niikappu.hokkaido.jp", + "niki.hokkaido.jp", + "nishiokoppe.hokkaido.jp", + "noboribetsu.hokkaido.jp", + "numata.hokkaido.jp", + "obihiro.hokkaido.jp", + "obira.hokkaido.jp", + "oketo.hokkaido.jp", + "okoppe.hokkaido.jp", + "otaru.hokkaido.jp", + "otobe.hokkaido.jp", + "otofuke.hokkaido.jp", + "otoineppu.hokkaido.jp", + "oumu.hokkaido.jp", + "ozora.hokkaido.jp", + "pippu.hokkaido.jp", + "rankoshi.hokkaido.jp", + "rebun.hokkaido.jp", + "rikubetsu.hokkaido.jp", + "rishiri.hokkaido.jp", + "rishirifuji.hokkaido.jp", + "saroma.hokkaido.jp", + "sarufutsu.hokkaido.jp", + "shakotan.hokkaido.jp", + "shari.hokkaido.jp", + "shibecha.hokkaido.jp", + "shibetsu.hokkaido.jp", + "shikabe.hokkaido.jp", + "shikaoi.hokkaido.jp", + "shimamaki.hokkaido.jp", + "shimizu.hokkaido.jp", + "shimokawa.hokkaido.jp", + "shinshinotsu.hokkaido.jp", + "shintoku.hokkaido.jp", + "shiranuka.hokkaido.jp", + "shiraoi.hokkaido.jp", + "shiriuchi.hokkaido.jp", + "sobetsu.hokkaido.jp", + "sunagawa.hokkaido.jp", + "taiki.hokkaido.jp", + "takasu.hokkaido.jp", + "takikawa.hokkaido.jp", + "takinoue.hokkaido.jp", + "teshikaga.hokkaido.jp", + "tobetsu.hokkaido.jp", + "tohma.hokkaido.jp", + "tomakomai.hokkaido.jp", + "tomari.hokkaido.jp", + "toya.hokkaido.jp", + "toyako.hokkaido.jp", + "toyotomi.hokkaido.jp", + "toyoura.hokkaido.jp", + "tsubetsu.hokkaido.jp", + "tsukigata.hokkaido.jp", + "urakawa.hokkaido.jp", + "urausu.hokkaido.jp", + "uryu.hokkaido.jp", + "utashinai.hokkaido.jp", + "wakkanai.hokkaido.jp", + "wassamu.hokkaido.jp", + "yakumo.hokkaido.jp", + "yoichi.hokkaido.jp", + "aioi.hyogo.jp", + "akashi.hyogo.jp", + "ako.hyogo.jp", + "amagasaki.hyogo.jp", + "aogaki.hyogo.jp", + "asago.hyogo.jp", + "ashiya.hyogo.jp", + "awaji.hyogo.jp", + "fukusaki.hyogo.jp", + "goshiki.hyogo.jp", + "harima.hyogo.jp", + "himeji.hyogo.jp", + "ichikawa.hyogo.jp", + "inagawa.hyogo.jp", + "itami.hyogo.jp", + "kakogawa.hyogo.jp", + "kamigori.hyogo.jp", + "kamikawa.hyogo.jp", + "kasai.hyogo.jp", + "kasuga.hyogo.jp", + "kawanishi.hyogo.jp", + "miki.hyogo.jp", + "minamiawaji.hyogo.jp", + "nishinomiya.hyogo.jp", + "nishiwaki.hyogo.jp", + "ono.hyogo.jp", + "sanda.hyogo.jp", + "sannan.hyogo.jp", + "sasayama.hyogo.jp", + "sayo.hyogo.jp", + "shingu.hyogo.jp", + "shinonsen.hyogo.jp", + "shiso.hyogo.jp", + "sumoto.hyogo.jp", + "taishi.hyogo.jp", + "taka.hyogo.jp", + "takarazuka.hyogo.jp", + "takasago.hyogo.jp", + "takino.hyogo.jp", + "tamba.hyogo.jp", + "tatsuno.hyogo.jp", + "toyooka.hyogo.jp", + "yabu.hyogo.jp", + "yashiro.hyogo.jp", + "yoka.hyogo.jp", + "yokawa.hyogo.jp", + "ami.ibaraki.jp", + "asahi.ibaraki.jp", + "bando.ibaraki.jp", + "chikusei.ibaraki.jp", + "daigo.ibaraki.jp", + "fujishiro.ibaraki.jp", + "hitachi.ibaraki.jp", + "hitachinaka.ibaraki.jp", + "hitachiomiya.ibaraki.jp", + "hitachiota.ibaraki.jp", + "ibaraki.ibaraki.jp", + "ina.ibaraki.jp", + "inashiki.ibaraki.jp", + "itako.ibaraki.jp", + "iwama.ibaraki.jp", + "joso.ibaraki.jp", + "kamisu.ibaraki.jp", + "kasama.ibaraki.jp", + "kashima.ibaraki.jp", + "kasumigaura.ibaraki.jp", + "koga.ibaraki.jp", + "miho.ibaraki.jp", + "mito.ibaraki.jp", + "moriya.ibaraki.jp", + "naka.ibaraki.jp", + "namegata.ibaraki.jp", + "oarai.ibaraki.jp", + "ogawa.ibaraki.jp", + "omitama.ibaraki.jp", + "ryugasaki.ibaraki.jp", + "sakai.ibaraki.jp", + "sakuragawa.ibaraki.jp", + "shimodate.ibaraki.jp", + "shimotsuma.ibaraki.jp", + "shirosato.ibaraki.jp", + "sowa.ibaraki.jp", + "suifu.ibaraki.jp", + "takahagi.ibaraki.jp", + "tamatsukuri.ibaraki.jp", + "tokai.ibaraki.jp", + "tomobe.ibaraki.jp", + "tone.ibaraki.jp", + "toride.ibaraki.jp", + "tsuchiura.ibaraki.jp", + "tsukuba.ibaraki.jp", + "uchihara.ibaraki.jp", + "ushiku.ibaraki.jp", + "yachiyo.ibaraki.jp", + "yamagata.ibaraki.jp", + "yawara.ibaraki.jp", + "yuki.ibaraki.jp", + "anamizu.ishikawa.jp", + "hakui.ishikawa.jp", + "hakusan.ishikawa.jp", + "kaga.ishikawa.jp", + "kahoku.ishikawa.jp", + "kanazawa.ishikawa.jp", + "kawakita.ishikawa.jp", + "komatsu.ishikawa.jp", + "nakanoto.ishikawa.jp", + "nanao.ishikawa.jp", + "nomi.ishikawa.jp", + "nonoichi.ishikawa.jp", + "noto.ishikawa.jp", + "shika.ishikawa.jp", + "suzu.ishikawa.jp", + "tsubata.ishikawa.jp", + "tsurugi.ishikawa.jp", + "uchinada.ishikawa.jp", + "wajima.ishikawa.jp", + "fudai.iwate.jp", + "fujisawa.iwate.jp", + "hanamaki.iwate.jp", + "hiraizumi.iwate.jp", + "hirono.iwate.jp", + "ichinohe.iwate.jp", + "ichinoseki.iwate.jp", + "iwaizumi.iwate.jp", + "iwate.iwate.jp", + "joboji.iwate.jp", + "kamaishi.iwate.jp", + "kanegasaki.iwate.jp", + "karumai.iwate.jp", + "kawai.iwate.jp", + "kitakami.iwate.jp", + "kuji.iwate.jp", + "kunohe.iwate.jp", + "kuzumaki.iwate.jp", + "miyako.iwate.jp", + "mizusawa.iwate.jp", + "morioka.iwate.jp", + "ninohe.iwate.jp", + "noda.iwate.jp", + "ofunato.iwate.jp", + "oshu.iwate.jp", + "otsuchi.iwate.jp", + "rikuzentakata.iwate.jp", + "shiwa.iwate.jp", + "shizukuishi.iwate.jp", + "sumita.iwate.jp", + "tanohata.iwate.jp", + "tono.iwate.jp", + "yahaba.iwate.jp", + "yamada.iwate.jp", + "ayagawa.kagawa.jp", + "higashikagawa.kagawa.jp", + "kanonji.kagawa.jp", + "kotohira.kagawa.jp", + "manno.kagawa.jp", + "marugame.kagawa.jp", + "mitoyo.kagawa.jp", + "naoshima.kagawa.jp", + "sanuki.kagawa.jp", + "tadotsu.kagawa.jp", + "takamatsu.kagawa.jp", + "tonosho.kagawa.jp", + "uchinomi.kagawa.jp", + "utazu.kagawa.jp", + "zentsuji.kagawa.jp", + "akune.kagoshima.jp", + "amami.kagoshima.jp", + "hioki.kagoshima.jp", + "isa.kagoshima.jp", + "isen.kagoshima.jp", + "izumi.kagoshima.jp", + "kagoshima.kagoshima.jp", + "kanoya.kagoshima.jp", + "kawanabe.kagoshima.jp", + "kinko.kagoshima.jp", + "kouyama.kagoshima.jp", + "makurazaki.kagoshima.jp", + "matsumoto.kagoshima.jp", + "minamitane.kagoshima.jp", + "nakatane.kagoshima.jp", + "nishinoomote.kagoshima.jp", + "satsumasendai.kagoshima.jp", + "soo.kagoshima.jp", + "tarumizu.kagoshima.jp", + "yusui.kagoshima.jp", + "aikawa.kanagawa.jp", + "atsugi.kanagawa.jp", + "ayase.kanagawa.jp", + "chigasaki.kanagawa.jp", + "ebina.kanagawa.jp", + "fujisawa.kanagawa.jp", + "hadano.kanagawa.jp", + "hakone.kanagawa.jp", + "hiratsuka.kanagawa.jp", + "isehara.kanagawa.jp", + "kaisei.kanagawa.jp", + "kamakura.kanagawa.jp", + "kiyokawa.kanagawa.jp", + "matsuda.kanagawa.jp", + "minamiashigara.kanagawa.jp", + "miura.kanagawa.jp", + "nakai.kanagawa.jp", + "ninomiya.kanagawa.jp", + "odawara.kanagawa.jp", + "oi.kanagawa.jp", + "oiso.kanagawa.jp", + "sagamihara.kanagawa.jp", + "samukawa.kanagawa.jp", + "tsukui.kanagawa.jp", + "yamakita.kanagawa.jp", + "yamato.kanagawa.jp", + "yokosuka.kanagawa.jp", + "yugawara.kanagawa.jp", + "zama.kanagawa.jp", + "zushi.kanagawa.jp", + "aki.kochi.jp", + "geisei.kochi.jp", + "hidaka.kochi.jp", + "higashitsuno.kochi.jp", + "ino.kochi.jp", + "kagami.kochi.jp", + "kami.kochi.jp", + "kitagawa.kochi.jp", + "kochi.kochi.jp", + "mihara.kochi.jp", + "motoyama.kochi.jp", + "muroto.kochi.jp", + "nahari.kochi.jp", + "nakamura.kochi.jp", + "nankoku.kochi.jp", + "nishitosa.kochi.jp", + "niyodogawa.kochi.jp", + "ochi.kochi.jp", + "okawa.kochi.jp", + "otoyo.kochi.jp", + "otsuki.kochi.jp", + "sakawa.kochi.jp", + "sukumo.kochi.jp", + "susaki.kochi.jp", + "tosa.kochi.jp", + "tosashimizu.kochi.jp", + "toyo.kochi.jp", + "tsuno.kochi.jp", + "umaji.kochi.jp", + "yasuda.kochi.jp", + "yusuhara.kochi.jp", + "amakusa.kumamoto.jp", + "arao.kumamoto.jp", + "aso.kumamoto.jp", + "choyo.kumamoto.jp", + "gyokuto.kumamoto.jp", + "kamiamakusa.kumamoto.jp", + "kikuchi.kumamoto.jp", + "kumamoto.kumamoto.jp", + "mashiki.kumamoto.jp", + "mifune.kumamoto.jp", + "minamata.kumamoto.jp", + "minamioguni.kumamoto.jp", + "nagasu.kumamoto.jp", + "nishihara.kumamoto.jp", + "oguni.kumamoto.jp", + "ozu.kumamoto.jp", + "sumoto.kumamoto.jp", + "takamori.kumamoto.jp", + "uki.kumamoto.jp", + "uto.kumamoto.jp", + "yamaga.kumamoto.jp", + "yamato.kumamoto.jp", + "yatsushiro.kumamoto.jp", + "ayabe.kyoto.jp", + "fukuchiyama.kyoto.jp", + "higashiyama.kyoto.jp", + "ide.kyoto.jp", + "ine.kyoto.jp", + "joyo.kyoto.jp", + "kameoka.kyoto.jp", + "kamo.kyoto.jp", + "kita.kyoto.jp", + "kizu.kyoto.jp", + "kumiyama.kyoto.jp", + "kyotamba.kyoto.jp", + "kyotanabe.kyoto.jp", + "kyotango.kyoto.jp", + "maizuru.kyoto.jp", + "minami.kyoto.jp", + "minamiyamashiro.kyoto.jp", + "miyazu.kyoto.jp", + "muko.kyoto.jp", + "nagaokakyo.kyoto.jp", + "nakagyo.kyoto.jp", + "nantan.kyoto.jp", + "oyamazaki.kyoto.jp", + "sakyo.kyoto.jp", + "seika.kyoto.jp", + "tanabe.kyoto.jp", + "uji.kyoto.jp", + "ujitawara.kyoto.jp", + "wazuka.kyoto.jp", + "yamashina.kyoto.jp", + "yawata.kyoto.jp", + "asahi.mie.jp", + "inabe.mie.jp", + "ise.mie.jp", + "kameyama.mie.jp", + "kawagoe.mie.jp", + "kiho.mie.jp", + "kisosaki.mie.jp", + "kiwa.mie.jp", + "komono.mie.jp", + "kumano.mie.jp", + "kuwana.mie.jp", + "matsusaka.mie.jp", + "meiwa.mie.jp", + "mihama.mie.jp", + "minamiise.mie.jp", + "misugi.mie.jp", + "miyama.mie.jp", + "nabari.mie.jp", + "shima.mie.jp", + "suzuka.mie.jp", + "tado.mie.jp", + "taiki.mie.jp", + "taki.mie.jp", + "tamaki.mie.jp", + "toba.mie.jp", + "tsu.mie.jp", + "udono.mie.jp", + "ureshino.mie.jp", + "watarai.mie.jp", + "yokkaichi.mie.jp", + "furukawa.miyagi.jp", + "higashimatsushima.miyagi.jp", + "ishinomaki.miyagi.jp", + "iwanuma.miyagi.jp", + "kakuda.miyagi.jp", + "kami.miyagi.jp", + "kawasaki.miyagi.jp", + "marumori.miyagi.jp", + "matsushima.miyagi.jp", + "minamisanriku.miyagi.jp", + "misato.miyagi.jp", + "murata.miyagi.jp", + "natori.miyagi.jp", + "ogawara.miyagi.jp", + "ohira.miyagi.jp", + "onagawa.miyagi.jp", + "osaki.miyagi.jp", + "rifu.miyagi.jp", + "semine.miyagi.jp", + "shibata.miyagi.jp", + "shichikashuku.miyagi.jp", + "shikama.miyagi.jp", + "shiogama.miyagi.jp", + "shiroishi.miyagi.jp", + "tagajo.miyagi.jp", + "taiwa.miyagi.jp", + "tome.miyagi.jp", + "tomiya.miyagi.jp", + "wakuya.miyagi.jp", + "watari.miyagi.jp", + "yamamoto.miyagi.jp", + "zao.miyagi.jp", + "aya.miyazaki.jp", + "ebino.miyazaki.jp", + "gokase.miyazaki.jp", + "hyuga.miyazaki.jp", + "kadogawa.miyazaki.jp", + "kawaminami.miyazaki.jp", + "kijo.miyazaki.jp", + "kitagawa.miyazaki.jp", + "kitakata.miyazaki.jp", + "kitaura.miyazaki.jp", + "kobayashi.miyazaki.jp", + "kunitomi.miyazaki.jp", + "kushima.miyazaki.jp", + "mimata.miyazaki.jp", + "miyakonojo.miyazaki.jp", + "miyazaki.miyazaki.jp", + "morotsuka.miyazaki.jp", + "nichinan.miyazaki.jp", + "nishimera.miyazaki.jp", + "nobeoka.miyazaki.jp", + "saito.miyazaki.jp", + "shiiba.miyazaki.jp", + "shintomi.miyazaki.jp", + "takaharu.miyazaki.jp", + "takanabe.miyazaki.jp", + "takazaki.miyazaki.jp", + "tsuno.miyazaki.jp", + "achi.nagano.jp", + "agematsu.nagano.jp", + "anan.nagano.jp", + "aoki.nagano.jp", + "asahi.nagano.jp", + "azumino.nagano.jp", + "chikuhoku.nagano.jp", + "chikuma.nagano.jp", + "chino.nagano.jp", + "fujimi.nagano.jp", + "hakuba.nagano.jp", + "hara.nagano.jp", + "hiraya.nagano.jp", + "iida.nagano.jp", + "iijima.nagano.jp", + "iiyama.nagano.jp", + "iizuna.nagano.jp", + "ikeda.nagano.jp", + "ikusaka.nagano.jp", + "ina.nagano.jp", + "karuizawa.nagano.jp", + "kawakami.nagano.jp", + "kiso.nagano.jp", + "kisofukushima.nagano.jp", + "kitaaiki.nagano.jp", + "komagane.nagano.jp", + "komoro.nagano.jp", + "matsukawa.nagano.jp", + "matsumoto.nagano.jp", + "miasa.nagano.jp", + "minamiaiki.nagano.jp", + "minamimaki.nagano.jp", + "minamiminowa.nagano.jp", + "minowa.nagano.jp", + "miyada.nagano.jp", + "miyota.nagano.jp", + "mochizuki.nagano.jp", + "nagano.nagano.jp", + "nagawa.nagano.jp", + "nagiso.nagano.jp", + "nakagawa.nagano.jp", + "nakano.nagano.jp", + "nozawaonsen.nagano.jp", + "obuse.nagano.jp", + "ogawa.nagano.jp", + "okaya.nagano.jp", + "omachi.nagano.jp", + "omi.nagano.jp", + "ookuwa.nagano.jp", + "ooshika.nagano.jp", + "otaki.nagano.jp", + "otari.nagano.jp", + "sakae.nagano.jp", + "sakaki.nagano.jp", + "saku.nagano.jp", + "sakuho.nagano.jp", + "shimosuwa.nagano.jp", + "shinanomachi.nagano.jp", + "shiojiri.nagano.jp", + "suwa.nagano.jp", + "suzaka.nagano.jp", + "takagi.nagano.jp", + "takamori.nagano.jp", + "takayama.nagano.jp", + "tateshina.nagano.jp", + "tatsuno.nagano.jp", + "togakushi.nagano.jp", + "togura.nagano.jp", + "tomi.nagano.jp", + "ueda.nagano.jp", + "wada.nagano.jp", + "yamagata.nagano.jp", + "yamanouchi.nagano.jp", + "yasaka.nagano.jp", + "yasuoka.nagano.jp", + "chijiwa.nagasaki.jp", + "futsu.nagasaki.jp", + "goto.nagasaki.jp", + "hasami.nagasaki.jp", + "hirado.nagasaki.jp", + "iki.nagasaki.jp", + "isahaya.nagasaki.jp", + "kawatana.nagasaki.jp", + "kuchinotsu.nagasaki.jp", + "matsuura.nagasaki.jp", + "nagasaki.nagasaki.jp", + "obama.nagasaki.jp", + "omura.nagasaki.jp", + "oseto.nagasaki.jp", + "saikai.nagasaki.jp", + "sasebo.nagasaki.jp", + "seihi.nagasaki.jp", + "shimabara.nagasaki.jp", + "shinkamigoto.nagasaki.jp", + "togitsu.nagasaki.jp", + "tsushima.nagasaki.jp", + "unzen.nagasaki.jp", + "ando.nara.jp", + "gose.nara.jp", + "heguri.nara.jp", + "higashiyoshino.nara.jp", + "ikaruga.nara.jp", + "ikoma.nara.jp", + "kamikitayama.nara.jp", + "kanmaki.nara.jp", + "kashiba.nara.jp", + "kashihara.nara.jp", + "katsuragi.nara.jp", + "kawai.nara.jp", + "kawakami.nara.jp", + "kawanishi.nara.jp", + "koryo.nara.jp", + "kurotaki.nara.jp", + "mitsue.nara.jp", + "miyake.nara.jp", + "nara.nara.jp", + "nosegawa.nara.jp", + "oji.nara.jp", + "ouda.nara.jp", + "oyodo.nara.jp", + "sakurai.nara.jp", + "sango.nara.jp", + "shimoichi.nara.jp", + "shimokitayama.nara.jp", + "shinjo.nara.jp", + "soni.nara.jp", + "takatori.nara.jp", + "tawaramoto.nara.jp", + "tenkawa.nara.jp", + "tenri.nara.jp", + "uda.nara.jp", + "yamatokoriyama.nara.jp", + "yamatotakada.nara.jp", + "yamazoe.nara.jp", + "yoshino.nara.jp", + "aga.niigata.jp", + "agano.niigata.jp", + "gosen.niigata.jp", + "itoigawa.niigata.jp", + "izumozaki.niigata.jp", + "joetsu.niigata.jp", + "kamo.niigata.jp", + "kariwa.niigata.jp", + "kashiwazaki.niigata.jp", + "minamiuonuma.niigata.jp", + "mitsuke.niigata.jp", + "muika.niigata.jp", + "murakami.niigata.jp", + "myoko.niigata.jp", + "nagaoka.niigata.jp", + "niigata.niigata.jp", + "ojiya.niigata.jp", + "omi.niigata.jp", + "sado.niigata.jp", + "sanjo.niigata.jp", + "seiro.niigata.jp", + "seirou.niigata.jp", + "sekikawa.niigata.jp", + "shibata.niigata.jp", + "tagami.niigata.jp", + "tainai.niigata.jp", + "tochio.niigata.jp", + "tokamachi.niigata.jp", + "tsubame.niigata.jp", + "tsunan.niigata.jp", + "uonuma.niigata.jp", + "yahiko.niigata.jp", + "yoita.niigata.jp", + "yuzawa.niigata.jp", + "beppu.oita.jp", + "bungoono.oita.jp", + "bungotakada.oita.jp", + "hasama.oita.jp", + "hiji.oita.jp", + "himeshima.oita.jp", + "hita.oita.jp", + "kamitsue.oita.jp", + "kokonoe.oita.jp", + "kuju.oita.jp", + "kunisaki.oita.jp", + "kusu.oita.jp", + "oita.oita.jp", + "saiki.oita.jp", + "taketa.oita.jp", + "tsukumi.oita.jp", + "usa.oita.jp", + "usuki.oita.jp", + "yufu.oita.jp", + "akaiwa.okayama.jp", + "asakuchi.okayama.jp", + "bizen.okayama.jp", + "hayashima.okayama.jp", + "ibara.okayama.jp", + "kagamino.okayama.jp", + "kasaoka.okayama.jp", + "kibichuo.okayama.jp", + "kumenan.okayama.jp", + "kurashiki.okayama.jp", + "maniwa.okayama.jp", + "misaki.okayama.jp", + "nagi.okayama.jp", + "niimi.okayama.jp", + "nishiawakura.okayama.jp", + "okayama.okayama.jp", + "satosho.okayama.jp", + "setouchi.okayama.jp", + "shinjo.okayama.jp", + "shoo.okayama.jp", + "soja.okayama.jp", + "takahashi.okayama.jp", + "tamano.okayama.jp", + "tsuyama.okayama.jp", + "wake.okayama.jp", + "yakage.okayama.jp", + "aguni.okinawa.jp", + "ginowan.okinawa.jp", + "ginoza.okinawa.jp", + "gushikami.okinawa.jp", + "haebaru.okinawa.jp", + "higashi.okinawa.jp", + "hirara.okinawa.jp", + "iheya.okinawa.jp", + "ishigaki.okinawa.jp", + "ishikawa.okinawa.jp", + "itoman.okinawa.jp", + "izena.okinawa.jp", + "kadena.okinawa.jp", + "kin.okinawa.jp", + "kitadaito.okinawa.jp", + "kitanakagusuku.okinawa.jp", + "kumejima.okinawa.jp", + "kunigami.okinawa.jp", + "minamidaito.okinawa.jp", + "motobu.okinawa.jp", + "nago.okinawa.jp", + "naha.okinawa.jp", + "nakagusuku.okinawa.jp", + "nakijin.okinawa.jp", + "nanjo.okinawa.jp", + "nishihara.okinawa.jp", + "ogimi.okinawa.jp", + "okinawa.okinawa.jp", + "onna.okinawa.jp", + "shimoji.okinawa.jp", + "taketomi.okinawa.jp", + "tarama.okinawa.jp", + "tokashiki.okinawa.jp", + "tomigusuku.okinawa.jp", + "tonaki.okinawa.jp", + "urasoe.okinawa.jp", + "uruma.okinawa.jp", + "yaese.okinawa.jp", + "yomitan.okinawa.jp", + "yonabaru.okinawa.jp", + "yonaguni.okinawa.jp", + "zamami.okinawa.jp", + "abeno.osaka.jp", + "chihayaakasaka.osaka.jp", + "chuo.osaka.jp", + "daito.osaka.jp", + "fujiidera.osaka.jp", + "habikino.osaka.jp", + "hannan.osaka.jp", + "higashiosaka.osaka.jp", + "higashisumiyoshi.osaka.jp", + "higashiyodogawa.osaka.jp", + "hirakata.osaka.jp", + "ibaraki.osaka.jp", + "ikeda.osaka.jp", + "izumi.osaka.jp", + "izumiotsu.osaka.jp", + "izumisano.osaka.jp", + "kadoma.osaka.jp", + "kaizuka.osaka.jp", + "kanan.osaka.jp", + "kashiwara.osaka.jp", + "katano.osaka.jp", + "kawachinagano.osaka.jp", + "kishiwada.osaka.jp", + "kita.osaka.jp", + "kumatori.osaka.jp", + "matsubara.osaka.jp", + "minato.osaka.jp", + "minoh.osaka.jp", + "misaki.osaka.jp", + "moriguchi.osaka.jp", + "neyagawa.osaka.jp", + "nishi.osaka.jp", + "nose.osaka.jp", + "osakasayama.osaka.jp", + "sakai.osaka.jp", + "sayama.osaka.jp", + "sennan.osaka.jp", + "settsu.osaka.jp", + "shijonawate.osaka.jp", + "shimamoto.osaka.jp", + "suita.osaka.jp", + "tadaoka.osaka.jp", + "taishi.osaka.jp", + "tajiri.osaka.jp", + "takaishi.osaka.jp", + "takatsuki.osaka.jp", + "tondabayashi.osaka.jp", + "toyonaka.osaka.jp", + "toyono.osaka.jp", + "yao.osaka.jp", + "ariake.saga.jp", + "arita.saga.jp", + "fukudomi.saga.jp", + "genkai.saga.jp", + "hamatama.saga.jp", + "hizen.saga.jp", + "imari.saga.jp", + "kamimine.saga.jp", + "kanzaki.saga.jp", + "karatsu.saga.jp", + "kashima.saga.jp", + "kitagata.saga.jp", + "kitahata.saga.jp", + "kiyama.saga.jp", + "kouhoku.saga.jp", + "kyuragi.saga.jp", + "nishiarita.saga.jp", + "ogi.saga.jp", + "omachi.saga.jp", + "ouchi.saga.jp", + "saga.saga.jp", + "shiroishi.saga.jp", + "taku.saga.jp", + "tara.saga.jp", + "tosu.saga.jp", + "yoshinogari.saga.jp", + "arakawa.saitama.jp", + "asaka.saitama.jp", + "chichibu.saitama.jp", + "fujimi.saitama.jp", + "fujimino.saitama.jp", + "fukaya.saitama.jp", + "hanno.saitama.jp", + "hanyu.saitama.jp", + "hasuda.saitama.jp", + "hatogaya.saitama.jp", + "hatoyama.saitama.jp", + "hidaka.saitama.jp", + "higashichichibu.saitama.jp", + "higashimatsuyama.saitama.jp", + "honjo.saitama.jp", + "ina.saitama.jp", + "iruma.saitama.jp", + "iwatsuki.saitama.jp", + "kamiizumi.saitama.jp", + "kamikawa.saitama.jp", + "kamisato.saitama.jp", + "kasukabe.saitama.jp", + "kawagoe.saitama.jp", + "kawaguchi.saitama.jp", + "kawajima.saitama.jp", + "kazo.saitama.jp", + "kitamoto.saitama.jp", + "koshigaya.saitama.jp", + "kounosu.saitama.jp", + "kuki.saitama.jp", + "kumagaya.saitama.jp", + "matsubushi.saitama.jp", + "minano.saitama.jp", + "misato.saitama.jp", + "miyashiro.saitama.jp", + "miyoshi.saitama.jp", + "moroyama.saitama.jp", + "nagatoro.saitama.jp", + "namegawa.saitama.jp", + "niiza.saitama.jp", + "ogano.saitama.jp", + "ogawa.saitama.jp", + "ogose.saitama.jp", + "okegawa.saitama.jp", + "omiya.saitama.jp", + "otaki.saitama.jp", + "ranzan.saitama.jp", + "ryokami.saitama.jp", + "saitama.saitama.jp", + "sakado.saitama.jp", + "satte.saitama.jp", + "sayama.saitama.jp", + "shiki.saitama.jp", + "shiraoka.saitama.jp", + "soka.saitama.jp", + "sugito.saitama.jp", + "toda.saitama.jp", + "tokigawa.saitama.jp", + "tokorozawa.saitama.jp", + "tsurugashima.saitama.jp", + "urawa.saitama.jp", + "warabi.saitama.jp", + "yashio.saitama.jp", + "yokoze.saitama.jp", + "yono.saitama.jp", + "yorii.saitama.jp", + "yoshida.saitama.jp", + "yoshikawa.saitama.jp", + "yoshimi.saitama.jp", + "aisho.shiga.jp", + "gamo.shiga.jp", + "higashiomi.shiga.jp", + "hikone.shiga.jp", + "koka.shiga.jp", + "konan.shiga.jp", + "kosei.shiga.jp", + "koto.shiga.jp", + "kusatsu.shiga.jp", + "maibara.shiga.jp", + "moriyama.shiga.jp", + "nagahama.shiga.jp", + "nishiazai.shiga.jp", + "notogawa.shiga.jp", + "omihachiman.shiga.jp", + "otsu.shiga.jp", + "ritto.shiga.jp", + "ryuoh.shiga.jp", + "takashima.shiga.jp", + "takatsuki.shiga.jp", + "torahime.shiga.jp", + "toyosato.shiga.jp", + "yasu.shiga.jp", + "akagi.shimane.jp", + "ama.shimane.jp", + "gotsu.shimane.jp", + "hamada.shimane.jp", + "higashiizumo.shimane.jp", + "hikawa.shimane.jp", + "hikimi.shimane.jp", + "izumo.shimane.jp", + "kakinoki.shimane.jp", + "masuda.shimane.jp", + "matsue.shimane.jp", + "misato.shimane.jp", + "nishinoshima.shimane.jp", + "ohda.shimane.jp", + "okinoshima.shimane.jp", + "okuizumo.shimane.jp", + "shimane.shimane.jp", + "tamayu.shimane.jp", + "tsuwano.shimane.jp", + "unnan.shimane.jp", + "yakumo.shimane.jp", + "yasugi.shimane.jp", + "yatsuka.shimane.jp", + "arai.shizuoka.jp", + "atami.shizuoka.jp", + "fuji.shizuoka.jp", + "fujieda.shizuoka.jp", + "fujikawa.shizuoka.jp", + "fujinomiya.shizuoka.jp", + "fukuroi.shizuoka.jp", + "gotemba.shizuoka.jp", + "haibara.shizuoka.jp", + "hamamatsu.shizuoka.jp", + "higashiizu.shizuoka.jp", + "ito.shizuoka.jp", + "iwata.shizuoka.jp", + "izu.shizuoka.jp", + "izunokuni.shizuoka.jp", + "kakegawa.shizuoka.jp", + "kannami.shizuoka.jp", + "kawanehon.shizuoka.jp", + "kawazu.shizuoka.jp", + "kikugawa.shizuoka.jp", + "kosai.shizuoka.jp", + "makinohara.shizuoka.jp", + "matsuzaki.shizuoka.jp", + "minamiizu.shizuoka.jp", + "mishima.shizuoka.jp", + "morimachi.shizuoka.jp", + "nishiizu.shizuoka.jp", + "numazu.shizuoka.jp", + "omaezaki.shizuoka.jp", + "shimada.shizuoka.jp", + "shimizu.shizuoka.jp", + "shimoda.shizuoka.jp", + "shizuoka.shizuoka.jp", + "susono.shizuoka.jp", + "yaizu.shizuoka.jp", + "yoshida.shizuoka.jp", + "ashikaga.tochigi.jp", + "bato.tochigi.jp", + "haga.tochigi.jp", + "ichikai.tochigi.jp", + "iwafune.tochigi.jp", + "kaminokawa.tochigi.jp", + "kanuma.tochigi.jp", + "karasuyama.tochigi.jp", + "kuroiso.tochigi.jp", + "mashiko.tochigi.jp", + "mibu.tochigi.jp", + "moka.tochigi.jp", + "motegi.tochigi.jp", + "nasu.tochigi.jp", + "nasushiobara.tochigi.jp", + "nikko.tochigi.jp", + "nishikata.tochigi.jp", + "nogi.tochigi.jp", + "ohira.tochigi.jp", + "ohtawara.tochigi.jp", + "oyama.tochigi.jp", + "sakura.tochigi.jp", + "sano.tochigi.jp", + "shimotsuke.tochigi.jp", + "shioya.tochigi.jp", + "takanezawa.tochigi.jp", + "tochigi.tochigi.jp", + "tsuga.tochigi.jp", + "ujiie.tochigi.jp", + "utsunomiya.tochigi.jp", + "yaita.tochigi.jp", + "aizumi.tokushima.jp", + "anan.tokushima.jp", + "ichiba.tokushima.jp", + "itano.tokushima.jp", + "kainan.tokushima.jp", + "komatsushima.tokushima.jp", + "matsushige.tokushima.jp", + "mima.tokushima.jp", + "minami.tokushima.jp", + "miyoshi.tokushima.jp", + "mugi.tokushima.jp", + "nakagawa.tokushima.jp", + "naruto.tokushima.jp", + "sanagochi.tokushima.jp", + "shishikui.tokushima.jp", + "tokushima.tokushima.jp", + "wajiki.tokushima.jp", + "adachi.tokyo.jp", + "akiruno.tokyo.jp", + "akishima.tokyo.jp", + "aogashima.tokyo.jp", + "arakawa.tokyo.jp", + "bunkyo.tokyo.jp", + "chiyoda.tokyo.jp", + "chofu.tokyo.jp", + "chuo.tokyo.jp", + "edogawa.tokyo.jp", + "fuchu.tokyo.jp", + "fussa.tokyo.jp", + "hachijo.tokyo.jp", + "hachioji.tokyo.jp", + "hamura.tokyo.jp", + "higashikurume.tokyo.jp", + "higashimurayama.tokyo.jp", + "higashiyamato.tokyo.jp", + "hino.tokyo.jp", + "hinode.tokyo.jp", + "hinohara.tokyo.jp", + "inagi.tokyo.jp", + "itabashi.tokyo.jp", + "katsushika.tokyo.jp", + "kita.tokyo.jp", + "kiyose.tokyo.jp", + "kodaira.tokyo.jp", + "koganei.tokyo.jp", + "kokubunji.tokyo.jp", + "komae.tokyo.jp", + "koto.tokyo.jp", + "kouzushima.tokyo.jp", + "kunitachi.tokyo.jp", + "machida.tokyo.jp", + "meguro.tokyo.jp", + "minato.tokyo.jp", + "mitaka.tokyo.jp", + "mizuho.tokyo.jp", + "musashimurayama.tokyo.jp", + "musashino.tokyo.jp", + "nakano.tokyo.jp", + "nerima.tokyo.jp", + "ogasawara.tokyo.jp", + "okutama.tokyo.jp", + "ome.tokyo.jp", + "oshima.tokyo.jp", + "ota.tokyo.jp", + "setagaya.tokyo.jp", + "shibuya.tokyo.jp", + "shinagawa.tokyo.jp", + "shinjuku.tokyo.jp", + "suginami.tokyo.jp", + "sumida.tokyo.jp", + "tachikawa.tokyo.jp", + "taito.tokyo.jp", + "tama.tokyo.jp", + "toshima.tokyo.jp", + "chizu.tottori.jp", + "hino.tottori.jp", + "kawahara.tottori.jp", + "koge.tottori.jp", + "kotoura.tottori.jp", + "misasa.tottori.jp", + "nanbu.tottori.jp", + "nichinan.tottori.jp", + "sakaiminato.tottori.jp", + "tottori.tottori.jp", + "wakasa.tottori.jp", + "yazu.tottori.jp", + "yonago.tottori.jp", + "asahi.toyama.jp", + "fuchu.toyama.jp", + "fukumitsu.toyama.jp", + "funahashi.toyama.jp", + "himi.toyama.jp", + "imizu.toyama.jp", + "inami.toyama.jp", + "johana.toyama.jp", + "kamiichi.toyama.jp", + "kurobe.toyama.jp", + "nakaniikawa.toyama.jp", + "namerikawa.toyama.jp", + "nanto.toyama.jp", + "nyuzen.toyama.jp", + "oyabe.toyama.jp", + "taira.toyama.jp", + "takaoka.toyama.jp", + "tateyama.toyama.jp", + "toga.toyama.jp", + "tonami.toyama.jp", + "toyama.toyama.jp", + "unazuki.toyama.jp", + "uozu.toyama.jp", + "yamada.toyama.jp", + "arida.wakayama.jp", + "aridagawa.wakayama.jp", + "gobo.wakayama.jp", + "hashimoto.wakayama.jp", + "hidaka.wakayama.jp", + "hirogawa.wakayama.jp", + "inami.wakayama.jp", + "iwade.wakayama.jp", + "kainan.wakayama.jp", + "kamitonda.wakayama.jp", + "katsuragi.wakayama.jp", + "kimino.wakayama.jp", + "kinokawa.wakayama.jp", + "kitayama.wakayama.jp", + "koya.wakayama.jp", + "koza.wakayama.jp", + "kozagawa.wakayama.jp", + "kudoyama.wakayama.jp", + "kushimoto.wakayama.jp", + "mihama.wakayama.jp", + "misato.wakayama.jp", + "nachikatsuura.wakayama.jp", + "shingu.wakayama.jp", + "shirahama.wakayama.jp", + "taiji.wakayama.jp", + "tanabe.wakayama.jp", + "wakayama.wakayama.jp", + "yuasa.wakayama.jp", + "yura.wakayama.jp", + "asahi.yamagata.jp", + "funagata.yamagata.jp", + "higashine.yamagata.jp", + "iide.yamagata.jp", + "kahoku.yamagata.jp", + "kaminoyama.yamagata.jp", + "kaneyama.yamagata.jp", + "kawanishi.yamagata.jp", + "mamurogawa.yamagata.jp", + "mikawa.yamagata.jp", + "murayama.yamagata.jp", + "nagai.yamagata.jp", + "nakayama.yamagata.jp", + "nanyo.yamagata.jp", + "nishikawa.yamagata.jp", + "obanazawa.yamagata.jp", + "oe.yamagata.jp", + "oguni.yamagata.jp", + "ohkura.yamagata.jp", + "oishida.yamagata.jp", + "sagae.yamagata.jp", + "sakata.yamagata.jp", + "sakegawa.yamagata.jp", + "shinjo.yamagata.jp", + "shirataka.yamagata.jp", + "shonai.yamagata.jp", + "takahata.yamagata.jp", + "tendo.yamagata.jp", + "tozawa.yamagata.jp", + "tsuruoka.yamagata.jp", + "yamagata.yamagata.jp", + "yamanobe.yamagata.jp", + "yonezawa.yamagata.jp", + "yuza.yamagata.jp", + "abu.yamaguchi.jp", + "hagi.yamaguchi.jp", + "hikari.yamaguchi.jp", + "hofu.yamaguchi.jp", + "iwakuni.yamaguchi.jp", + "kudamatsu.yamaguchi.jp", + "mitou.yamaguchi.jp", + "nagato.yamaguchi.jp", + "oshima.yamaguchi.jp", + "shimonoseki.yamaguchi.jp", + "shunan.yamaguchi.jp", + "tabuse.yamaguchi.jp", + "tokuyama.yamaguchi.jp", + "toyota.yamaguchi.jp", + "ube.yamaguchi.jp", + "yuu.yamaguchi.jp", + "chuo.yamanashi.jp", + "doshi.yamanashi.jp", + "fuefuki.yamanashi.jp", + "fujikawa.yamanashi.jp", + "fujikawaguchiko.yamanashi.jp", + "fujiyoshida.yamanashi.jp", + "hayakawa.yamanashi.jp", + "hokuto.yamanashi.jp", + "ichikawamisato.yamanashi.jp", + "kai.yamanashi.jp", + "kofu.yamanashi.jp", + "koshu.yamanashi.jp", + "kosuge.yamanashi.jp", + "minami-alps.yamanashi.jp", + "minobu.yamanashi.jp", + "nakamichi.yamanashi.jp", + "nanbu.yamanashi.jp", + "narusawa.yamanashi.jp", + "nirasaki.yamanashi.jp", + "nishikatsura.yamanashi.jp", + "oshino.yamanashi.jp", + "otsuki.yamanashi.jp", + "showa.yamanashi.jp", + "tabayama.yamanashi.jp", + "tsuru.yamanashi.jp", + "uenohara.yamanashi.jp", + "yamanakako.yamanashi.jp", + "yamanashi.yamanashi.jp", + "ke", + "ac.ke", + "co.ke", + "go.ke", + "info.ke", + "me.ke", + "mobi.ke", + "ne.ke", + "or.ke", + "sc.ke", + "kg", + "org.kg", + "net.kg", + "com.kg", + "edu.kg", + "gov.kg", + "mil.kg", + "*.kh", + "ki", + "edu.ki", + "biz.ki", + "net.ki", + "org.ki", + "gov.ki", + "info.ki", + "com.ki", + "km", + "org.km", + "nom.km", + "gov.km", + "prd.km", + "tm.km", + "edu.km", + "mil.km", + "ass.km", + "com.km", + "coop.km", + "asso.km", + "presse.km", + "medecin.km", + "notaires.km", + "pharmaciens.km", + "veterinaire.km", + "gouv.km", + "kn", + "net.kn", + "org.kn", + "edu.kn", + "gov.kn", + "kp", + "com.kp", + "edu.kp", + "gov.kp", + "org.kp", + "rep.kp", + "tra.kp", + "kr", + "ac.kr", + "co.kr", + "es.kr", + "go.kr", + "hs.kr", + "kg.kr", + "mil.kr", + "ms.kr", + "ne.kr", + "or.kr", + "pe.kr", + "re.kr", + "sc.kr", + "busan.kr", + "chungbuk.kr", + "chungnam.kr", + "daegu.kr", + "daejeon.kr", + "gangwon.kr", + "gwangju.kr", + "gyeongbuk.kr", + "gyeonggi.kr", + "gyeongnam.kr", + "incheon.kr", + "jeju.kr", + "jeonbuk.kr", + "jeonnam.kr", + "seoul.kr", + "ulsan.kr", + "kw", + "com.kw", + "edu.kw", + "emb.kw", + "gov.kw", + "ind.kw", + "net.kw", + "org.kw", + "ky", + "com.ky", + "edu.ky", + "net.ky", + "org.ky", + "kz", + "org.kz", + "edu.kz", + "net.kz", + "gov.kz", + "mil.kz", + "com.kz", + "la", + "int.la", + "net.la", + "info.la", + "edu.la", + "gov.la", + "per.la", + "com.la", + "org.la", + "lb", + "com.lb", + "edu.lb", + "gov.lb", + "net.lb", + "org.lb", + "lc", + "com.lc", + "net.lc", + "co.lc", + "org.lc", + "edu.lc", + "gov.lc", + "li", + "lk", + "gov.lk", + "sch.lk", + "net.lk", + "int.lk", + "com.lk", + "org.lk", + "edu.lk", + "ngo.lk", + "soc.lk", + "web.lk", + "ltd.lk", + "assn.lk", + "grp.lk", + "hotel.lk", + "ac.lk", + "lr", + "com.lr", + "edu.lr", + "gov.lr", + "org.lr", + "net.lr", + "ls", + "ac.ls", + "biz.ls", + "co.ls", + "edu.ls", + "gov.ls", + "info.ls", + "net.ls", + "org.ls", + "sc.ls", + "lt", + "gov.lt", + "lu", + "lv", + "com.lv", + "edu.lv", + "gov.lv", + "org.lv", + "mil.lv", + "id.lv", + "net.lv", + "asn.lv", + "conf.lv", + "ly", + "com.ly", + "net.ly", + "gov.ly", + "plc.ly", + "edu.ly", + "sch.ly", + "med.ly", + "org.ly", + "id.ly", + "ma", + "co.ma", + "net.ma", + "gov.ma", + "org.ma", + "ac.ma", + "press.ma", + "mc", + "tm.mc", + "asso.mc", + "md", + "me", + "co.me", + "net.me", + "org.me", + "edu.me", + "ac.me", + "gov.me", + "its.me", + "priv.me", + "mg", + "org.mg", + "nom.mg", + "gov.mg", + "prd.mg", + "tm.mg", + "edu.mg", + "mil.mg", + "com.mg", + "co.mg", + "mh", + "mil", + "mk", + "com.mk", + "org.mk", + "net.mk", + "edu.mk", + "gov.mk", + "inf.mk", + "name.mk", + "ml", + "com.ml", + "edu.ml", + "gouv.ml", + "gov.ml", + "net.ml", + "org.ml", + "presse.ml", + "*.mm", + "mn", + "gov.mn", + "edu.mn", + "org.mn", + "mo", + "com.mo", + "net.mo", + "org.mo", + "edu.mo", + "gov.mo", + "mobi", + "mp", + "mq", + "mr", + "gov.mr", + "ms", + "com.ms", + "edu.ms", + "gov.ms", + "net.ms", + "org.ms", + "mt", + "com.mt", + "edu.mt", + "net.mt", + "org.mt", + "mu", + "com.mu", + "net.mu", + "org.mu", + "gov.mu", + "ac.mu", + "co.mu", + "or.mu", + "museum", + "academy.museum", + "agriculture.museum", + "air.museum", + "airguard.museum", + "alabama.museum", + "alaska.museum", + "amber.museum", + "ambulance.museum", + "american.museum", + "americana.museum", + "americanantiques.museum", + "americanart.museum", + "amsterdam.museum", + "and.museum", + "annefrank.museum", + "anthro.museum", + "anthropology.museum", + "antiques.museum", + "aquarium.museum", + "arboretum.museum", + "archaeological.museum", + "archaeology.museum", + "architecture.museum", + "art.museum", + "artanddesign.museum", + "artcenter.museum", + "artdeco.museum", + "arteducation.museum", + "artgallery.museum", + "arts.museum", + "artsandcrafts.museum", + "asmatart.museum", + "assassination.museum", + "assisi.museum", + "association.museum", + "astronomy.museum", + "atlanta.museum", + "austin.museum", + "australia.museum", + "automotive.museum", + "aviation.museum", + "axis.museum", + "badajoz.museum", + "baghdad.museum", + "bahn.museum", + "bale.museum", + "baltimore.museum", + "barcelona.museum", + "baseball.museum", + "basel.museum", + "baths.museum", + "bauern.museum", + "beauxarts.museum", + "beeldengeluid.museum", + "bellevue.museum", + "bergbau.museum", + "berkeley.museum", + "berlin.museum", + "bern.museum", + "bible.museum", + "bilbao.museum", + "bill.museum", + "birdart.museum", + "birthplace.museum", + "bonn.museum", + "boston.museum", + "botanical.museum", + "botanicalgarden.museum", + "botanicgarden.museum", + "botany.museum", + "brandywinevalley.museum", + "brasil.museum", + "bristol.museum", + "british.museum", + "britishcolumbia.museum", + "broadcast.museum", + "brunel.museum", + "brussel.museum", + "brussels.museum", + "bruxelles.museum", + "building.museum", + "burghof.museum", + "bus.museum", + "bushey.museum", + "cadaques.museum", + "california.museum", + "cambridge.museum", + "can.museum", + "canada.museum", + "capebreton.museum", + "carrier.museum", + "cartoonart.museum", + "casadelamoneda.museum", + "castle.museum", + "castres.museum", + "celtic.museum", + "center.museum", + "chattanooga.museum", + "cheltenham.museum", + "chesapeakebay.museum", + "chicago.museum", + "children.museum", + "childrens.museum", + "childrensgarden.museum", + "chiropractic.museum", + "chocolate.museum", + "christiansburg.museum", + "cincinnati.museum", + "cinema.museum", + "circus.museum", + "civilisation.museum", + "civilization.museum", + "civilwar.museum", + "clinton.museum", + "clock.museum", + "coal.museum", + "coastaldefence.museum", + "cody.museum", + "coldwar.museum", + "collection.museum", + "colonialwilliamsburg.museum", + "coloradoplateau.museum", + "columbia.museum", + "columbus.museum", + "communication.museum", + "communications.museum", + "community.museum", + "computer.museum", + "computerhistory.museum", + "comunica\xE7\xF5es.museum", + "contemporary.museum", + "contemporaryart.museum", + "convent.museum", + "copenhagen.museum", + "corporation.museum", + "correios-e-telecomunica\xE7\xF5es.museum", + "corvette.museum", + "costume.museum", + "countryestate.museum", + "county.museum", + "crafts.museum", + "cranbrook.museum", + "creation.museum", + "cultural.museum", + "culturalcenter.museum", + "culture.museum", + "cyber.museum", + "cymru.museum", + "dali.museum", + "dallas.museum", + "database.museum", + "ddr.museum", + "decorativearts.museum", + "delaware.museum", + "delmenhorst.museum", + "denmark.museum", + "depot.museum", + "design.museum", + "detroit.museum", + "dinosaur.museum", + "discovery.museum", + "dolls.museum", + "donostia.museum", + "durham.museum", + "eastafrica.museum", + "eastcoast.museum", + "education.museum", + "educational.museum", + "egyptian.museum", + "eisenbahn.museum", + "elburg.museum", + "elvendrell.museum", + "embroidery.museum", + "encyclopedic.museum", + "england.museum", + "entomology.museum", + "environment.museum", + "environmentalconservation.museum", + "epilepsy.museum", + "essex.museum", + "estate.museum", + "ethnology.museum", + "exeter.museum", + "exhibition.museum", + "family.museum", + "farm.museum", + "farmequipment.museum", + "farmers.museum", + "farmstead.museum", + "field.museum", + "figueres.museum", + "filatelia.museum", + "film.museum", + "fineart.museum", + "finearts.museum", + "finland.museum", + "flanders.museum", + "florida.museum", + "force.museum", + "fortmissoula.museum", + "fortworth.museum", + "foundation.museum", + "francaise.museum", + "frankfurt.museum", + "franziskaner.museum", + "freemasonry.museum", + "freiburg.museum", + "fribourg.museum", + "frog.museum", + "fundacio.museum", + "furniture.museum", + "gallery.museum", + "garden.museum", + "gateway.museum", + "geelvinck.museum", + "gemological.museum", + "geology.museum", + "georgia.museum", + "giessen.museum", + "glas.museum", + "glass.museum", + "gorge.museum", + "grandrapids.museum", + "graz.museum", + "guernsey.museum", + "halloffame.museum", + "hamburg.museum", + "handson.museum", + "harvestcelebration.museum", + "hawaii.museum", + "health.museum", + "heimatunduhren.museum", + "hellas.museum", + "helsinki.museum", + "hembygdsforbund.museum", + "heritage.museum", + "histoire.museum", + "historical.museum", + "historicalsociety.museum", + "historichouses.museum", + "historisch.museum", + "historisches.museum", + "history.museum", + "historyofscience.museum", + "horology.museum", + "house.museum", + "humanities.museum", + "illustration.museum", + "imageandsound.museum", + "indian.museum", + "indiana.museum", + "indianapolis.museum", + "indianmarket.museum", + "intelligence.museum", + "interactive.museum", + "iraq.museum", + "iron.museum", + "isleofman.museum", + "jamison.museum", + "jefferson.museum", + "jerusalem.museum", + "jewelry.museum", + "jewish.museum", + "jewishart.museum", + "jfk.museum", + "journalism.museum", + "judaica.museum", + "judygarland.museum", + "juedisches.museum", + "juif.museum", + "karate.museum", + "karikatur.museum", + "kids.museum", + "koebenhavn.museum", + "koeln.museum", + "kunst.museum", + "kunstsammlung.museum", + "kunstunddesign.museum", + "labor.museum", + "labour.museum", + "lajolla.museum", + "lancashire.museum", + "landes.museum", + "lans.museum", + "l\xE4ns.museum", + "larsson.museum", + "lewismiller.museum", + "lincoln.museum", + "linz.museum", + "living.museum", + "livinghistory.museum", + "localhistory.museum", + "london.museum", + "losangeles.museum", + "louvre.museum", + "loyalist.museum", + "lucerne.museum", + "luxembourg.museum", + "luzern.museum", + "mad.museum", + "madrid.museum", + "mallorca.museum", + "manchester.museum", + "mansion.museum", + "mansions.museum", + "manx.museum", + "marburg.museum", + "maritime.museum", + "maritimo.museum", + "maryland.museum", + "marylhurst.museum", + "media.museum", + "medical.museum", + "medizinhistorisches.museum", + "meeres.museum", + "memorial.museum", + "mesaverde.museum", + "michigan.museum", + "midatlantic.museum", + "military.museum", + "mill.museum", + "miners.museum", + "mining.museum", + "minnesota.museum", + "missile.museum", + "missoula.museum", + "modern.museum", + "moma.museum", + "money.museum", + "monmouth.museum", + "monticello.museum", + "montreal.museum", + "moscow.museum", + "motorcycle.museum", + "muenchen.museum", + "muenster.museum", + "mulhouse.museum", + "muncie.museum", + "museet.museum", + "museumcenter.museum", + "museumvereniging.museum", + "music.museum", + "national.museum", + "nationalfirearms.museum", + "nationalheritage.museum", + "nativeamerican.museum", + "naturalhistory.museum", + "naturalhistorymuseum.museum", + "naturalsciences.museum", + "nature.museum", + "naturhistorisches.museum", + "natuurwetenschappen.museum", + "naumburg.museum", + "naval.museum", + "nebraska.museum", + "neues.museum", + "newhampshire.museum", + "newjersey.museum", + "newmexico.museum", + "newport.museum", + "newspaper.museum", + "newyork.museum", + "niepce.museum", + "norfolk.museum", + "north.museum", + "nrw.museum", + "nyc.museum", + "nyny.museum", + "oceanographic.museum", + "oceanographique.museum", + "omaha.museum", + "online.museum", + "ontario.museum", + "openair.museum", + "oregon.museum", + "oregontrail.museum", + "otago.museum", + "oxford.museum", + "pacific.museum", + "paderborn.museum", + "palace.museum", + "paleo.museum", + "palmsprings.museum", + "panama.museum", + "paris.museum", + "pasadena.museum", + "pharmacy.museum", + "philadelphia.museum", + "philadelphiaarea.museum", + "philately.museum", + "phoenix.museum", + "photography.museum", + "pilots.museum", + "pittsburgh.museum", + "planetarium.museum", + "plantation.museum", + "plants.museum", + "plaza.museum", + "portal.museum", + "portland.museum", + "portlligat.museum", + "posts-and-telecommunications.museum", + "preservation.museum", + "presidio.museum", + "press.museum", + "project.museum", + "public.museum", + "pubol.museum", + "quebec.museum", + "railroad.museum", + "railway.museum", + "research.museum", + "resistance.museum", + "riodejaneiro.museum", + "rochester.museum", + "rockart.museum", + "roma.museum", + "russia.museum", + "saintlouis.museum", + "salem.museum", + "salvadordali.museum", + "salzburg.museum", + "sandiego.museum", + "sanfrancisco.museum", + "santabarbara.museum", + "santacruz.museum", + "santafe.museum", + "saskatchewan.museum", + "satx.museum", + "savannahga.museum", + "schlesisches.museum", + "schoenbrunn.museum", + "schokoladen.museum", + "school.museum", + "schweiz.museum", + "science.museum", + "scienceandhistory.museum", + "scienceandindustry.museum", + "sciencecenter.museum", + "sciencecenters.museum", + "science-fiction.museum", + "sciencehistory.museum", + "sciences.museum", + "sciencesnaturelles.museum", + "scotland.museum", + "seaport.museum", + "settlement.museum", + "settlers.museum", + "shell.museum", + "sherbrooke.museum", + "sibenik.museum", + "silk.museum", + "ski.museum", + "skole.museum", + "society.museum", + "sologne.museum", + "soundandvision.museum", + "southcarolina.museum", + "southwest.museum", + "space.museum", + "spy.museum", + "square.museum", + "stadt.museum", + "stalbans.museum", + "starnberg.museum", + "state.museum", + "stateofdelaware.museum", + "station.museum", + "steam.museum", + "steiermark.museum", + "stjohn.museum", + "stockholm.museum", + "stpetersburg.museum", + "stuttgart.museum", + "suisse.museum", + "surgeonshall.museum", + "surrey.museum", + "svizzera.museum", + "sweden.museum", + "sydney.museum", + "tank.museum", + "tcm.museum", + "technology.museum", + "telekommunikation.museum", + "television.museum", + "texas.museum", + "textile.museum", + "theater.museum", + "time.museum", + "timekeeping.museum", + "topology.museum", + "torino.museum", + "touch.museum", + "town.museum", + "transport.museum", + "tree.museum", + "trolley.museum", + "trust.museum", + "trustee.museum", + "uhren.museum", + "ulm.museum", + "undersea.museum", + "university.museum", + "usa.museum", + "usantiques.museum", + "usarts.museum", + "uscountryestate.museum", + "usculture.museum", + "usdecorativearts.museum", + "usgarden.museum", + "ushistory.museum", + "ushuaia.museum", + "uslivinghistory.museum", + "utah.museum", + "uvic.museum", + "valley.museum", + "vantaa.museum", + "versailles.museum", + "viking.museum", + "village.museum", + "virginia.museum", + "virtual.museum", + "virtuel.museum", + "vlaanderen.museum", + "volkenkunde.museum", + "wales.museum", + "wallonie.museum", + "war.museum", + "washingtondc.museum", + "watchandclock.museum", + "watch-and-clock.museum", + "western.museum", + "westfalen.museum", + "whaling.museum", + "wildlife.museum", + "williamsburg.museum", + "windmill.museum", + "workshop.museum", + "york.museum", + "yorkshire.museum", + "yosemite.museum", + "youth.museum", + "zoological.museum", + "zoology.museum", + "\u05D9\u05E8\u05D5\u05E9\u05DC\u05D9\u05DD.museum", + "\u0438\u043A\u043E\u043C.museum", + "mv", + "aero.mv", + "biz.mv", + "com.mv", + "coop.mv", + "edu.mv", + "gov.mv", + "info.mv", + "int.mv", + "mil.mv", + "museum.mv", + "name.mv", + "net.mv", + "org.mv", + "pro.mv", + "mw", + "ac.mw", + "biz.mw", + "co.mw", + "com.mw", + "coop.mw", + "edu.mw", + "gov.mw", + "int.mw", + "museum.mw", + "net.mw", + "org.mw", + "mx", + "com.mx", + "org.mx", + "gob.mx", + "edu.mx", + "net.mx", + "my", + "biz.my", + "com.my", + "edu.my", + "gov.my", + "mil.my", + "name.my", + "net.my", + "org.my", + "mz", + "ac.mz", + "adv.mz", + "co.mz", + "edu.mz", + "gov.mz", + "mil.mz", + "net.mz", + "org.mz", + "na", + "info.na", + "pro.na", + "name.na", + "school.na", + "or.na", + "dr.na", + "us.na", + "mx.na", + "ca.na", + "in.na", + "cc.na", + "tv.na", + "ws.na", + "mobi.na", + "co.na", + "com.na", + "org.na", + "name", + "nc", + "asso.nc", + "nom.nc", + "ne", + "net", + "nf", + "com.nf", + "net.nf", + "per.nf", + "rec.nf", + "web.nf", + "arts.nf", + "firm.nf", + "info.nf", + "other.nf", + "store.nf", + "ng", + "com.ng", + "edu.ng", + "gov.ng", + "i.ng", + "mil.ng", + "mobi.ng", + "name.ng", + "net.ng", + "org.ng", + "sch.ng", + "ni", + "ac.ni", + "biz.ni", + "co.ni", + "com.ni", + "edu.ni", + "gob.ni", + "in.ni", + "info.ni", + "int.ni", + "mil.ni", + "net.ni", + "nom.ni", + "org.ni", + "web.ni", + "nl", + "no", + "fhs.no", + "vgs.no", + "fylkesbibl.no", + "folkebibl.no", + "museum.no", + "idrett.no", + "priv.no", + "mil.no", + "stat.no", + "dep.no", + "kommune.no", + "herad.no", + "aa.no", + "ah.no", + "bu.no", + "fm.no", + "hl.no", + "hm.no", + "jan-mayen.no", + "mr.no", + "nl.no", + "nt.no", + "of.no", + "ol.no", + "oslo.no", + "rl.no", + "sf.no", + "st.no", + "svalbard.no", + "tm.no", + "tr.no", + "va.no", + "vf.no", + "gs.aa.no", + "gs.ah.no", + "gs.bu.no", + "gs.fm.no", + "gs.hl.no", + "gs.hm.no", + "gs.jan-mayen.no", + "gs.mr.no", + "gs.nl.no", + "gs.nt.no", + "gs.of.no", + "gs.ol.no", + "gs.oslo.no", + "gs.rl.no", + "gs.sf.no", + "gs.st.no", + "gs.svalbard.no", + "gs.tm.no", + "gs.tr.no", + "gs.va.no", + "gs.vf.no", + "akrehamn.no", + "\xE5krehamn.no", + "algard.no", + "\xE5lg\xE5rd.no", + "arna.no", + "brumunddal.no", + "bryne.no", + "bronnoysund.no", + "br\xF8nn\xF8ysund.no", + "drobak.no", + "dr\xF8bak.no", + "egersund.no", + "fetsund.no", + "floro.no", + "flor\xF8.no", + "fredrikstad.no", + "hokksund.no", + "honefoss.no", + "h\xF8nefoss.no", + "jessheim.no", + "jorpeland.no", + "j\xF8rpeland.no", + "kirkenes.no", + "kopervik.no", + "krokstadelva.no", + "langevag.no", + "langev\xE5g.no", + "leirvik.no", + "mjondalen.no", + "mj\xF8ndalen.no", + "mo-i-rana.no", + "mosjoen.no", + "mosj\xF8en.no", + "nesoddtangen.no", + "orkanger.no", + "osoyro.no", + "os\xF8yro.no", + "raholt.no", + "r\xE5holt.no", + "sandnessjoen.no", + "sandnessj\xF8en.no", + "skedsmokorset.no", + "slattum.no", + "spjelkavik.no", + "stathelle.no", + "stavern.no", + "stjordalshalsen.no", + "stj\xF8rdalshalsen.no", + "tananger.no", + "tranby.no", + "vossevangen.no", + "afjord.no", + "\xE5fjord.no", + "agdenes.no", + "al.no", + "\xE5l.no", + "alesund.no", + "\xE5lesund.no", + "alstahaug.no", + "alta.no", + "\xE1lt\xE1.no", + "alaheadju.no", + "\xE1laheadju.no", + "alvdal.no", + "amli.no", + "\xE5mli.no", + "amot.no", + "\xE5mot.no", + "andebu.no", + "andoy.no", + "and\xF8y.no", + "andasuolo.no", + "ardal.no", + "\xE5rdal.no", + "aremark.no", + "arendal.no", + "\xE5s.no", + "aseral.no", + "\xE5seral.no", + "asker.no", + "askim.no", + "askvoll.no", + "askoy.no", + "ask\xF8y.no", + "asnes.no", + "\xE5snes.no", + "audnedaln.no", + "aukra.no", + "aure.no", + "aurland.no", + "aurskog-holand.no", + "aurskog-h\xF8land.no", + "austevoll.no", + "austrheim.no", + "averoy.no", + "aver\xF8y.no", + "balestrand.no", + "ballangen.no", + "balat.no", + "b\xE1l\xE1t.no", + "balsfjord.no", + "bahccavuotna.no", + "b\xE1hccavuotna.no", + "bamble.no", + "bardu.no", + "beardu.no", + "beiarn.no", + "bajddar.no", + "b\xE1jddar.no", + "baidar.no", + "b\xE1id\xE1r.no", + "berg.no", + "bergen.no", + "berlevag.no", + "berlev\xE5g.no", + "bearalvahki.no", + "bearalv\xE1hki.no", + "bindal.no", + "birkenes.no", + "bjarkoy.no", + "bjark\xF8y.no", + "bjerkreim.no", + "bjugn.no", + "bodo.no", + "bod\xF8.no", + "badaddja.no", + "b\xE5d\xE5ddj\xE5.no", + "budejju.no", + "bokn.no", + "bremanger.no", + "bronnoy.no", + "br\xF8nn\xF8y.no", + "bygland.no", + "bykle.no", + "barum.no", + "b\xE6rum.no", + "bo.telemark.no", + "b\xF8.telemark.no", + "bo.nordland.no", + "b\xF8.nordland.no", + "bievat.no", + "biev\xE1t.no", + "bomlo.no", + "b\xF8mlo.no", + "batsfjord.no", + "b\xE5tsfjord.no", + "bahcavuotna.no", + "b\xE1hcavuotna.no", + "dovre.no", + "drammen.no", + "drangedal.no", + "dyroy.no", + "dyr\xF8y.no", + "donna.no", + "d\xF8nna.no", + "eid.no", + "eidfjord.no", + "eidsberg.no", + "eidskog.no", + "eidsvoll.no", + "eigersund.no", + "elverum.no", + "enebakk.no", + "engerdal.no", + "etne.no", + "etnedal.no", + "evenes.no", + "evenassi.no", + "even\xE1\u0161\u0161i.no", + "evje-og-hornnes.no", + "farsund.no", + "fauske.no", + "fuossko.no", + "fuoisku.no", + "fedje.no", + "fet.no", + "finnoy.no", + "finn\xF8y.no", + "fitjar.no", + "fjaler.no", + "fjell.no", + "flakstad.no", + "flatanger.no", + "flekkefjord.no", + "flesberg.no", + "flora.no", + "fla.no", + "fl\xE5.no", + "folldal.no", + "forsand.no", + "fosnes.no", + "frei.no", + "frogn.no", + "froland.no", + "frosta.no", + "frana.no", + "fr\xE6na.no", + "froya.no", + "fr\xF8ya.no", + "fusa.no", + "fyresdal.no", + "forde.no", + "f\xF8rde.no", + "gamvik.no", + "gangaviika.no", + "g\xE1\u014Bgaviika.no", + "gaular.no", + "gausdal.no", + "gildeskal.no", + "gildesk\xE5l.no", + "giske.no", + "gjemnes.no", + "gjerdrum.no", + "gjerstad.no", + "gjesdal.no", + "gjovik.no", + "gj\xF8vik.no", + "gloppen.no", + "gol.no", + "gran.no", + "grane.no", + "granvin.no", + "gratangen.no", + "grimstad.no", + "grong.no", + "kraanghke.no", + "kr\xE5anghke.no", + "grue.no", + "gulen.no", + "hadsel.no", + "halden.no", + "halsa.no", + "hamar.no", + "hamaroy.no", + "habmer.no", + "h\xE1bmer.no", + "hapmir.no", + "h\xE1pmir.no", + "hammerfest.no", + "hammarfeasta.no", + "h\xE1mm\xE1rfeasta.no", + "haram.no", + "hareid.no", + "harstad.no", + "hasvik.no", + "aknoluokta.no", + "\xE1k\u014Boluokta.no", + "hattfjelldal.no", + "aarborte.no", + "haugesund.no", + "hemne.no", + "hemnes.no", + "hemsedal.no", + "heroy.more-og-romsdal.no", + "her\xF8y.m\xF8re-og-romsdal.no", + "heroy.nordland.no", + "her\xF8y.nordland.no", + "hitra.no", + "hjartdal.no", + "hjelmeland.no", + "hobol.no", + "hob\xF8l.no", + "hof.no", + "hol.no", + "hole.no", + "holmestrand.no", + "holtalen.no", + "holt\xE5len.no", + "hornindal.no", + "horten.no", + "hurdal.no", + "hurum.no", + "hvaler.no", + "hyllestad.no", + "hagebostad.no", + "h\xE6gebostad.no", + "hoyanger.no", + "h\xF8yanger.no", + "hoylandet.no", + "h\xF8ylandet.no", + "ha.no", + "h\xE5.no", + "ibestad.no", + "inderoy.no", + "inder\xF8y.no", + "iveland.no", + "jevnaker.no", + "jondal.no", + "jolster.no", + "j\xF8lster.no", + "karasjok.no", + "karasjohka.no", + "k\xE1r\xE1\u0161johka.no", + "karlsoy.no", + "galsa.no", + "g\xE1ls\xE1.no", + "karmoy.no", + "karm\xF8y.no", + "kautokeino.no", + "guovdageaidnu.no", + "klepp.no", + "klabu.no", + "kl\xE6bu.no", + "kongsberg.no", + "kongsvinger.no", + "kragero.no", + "krager\xF8.no", + "kristiansand.no", + "kristiansund.no", + "krodsherad.no", + "kr\xF8dsherad.no", + "kvalsund.no", + "rahkkeravju.no", + "r\xE1hkker\xE1vju.no", + "kvam.no", + "kvinesdal.no", + "kvinnherad.no", + "kviteseid.no", + "kvitsoy.no", + "kvits\xF8y.no", + "kvafjord.no", + "kv\xE6fjord.no", + "giehtavuoatna.no", + "kvanangen.no", + "kv\xE6nangen.no", + "navuotna.no", + "n\xE1vuotna.no", + "kafjord.no", + "k\xE5fjord.no", + "gaivuotna.no", + "g\xE1ivuotna.no", + "larvik.no", + "lavangen.no", + "lavagis.no", + "loabat.no", + "loab\xE1t.no", + "lebesby.no", + "davvesiida.no", + "leikanger.no", + "leirfjord.no", + "leka.no", + "leksvik.no", + "lenvik.no", + "leangaviika.no", + "lea\u014Bgaviika.no", + "lesja.no", + "levanger.no", + "lier.no", + "lierne.no", + "lillehammer.no", + "lillesand.no", + "lindesnes.no", + "lindas.no", + "lind\xE5s.no", + "lom.no", + "loppa.no", + "lahppi.no", + "l\xE1hppi.no", + "lund.no", + "lunner.no", + "luroy.no", + "lur\xF8y.no", + "luster.no", + "lyngdal.no", + "lyngen.no", + "ivgu.no", + "lardal.no", + "lerdal.no", + "l\xE6rdal.no", + "lodingen.no", + "l\xF8dingen.no", + "lorenskog.no", + "l\xF8renskog.no", + "loten.no", + "l\xF8ten.no", + "malvik.no", + "masoy.no", + "m\xE5s\xF8y.no", + "muosat.no", + "muos\xE1t.no", + "mandal.no", + "marker.no", + "marnardal.no", + "masfjorden.no", + "meland.no", + "meldal.no", + "melhus.no", + "meloy.no", + "mel\xF8y.no", + "meraker.no", + "mer\xE5ker.no", + "moareke.no", + "mo\xE5reke.no", + "midsund.no", + "midtre-gauldal.no", + "modalen.no", + "modum.no", + "molde.no", + "moskenes.no", + "moss.no", + "mosvik.no", + "malselv.no", + "m\xE5lselv.no", + "malatvuopmi.no", + "m\xE1latvuopmi.no", + "namdalseid.no", + "aejrie.no", + "namsos.no", + "namsskogan.no", + "naamesjevuemie.no", + "n\xE5\xE5mesjevuemie.no", + "laakesvuemie.no", + "nannestad.no", + "narvik.no", + "narviika.no", + "naustdal.no", + "nedre-eiker.no", + "nes.akershus.no", + "nes.buskerud.no", + "nesna.no", + "nesodden.no", + "nesseby.no", + "unjarga.no", + "unj\xE1rga.no", + "nesset.no", + "nissedal.no", + "nittedal.no", + "nord-aurdal.no", + "nord-fron.no", + "nord-odal.no", + "norddal.no", + "nordkapp.no", + "davvenjarga.no", + "davvenj\xE1rga.no", + "nordre-land.no", + "nordreisa.no", + "raisa.no", + "r\xE1isa.no", + "nore-og-uvdal.no", + "notodden.no", + "naroy.no", + "n\xE6r\xF8y.no", + "notteroy.no", + "n\xF8tter\xF8y.no", + "odda.no", + "oksnes.no", + "\xF8ksnes.no", + "oppdal.no", + "oppegard.no", + "oppeg\xE5rd.no", + "orkdal.no", + "orland.no", + "\xF8rland.no", + "orskog.no", + "\xF8rskog.no", + "orsta.no", + "\xF8rsta.no", + "os.hedmark.no", + "os.hordaland.no", + "osen.no", + "osteroy.no", + "oster\xF8y.no", + "ostre-toten.no", + "\xF8stre-toten.no", + "overhalla.no", + "ovre-eiker.no", + "\xF8vre-eiker.no", + "oyer.no", + "\xF8yer.no", + "oygarden.no", + "\xF8ygarden.no", + "oystre-slidre.no", + "\xF8ystre-slidre.no", + "porsanger.no", + "porsangu.no", + "pors\xE1\u014Bgu.no", + "porsgrunn.no", + "radoy.no", + "rad\xF8y.no", + "rakkestad.no", + "rana.no", + "ruovat.no", + "randaberg.no", + "rauma.no", + "rendalen.no", + "rennebu.no", + "rennesoy.no", + "rennes\xF8y.no", + "rindal.no", + "ringebu.no", + "ringerike.no", + "ringsaker.no", + "rissa.no", + "risor.no", + "ris\xF8r.no", + "roan.no", + "rollag.no", + "rygge.no", + "ralingen.no", + "r\xE6lingen.no", + "rodoy.no", + "r\xF8d\xF8y.no", + "romskog.no", + "r\xF8mskog.no", + "roros.no", + "r\xF8ros.no", + "rost.no", + "r\xF8st.no", + "royken.no", + "r\xF8yken.no", + "royrvik.no", + "r\xF8yrvik.no", + "rade.no", + "r\xE5de.no", + "salangen.no", + "siellak.no", + "saltdal.no", + "salat.no", + "s\xE1l\xE1t.no", + "s\xE1lat.no", + "samnanger.no", + "sande.more-og-romsdal.no", + "sande.m\xF8re-og-romsdal.no", + "sande.vestfold.no", + "sandefjord.no", + "sandnes.no", + "sandoy.no", + "sand\xF8y.no", + "sarpsborg.no", + "sauda.no", + "sauherad.no", + "sel.no", + "selbu.no", + "selje.no", + "seljord.no", + "sigdal.no", + "siljan.no", + "sirdal.no", + "skaun.no", + "skedsmo.no", + "ski.no", + "skien.no", + "skiptvet.no", + "skjervoy.no", + "skjerv\xF8y.no", + "skierva.no", + "skierv\xE1.no", + "skjak.no", + "skj\xE5k.no", + "skodje.no", + "skanland.no", + "sk\xE5nland.no", + "skanit.no", + "sk\xE1nit.no", + "smola.no", + "sm\xF8la.no", + "snillfjord.no", + "snasa.no", + "sn\xE5sa.no", + "snoasa.no", + "snaase.no", + "sn\xE5ase.no", + "sogndal.no", + "sokndal.no", + "sola.no", + "solund.no", + "songdalen.no", + "sortland.no", + "spydeberg.no", + "stange.no", + "stavanger.no", + "steigen.no", + "steinkjer.no", + "stjordal.no", + "stj\xF8rdal.no", + "stokke.no", + "stor-elvdal.no", + "stord.no", + "stordal.no", + "storfjord.no", + "omasvuotna.no", + "strand.no", + "stranda.no", + "stryn.no", + "sula.no", + "suldal.no", + "sund.no", + "sunndal.no", + "surnadal.no", + "sveio.no", + "svelvik.no", + "sykkylven.no", + "sogne.no", + "s\xF8gne.no", + "somna.no", + "s\xF8mna.no", + "sondre-land.no", + "s\xF8ndre-land.no", + "sor-aurdal.no", + "s\xF8r-aurdal.no", + "sor-fron.no", + "s\xF8r-fron.no", + "sor-odal.no", + "s\xF8r-odal.no", + "sor-varanger.no", + "s\xF8r-varanger.no", + "matta-varjjat.no", + "m\xE1tta-v\xE1rjjat.no", + "sorfold.no", + "s\xF8rfold.no", + "sorreisa.no", + "s\xF8rreisa.no", + "sorum.no", + "s\xF8rum.no", + "tana.no", + "deatnu.no", + "time.no", + "tingvoll.no", + "tinn.no", + "tjeldsund.no", + "dielddanuorri.no", + "tjome.no", + "tj\xF8me.no", + "tokke.no", + "tolga.no", + "torsken.no", + "tranoy.no", + "tran\xF8y.no", + "tromso.no", + "troms\xF8.no", + "tromsa.no", + "romsa.no", + "trondheim.no", + "troandin.no", + "trysil.no", + "trana.no", + "tr\xE6na.no", + "trogstad.no", + "tr\xF8gstad.no", + "tvedestrand.no", + "tydal.no", + "tynset.no", + "tysfjord.no", + "divtasvuodna.no", + "divttasvuotna.no", + "tysnes.no", + "tysvar.no", + "tysv\xE6r.no", + "tonsberg.no", + "t\xF8nsberg.no", + "ullensaker.no", + "ullensvang.no", + "ulvik.no", + "utsira.no", + "vadso.no", + "vads\xF8.no", + "cahcesuolo.no", + "\u010D\xE1hcesuolo.no", + "vaksdal.no", + "valle.no", + "vang.no", + "vanylven.no", + "vardo.no", + "vard\xF8.no", + "varggat.no", + "v\xE1rgg\xE1t.no", + "vefsn.no", + "vaapste.no", + "vega.no", + "vegarshei.no", + "veg\xE5rshei.no", + "vennesla.no", + "verdal.no", + "verran.no", + "vestby.no", + "vestnes.no", + "vestre-slidre.no", + "vestre-toten.no", + "vestvagoy.no", + "vestv\xE5g\xF8y.no", + "vevelstad.no", + "vik.no", + "vikna.no", + "vindafjord.no", + "volda.no", + "voss.no", + "varoy.no", + "v\xE6r\xF8y.no", + "vagan.no", + "v\xE5gan.no", + "voagat.no", + "vagsoy.no", + "v\xE5gs\xF8y.no", + "vaga.no", + "v\xE5g\xE5.no", + "valer.ostfold.no", + "v\xE5ler.\xF8stfold.no", + "valer.hedmark.no", + "v\xE5ler.hedmark.no", + "*.np", + "nr", + "biz.nr", + "info.nr", + "gov.nr", + "edu.nr", + "org.nr", + "net.nr", + "com.nr", + "nu", + "nz", + "ac.nz", + "co.nz", + "cri.nz", + "geek.nz", + "gen.nz", + "govt.nz", + "health.nz", + "iwi.nz", + "kiwi.nz", + "maori.nz", + "mil.nz", + "m\u0101ori.nz", + "net.nz", + "org.nz", + "parliament.nz", + "school.nz", + "om", + "co.om", + "com.om", + "edu.om", + "gov.om", + "med.om", + "museum.om", + "net.om", + "org.om", + "pro.om", + "onion", + "org", + "pa", + "ac.pa", + "gob.pa", + "com.pa", + "org.pa", + "sld.pa", + "edu.pa", + "net.pa", + "ing.pa", + "abo.pa", + "med.pa", + "nom.pa", + "pe", + "edu.pe", + "gob.pe", + "nom.pe", + "mil.pe", + "org.pe", + "com.pe", + "net.pe", + "pf", + "com.pf", + "org.pf", + "edu.pf", + "*.pg", + "ph", + "com.ph", + "net.ph", + "org.ph", + "gov.ph", + "edu.ph", + "ngo.ph", + "mil.ph", + "i.ph", + "pk", + "com.pk", + "net.pk", + "edu.pk", + "org.pk", + "fam.pk", + "biz.pk", + "web.pk", + "gov.pk", + "gob.pk", + "gok.pk", + "gon.pk", + "gop.pk", + "gos.pk", + "info.pk", + "pl", + "com.pl", + "net.pl", + "org.pl", + "aid.pl", + "agro.pl", + "atm.pl", + "auto.pl", + "biz.pl", + "edu.pl", + "gmina.pl", + "gsm.pl", + "info.pl", + "mail.pl", + "miasta.pl", + "media.pl", + "mil.pl", + "nieruchomosci.pl", + "nom.pl", + "pc.pl", + "powiat.pl", + "priv.pl", + "realestate.pl", + "rel.pl", + "sex.pl", + "shop.pl", + "sklep.pl", + "sos.pl", + "szkola.pl", + "targi.pl", + "tm.pl", + "tourism.pl", + "travel.pl", + "turystyka.pl", + "gov.pl", + "ap.gov.pl", + "ic.gov.pl", + "is.gov.pl", + "us.gov.pl", + "kmpsp.gov.pl", + "kppsp.gov.pl", + "kwpsp.gov.pl", + "psp.gov.pl", + "wskr.gov.pl", + "kwp.gov.pl", + "mw.gov.pl", + "ug.gov.pl", + "um.gov.pl", + "umig.gov.pl", + "ugim.gov.pl", + "upow.gov.pl", + "uw.gov.pl", + "starostwo.gov.pl", + "pa.gov.pl", + "po.gov.pl", + "psse.gov.pl", + "pup.gov.pl", + "rzgw.gov.pl", + "sa.gov.pl", + "so.gov.pl", + "sr.gov.pl", + "wsa.gov.pl", + "sko.gov.pl", + "uzs.gov.pl", + "wiih.gov.pl", + "winb.gov.pl", + "pinb.gov.pl", + "wios.gov.pl", + "witd.gov.pl", + "wzmiuw.gov.pl", + "piw.gov.pl", + "wiw.gov.pl", + "griw.gov.pl", + "wif.gov.pl", + "oum.gov.pl", + "sdn.gov.pl", + "zp.gov.pl", + "uppo.gov.pl", + "mup.gov.pl", + "wuoz.gov.pl", + "konsulat.gov.pl", + "oirm.gov.pl", + "augustow.pl", + "babia-gora.pl", + "bedzin.pl", + "beskidy.pl", + "bialowieza.pl", + "bialystok.pl", + "bielawa.pl", + "bieszczady.pl", + "boleslawiec.pl", + "bydgoszcz.pl", + "bytom.pl", + "cieszyn.pl", + "czeladz.pl", + "czest.pl", + "dlugoleka.pl", + "elblag.pl", + "elk.pl", + "glogow.pl", + "gniezno.pl", + "gorlice.pl", + "grajewo.pl", + "ilawa.pl", + "jaworzno.pl", + "jelenia-gora.pl", + "jgora.pl", + "kalisz.pl", + "kazimierz-dolny.pl", + "karpacz.pl", + "kartuzy.pl", + "kaszuby.pl", + "katowice.pl", + "kepno.pl", + "ketrzyn.pl", + "klodzko.pl", + "kobierzyce.pl", + "kolobrzeg.pl", + "konin.pl", + "konskowola.pl", + "kutno.pl", + "lapy.pl", + "lebork.pl", + "legnica.pl", + "lezajsk.pl", + "limanowa.pl", + "lomza.pl", + "lowicz.pl", + "lubin.pl", + "lukow.pl", + "malbork.pl", + "malopolska.pl", + "mazowsze.pl", + "mazury.pl", + "mielec.pl", + "mielno.pl", + "mragowo.pl", + "naklo.pl", + "nowaruda.pl", + "nysa.pl", + "olawa.pl", + "olecko.pl", + "olkusz.pl", + "olsztyn.pl", + "opoczno.pl", + "opole.pl", + "ostroda.pl", + "ostroleka.pl", + "ostrowiec.pl", + "ostrowwlkp.pl", + "pila.pl", + "pisz.pl", + "podhale.pl", + "podlasie.pl", + "polkowice.pl", + "pomorze.pl", + "pomorskie.pl", + "prochowice.pl", + "pruszkow.pl", + "przeworsk.pl", + "pulawy.pl", + "radom.pl", + "rawa-maz.pl", + "rybnik.pl", + "rzeszow.pl", + "sanok.pl", + "sejny.pl", + "slask.pl", + "slupsk.pl", + "sosnowiec.pl", + "stalowa-wola.pl", + "skoczow.pl", + "starachowice.pl", + "stargard.pl", + "suwalki.pl", + "swidnica.pl", + "swiebodzin.pl", + "swinoujscie.pl", + "szczecin.pl", + "szczytno.pl", + "tarnobrzeg.pl", + "tgory.pl", + "turek.pl", + "tychy.pl", + "ustka.pl", + "walbrzych.pl", + "warmia.pl", + "warszawa.pl", + "waw.pl", + "wegrow.pl", + "wielun.pl", + "wlocl.pl", + "wloclawek.pl", + "wodzislaw.pl", + "wolomin.pl", + "wroclaw.pl", + "zachpomor.pl", + "zagan.pl", + "zarow.pl", + "zgora.pl", + "zgorzelec.pl", + "pm", + "pn", + "gov.pn", + "co.pn", + "org.pn", + "edu.pn", + "net.pn", + "post", + "pr", + "com.pr", + "net.pr", + "org.pr", + "gov.pr", + "edu.pr", + "isla.pr", + "pro.pr", + "biz.pr", + "info.pr", + "name.pr", + "est.pr", + "prof.pr", + "ac.pr", + "pro", + "aaa.pro", + "aca.pro", + "acct.pro", + "avocat.pro", + "bar.pro", + "cpa.pro", + "eng.pro", + "jur.pro", + "law.pro", + "med.pro", + "recht.pro", + "ps", + "edu.ps", + "gov.ps", + "sec.ps", + "plo.ps", + "com.ps", + "org.ps", + "net.ps", + "pt", + "net.pt", + "gov.pt", + "org.pt", + "edu.pt", + "int.pt", + "publ.pt", + "com.pt", + "nome.pt", + "pw", + "co.pw", + "ne.pw", + "or.pw", + "ed.pw", + "go.pw", + "belau.pw", + "py", + "com.py", + "coop.py", + "edu.py", + "gov.py", + "mil.py", + "net.py", + "org.py", + "qa", + "com.qa", + "edu.qa", + "gov.qa", + "mil.qa", + "name.qa", + "net.qa", + "org.qa", + "sch.qa", + "re", + "asso.re", + "com.re", + "nom.re", + "ro", + "arts.ro", + "com.ro", + "firm.ro", + "info.ro", + "nom.ro", + "nt.ro", + "org.ro", + "rec.ro", + "store.ro", + "tm.ro", + "www.ro", + "rs", + "ac.rs", + "co.rs", + "edu.rs", + "gov.rs", + "in.rs", + "org.rs", + "ru", + "rw", + "ac.rw", + "co.rw", + "coop.rw", + "gov.rw", + "mil.rw", + "net.rw", + "org.rw", + "sa", + "com.sa", + "net.sa", + "org.sa", + "gov.sa", + "med.sa", + "pub.sa", + "edu.sa", + "sch.sa", + "sb", + "com.sb", + "edu.sb", + "gov.sb", + "net.sb", + "org.sb", + "sc", + "com.sc", + "gov.sc", + "net.sc", + "org.sc", + "edu.sc", + "sd", + "com.sd", + "net.sd", + "org.sd", + "edu.sd", + "med.sd", + "tv.sd", + "gov.sd", + "info.sd", + "se", + "a.se", + "ac.se", + "b.se", + "bd.se", + "brand.se", + "c.se", + "d.se", + "e.se", + "f.se", + "fh.se", + "fhsk.se", + "fhv.se", + "g.se", + "h.se", + "i.se", + "k.se", + "komforb.se", + "kommunalforbund.se", + "komvux.se", + "l.se", + "lanbib.se", + "m.se", + "n.se", + "naturbruksgymn.se", + "o.se", + "org.se", + "p.se", + "parti.se", + "pp.se", + "press.se", + "r.se", + "s.se", + "t.se", + "tm.se", + "u.se", + "w.se", + "x.se", + "y.se", + "z.se", + "sg", + "com.sg", + "net.sg", + "org.sg", + "gov.sg", + "edu.sg", + "per.sg", + "sh", + "com.sh", + "net.sh", + "gov.sh", + "org.sh", + "mil.sh", + "si", + "sj", + "sk", + "sl", + "com.sl", + "net.sl", + "edu.sl", + "gov.sl", + "org.sl", + "sm", + "sn", + "art.sn", + "com.sn", + "edu.sn", + "gouv.sn", + "org.sn", + "perso.sn", + "univ.sn", + "so", + "com.so", + "edu.so", + "gov.so", + "me.so", + "net.so", + "org.so", + "sr", + "ss", + "biz.ss", + "com.ss", + "edu.ss", + "gov.ss", + "me.ss", + "net.ss", + "org.ss", + "sch.ss", + "st", + "co.st", + "com.st", + "consulado.st", + "edu.st", + "embaixada.st", + "mil.st", + "net.st", + "org.st", + "principe.st", + "saotome.st", + "store.st", + "su", + "sv", + "com.sv", + "edu.sv", + "gob.sv", + "org.sv", + "red.sv", + "sx", + "gov.sx", + "sy", + "edu.sy", + "gov.sy", + "net.sy", + "mil.sy", + "com.sy", + "org.sy", + "sz", + "co.sz", + "ac.sz", + "org.sz", + "tc", + "td", + "tel", + "tf", + "tg", + "th", + "ac.th", + "co.th", + "go.th", + "in.th", + "mi.th", + "net.th", + "or.th", + "tj", + "ac.tj", + "biz.tj", + "co.tj", + "com.tj", + "edu.tj", + "go.tj", + "gov.tj", + "int.tj", + "mil.tj", + "name.tj", + "net.tj", + "nic.tj", + "org.tj", + "test.tj", + "web.tj", + "tk", + "tl", + "gov.tl", + "tm", + "com.tm", + "co.tm", + "org.tm", + "net.tm", + "nom.tm", + "gov.tm", + "mil.tm", + "edu.tm", + "tn", + "com.tn", + "ens.tn", + "fin.tn", + "gov.tn", + "ind.tn", + "info.tn", + "intl.tn", + "mincom.tn", + "nat.tn", + "net.tn", + "org.tn", + "perso.tn", + "tourism.tn", + "to", + "com.to", + "gov.to", + "net.to", + "org.to", + "edu.to", + "mil.to", + "tr", + "av.tr", + "bbs.tr", + "bel.tr", + "biz.tr", + "com.tr", + "dr.tr", + "edu.tr", + "gen.tr", + "gov.tr", + "info.tr", + "mil.tr", + "k12.tr", + "kep.tr", + "name.tr", + "net.tr", + "org.tr", + "pol.tr", + "tel.tr", + "tsk.tr", + "tv.tr", + "web.tr", + "nc.tr", + "gov.nc.tr", + "tt", + "co.tt", + "com.tt", + "org.tt", + "net.tt", + "biz.tt", + "info.tt", + "pro.tt", + "int.tt", + "coop.tt", + "jobs.tt", + "mobi.tt", + "travel.tt", + "museum.tt", + "aero.tt", + "name.tt", + "gov.tt", + "edu.tt", + "tv", + "tw", + "edu.tw", + "gov.tw", + "mil.tw", + "com.tw", + "net.tw", + "org.tw", + "idv.tw", + "game.tw", + "ebiz.tw", + "club.tw", + "\u7DB2\u8DEF.tw", + "\u7D44\u7E54.tw", + "\u5546\u696D.tw", + "tz", + "ac.tz", + "co.tz", + "go.tz", + "hotel.tz", + "info.tz", + "me.tz", + "mil.tz", + "mobi.tz", + "ne.tz", + "or.tz", + "sc.tz", + "tv.tz", + "ua", + "com.ua", + "edu.ua", + "gov.ua", + "in.ua", + "net.ua", + "org.ua", + "cherkassy.ua", + "cherkasy.ua", + "chernigov.ua", + "chernihiv.ua", + "chernivtsi.ua", + "chernovtsy.ua", + "ck.ua", + "cn.ua", + "cr.ua", + "crimea.ua", + "cv.ua", + "dn.ua", + "dnepropetrovsk.ua", + "dnipropetrovsk.ua", + "donetsk.ua", + "dp.ua", + "if.ua", + "ivano-frankivsk.ua", + "kh.ua", + "kharkiv.ua", + "kharkov.ua", + "kherson.ua", + "khmelnitskiy.ua", + "khmelnytskyi.ua", + "kiev.ua", + "kirovograd.ua", + "km.ua", + "kr.ua", + "krym.ua", + "ks.ua", + "kv.ua", + "kyiv.ua", + "lg.ua", + "lt.ua", + "lugansk.ua", + "lutsk.ua", + "lv.ua", + "lviv.ua", + "mk.ua", + "mykolaiv.ua", + "nikolaev.ua", + "od.ua", + "odesa.ua", + "odessa.ua", + "pl.ua", + "poltava.ua", + "rivne.ua", + "rovno.ua", + "rv.ua", + "sb.ua", + "sebastopol.ua", + "sevastopol.ua", + "sm.ua", + "sumy.ua", + "te.ua", + "ternopil.ua", + "uz.ua", + "uzhgorod.ua", + "vinnica.ua", + "vinnytsia.ua", + "vn.ua", + "volyn.ua", + "yalta.ua", + "zaporizhzhe.ua", + "zaporizhzhia.ua", + "zhitomir.ua", + "zhytomyr.ua", + "zp.ua", + "zt.ua", + "ug", + "co.ug", + "or.ug", + "ac.ug", + "sc.ug", + "go.ug", + "ne.ug", + "com.ug", + "org.ug", + "uk", + "ac.uk", + "co.uk", + "gov.uk", + "ltd.uk", + "me.uk", + "net.uk", + "nhs.uk", + "org.uk", + "plc.uk", + "police.uk", + "*.sch.uk", + "us", + "dni.us", + "fed.us", + "isa.us", + "kids.us", + "nsn.us", + "ak.us", + "al.us", + "ar.us", + "as.us", + "az.us", + "ca.us", + "co.us", + "ct.us", + "dc.us", + "de.us", + "fl.us", + "ga.us", + "gu.us", + "hi.us", + "ia.us", + "id.us", + "il.us", + "in.us", + "ks.us", + "ky.us", + "la.us", + "ma.us", + "md.us", + "me.us", + "mi.us", + "mn.us", + "mo.us", + "ms.us", + "mt.us", + "nc.us", + "nd.us", + "ne.us", + "nh.us", + "nj.us", + "nm.us", + "nv.us", + "ny.us", + "oh.us", + "ok.us", + "or.us", + "pa.us", + "pr.us", + "ri.us", + "sc.us", + "sd.us", + "tn.us", + "tx.us", + "ut.us", + "vi.us", + "vt.us", + "va.us", + "wa.us", + "wi.us", + "wv.us", + "wy.us", + "k12.ak.us", + "k12.al.us", + "k12.ar.us", + "k12.as.us", + "k12.az.us", + "k12.ca.us", + "k12.co.us", + "k12.ct.us", + "k12.dc.us", + "k12.de.us", + "k12.fl.us", + "k12.ga.us", + "k12.gu.us", + "k12.ia.us", + "k12.id.us", + "k12.il.us", + "k12.in.us", + "k12.ks.us", + "k12.ky.us", + "k12.la.us", + "k12.ma.us", + "k12.md.us", + "k12.me.us", + "k12.mi.us", + "k12.mn.us", + "k12.mo.us", + "k12.ms.us", + "k12.mt.us", + "k12.nc.us", + "k12.ne.us", + "k12.nh.us", + "k12.nj.us", + "k12.nm.us", + "k12.nv.us", + "k12.ny.us", + "k12.oh.us", + "k12.ok.us", + "k12.or.us", + "k12.pa.us", + "k12.pr.us", + "k12.sc.us", + "k12.tn.us", + "k12.tx.us", + "k12.ut.us", + "k12.vi.us", + "k12.vt.us", + "k12.va.us", + "k12.wa.us", + "k12.wi.us", + "k12.wy.us", + "cc.ak.us", + "cc.al.us", + "cc.ar.us", + "cc.as.us", + "cc.az.us", + "cc.ca.us", + "cc.co.us", + "cc.ct.us", + "cc.dc.us", + "cc.de.us", + "cc.fl.us", + "cc.ga.us", + "cc.gu.us", + "cc.hi.us", + "cc.ia.us", + "cc.id.us", + "cc.il.us", + "cc.in.us", + "cc.ks.us", + "cc.ky.us", + "cc.la.us", + "cc.ma.us", + "cc.md.us", + "cc.me.us", + "cc.mi.us", + "cc.mn.us", + "cc.mo.us", + "cc.ms.us", + "cc.mt.us", + "cc.nc.us", + "cc.nd.us", + "cc.ne.us", + "cc.nh.us", + "cc.nj.us", + "cc.nm.us", + "cc.nv.us", + "cc.ny.us", + "cc.oh.us", + "cc.ok.us", + "cc.or.us", + "cc.pa.us", + "cc.pr.us", + "cc.ri.us", + "cc.sc.us", + "cc.sd.us", + "cc.tn.us", + "cc.tx.us", + "cc.ut.us", + "cc.vi.us", + "cc.vt.us", + "cc.va.us", + "cc.wa.us", + "cc.wi.us", + "cc.wv.us", + "cc.wy.us", + "lib.ak.us", + "lib.al.us", + "lib.ar.us", + "lib.as.us", + "lib.az.us", + "lib.ca.us", + "lib.co.us", + "lib.ct.us", + "lib.dc.us", + "lib.fl.us", + "lib.ga.us", + "lib.gu.us", + "lib.hi.us", + "lib.ia.us", + "lib.id.us", + "lib.il.us", + "lib.in.us", + "lib.ks.us", + "lib.ky.us", + "lib.la.us", + "lib.ma.us", + "lib.md.us", + "lib.me.us", + "lib.mi.us", + "lib.mn.us", + "lib.mo.us", + "lib.ms.us", + "lib.mt.us", + "lib.nc.us", + "lib.nd.us", + "lib.ne.us", + "lib.nh.us", + "lib.nj.us", + "lib.nm.us", + "lib.nv.us", + "lib.ny.us", + "lib.oh.us", + "lib.ok.us", + "lib.or.us", + "lib.pa.us", + "lib.pr.us", + "lib.ri.us", + "lib.sc.us", + "lib.sd.us", + "lib.tn.us", + "lib.tx.us", + "lib.ut.us", + "lib.vi.us", + "lib.vt.us", + "lib.va.us", + "lib.wa.us", + "lib.wi.us", + "lib.wy.us", + "pvt.k12.ma.us", + "chtr.k12.ma.us", + "paroch.k12.ma.us", + "ann-arbor.mi.us", + "cog.mi.us", + "dst.mi.us", + "eaton.mi.us", + "gen.mi.us", + "mus.mi.us", + "tec.mi.us", + "washtenaw.mi.us", + "uy", + "com.uy", + "edu.uy", + "gub.uy", + "mil.uy", + "net.uy", + "org.uy", + "uz", + "co.uz", + "com.uz", + "net.uz", + "org.uz", + "va", + "vc", + "com.vc", + "net.vc", + "org.vc", + "gov.vc", + "mil.vc", + "edu.vc", + "ve", + "arts.ve", + "bib.ve", + "co.ve", + "com.ve", + "e12.ve", + "edu.ve", + "firm.ve", + "gob.ve", + "gov.ve", + "info.ve", + "int.ve", + "mil.ve", + "net.ve", + "nom.ve", + "org.ve", + "rar.ve", + "rec.ve", + "store.ve", + "tec.ve", + "web.ve", + "vg", + "vi", + "co.vi", + "com.vi", + "k12.vi", + "net.vi", + "org.vi", + "vn", + "com.vn", + "net.vn", + "org.vn", + "edu.vn", + "gov.vn", + "int.vn", + "ac.vn", + "biz.vn", + "info.vn", + "name.vn", + "pro.vn", + "health.vn", + "vu", + "com.vu", + "edu.vu", + "net.vu", + "org.vu", + "wf", + "ws", + "com.ws", + "net.ws", + "org.ws", + "gov.ws", + "edu.ws", + "yt", + "\u0627\u0645\u0627\u0631\u0627\u062A", + "\u0570\u0561\u0575", + "\u09AC\u09BE\u0982\u09B2\u09BE", + "\u0431\u0433", + "\u0627\u0644\u0628\u062D\u0631\u064A\u0646", + "\u0431\u0435\u043B", + "\u4E2D\u56FD", + "\u4E2D\u570B", + "\u0627\u0644\u062C\u0632\u0627\u0626\u0631", + "\u0645\u0635\u0631", + "\u0435\u044E", + "\u03B5\u03C5", + "\u0645\u0648\u0631\u064A\u062A\u0627\u0646\u064A\u0627", + "\u10D2\u10D4", + "\u03B5\u03BB", + "\u9999\u6E2F", + "\u516C\u53F8.\u9999\u6E2F", + "\u6559\u80B2.\u9999\u6E2F", + "\u653F\u5E9C.\u9999\u6E2F", + "\u500B\u4EBA.\u9999\u6E2F", + "\u7DB2\u7D61.\u9999\u6E2F", + "\u7D44\u7E54.\u9999\u6E2F", + "\u0CAD\u0CBE\u0CB0\u0CA4", + "\u0B2D\u0B3E\u0B30\u0B24", + "\u09AD\u09BE\u09F0\u09A4", + "\u092D\u093E\u0930\u0924\u092E\u094D", + "\u092D\u093E\u0930\u094B\u0924", + "\u0680\u0627\u0631\u062A", + "\u0D2D\u0D3E\u0D30\u0D24\u0D02", + "\u092D\u093E\u0930\u0924", + "\u0628\u0627\u0631\u062A", + "\u0628\u06BE\u0627\u0631\u062A", + "\u0C2D\u0C3E\u0C30\u0C24\u0C4D", + "\u0AAD\u0ABE\u0AB0\u0AA4", + "\u0A2D\u0A3E\u0A30\u0A24", + "\u09AD\u09BE\u09B0\u09A4", + "\u0B87\u0BA8\u0BCD\u0BA4\u0BBF\u0BAF\u0BBE", + "\u0627\u06CC\u0631\u0627\u0646", + "\u0627\u064A\u0631\u0627\u0646", + "\u0639\u0631\u0627\u0642", + "\u0627\u0644\u0627\u0631\u062F\u0646", + "\uD55C\uAD6D", + "\u049B\u0430\u0437", + "\u0EA5\u0EB2\u0EA7", + "\u0DBD\u0D82\u0D9A\u0DCF", + "\u0B87\u0BB2\u0B99\u0BCD\u0B95\u0BC8", + "\u0627\u0644\u0645\u063A\u0631\u0628", + "\u043C\u043A\u0434", + "\u043C\u043E\u043D", + "\u6FB3\u9580", + "\u6FB3\u95E8", + "\u0645\u0644\u064A\u0633\u064A\u0627", + "\u0639\u0645\u0627\u0646", + "\u067E\u0627\u06A9\u0633\u062A\u0627\u0646", + "\u067E\u0627\u0643\u0633\u062A\u0627\u0646", + "\u0641\u0644\u0633\u0637\u064A\u0646", + "\u0441\u0440\u0431", + "\u043F\u0440.\u0441\u0440\u0431", + "\u043E\u0440\u0433.\u0441\u0440\u0431", + "\u043E\u0431\u0440.\u0441\u0440\u0431", + "\u043E\u0434.\u0441\u0440\u0431", + "\u0443\u043F\u0440.\u0441\u0440\u0431", + "\u0430\u043A.\u0441\u0440\u0431", + "\u0440\u0444", + "\u0642\u0637\u0631", + "\u0627\u0644\u0633\u0639\u0648\u062F\u064A\u0629", + "\u0627\u0644\u0633\u0639\u0648\u062F\u06CC\u0629", + "\u0627\u0644\u0633\u0639\u0648\u062F\u06CC\u06C3", + "\u0627\u0644\u0633\u0639\u0648\u062F\u064A\u0647", + "\u0633\u0648\u062F\u0627\u0646", + "\u65B0\u52A0\u5761", + "\u0B9A\u0BBF\u0B99\u0BCD\u0B95\u0BAA\u0BCD\u0BAA\u0BC2\u0BB0\u0BCD", + "\u0633\u0648\u0631\u064A\u0629", + "\u0633\u0648\u0631\u064A\u0627", + "\u0E44\u0E17\u0E22", + "\u0E28\u0E36\u0E01\u0E29\u0E32.\u0E44\u0E17\u0E22", + "\u0E18\u0E38\u0E23\u0E01\u0E34\u0E08.\u0E44\u0E17\u0E22", + "\u0E23\u0E31\u0E10\u0E1A\u0E32\u0E25.\u0E44\u0E17\u0E22", + "\u0E17\u0E2B\u0E32\u0E23.\u0E44\u0E17\u0E22", + "\u0E40\u0E19\u0E47\u0E15.\u0E44\u0E17\u0E22", + "\u0E2D\u0E07\u0E04\u0E4C\u0E01\u0E23.\u0E44\u0E17\u0E22", + "\u062A\u0648\u0646\u0633", + "\u53F0\u7063", + "\u53F0\u6E7E", + "\u81FA\u7063", + "\u0443\u043A\u0440", + "\u0627\u0644\u064A\u0645\u0646", + "xxx", + "ye", + "com.ye", + "edu.ye", + "gov.ye", + "net.ye", + "mil.ye", + "org.ye", + "ac.za", + "agric.za", + "alt.za", + "co.za", + "edu.za", + "gov.za", + "grondar.za", + "law.za", + "mil.za", + "net.za", + "ngo.za", + "nic.za", + "nis.za", + "nom.za", + "org.za", + "school.za", + "tm.za", + "web.za", + "zm", + "ac.zm", + "biz.zm", + "co.zm", + "com.zm", + "edu.zm", + "gov.zm", + "info.zm", + "mil.zm", + "net.zm", + "org.zm", + "sch.zm", + "zw", + "ac.zw", + "co.zw", + "gov.zw", + "mil.zw", + "org.zw", + "aaa", + "aarp", + "abarth", + "abb", + "abbott", + "abbvie", + "abc", + "able", + "abogado", + "abudhabi", + "academy", + "accenture", + "accountant", + "accountants", + "aco", + "actor", + "adac", + "ads", + "adult", + "aeg", + "aetna", + "afl", + "africa", + "agakhan", + "agency", + "aig", + "airbus", + "airforce", + "airtel", + "akdn", + "alfaromeo", + "alibaba", + "alipay", + "allfinanz", + "allstate", + "ally", + "alsace", + "alstom", + "amazon", + "americanexpress", + "americanfamily", + "amex", + "amfam", + "amica", + "amsterdam", + "analytics", + "android", + "anquan", + "anz", + "aol", + "apartments", + "app", + "apple", + "aquarelle", + "arab", + "aramco", + "archi", + "army", + "art", + "arte", + "asda", + "associates", + "athleta", + "attorney", + "auction", + "audi", + "audible", + "audio", + "auspost", + "author", + "auto", + "autos", + "avianca", + "aws", + "axa", + "azure", + "baby", + "baidu", + "banamex", + "bananarepublic", + "band", + "bank", + "bar", + "barcelona", + "barclaycard", + "barclays", + "barefoot", + "bargains", + "baseball", + "basketball", + "bauhaus", + "bayern", + "bbc", + "bbt", + "bbva", + "bcg", + "bcn", + "beats", + "beauty", + "beer", + "bentley", + "berlin", + "best", + "bestbuy", + "bet", + "bharti", + "bible", + "bid", + "bike", + "bing", + "bingo", + "bio", + "black", + "blackfriday", + "blockbuster", + "blog", + "bloomberg", + "blue", + "bms", + "bmw", + "bnpparibas", + "boats", + "boehringer", + "bofa", + "bom", + "bond", + "boo", + "book", + "booking", + "bosch", + "bostik", + "boston", + "bot", + "boutique", + "box", + "bradesco", + "bridgestone", + "broadway", + "broker", + "brother", + "brussels", + "bugatti", + "build", + "builders", + "business", + "buy", + "buzz", + "bzh", + "cab", + "cafe", + "cal", + "call", + "calvinklein", + "cam", + "camera", + "camp", + "cancerresearch", + "canon", + "capetown", + "capital", + "capitalone", + "car", + "caravan", + "cards", + "care", + "career", + "careers", + "cars", + "casa", + "case", + "cash", + "casino", + "catering", + "catholic", + "cba", + "cbn", + "cbre", + "cbs", + "center", + "ceo", + "cern", + "cfa", + "cfd", + "chanel", + "channel", + "charity", + "chase", + "chat", + "cheap", + "chintai", + "christmas", + "chrome", + "church", + "cipriani", + "circle", + "cisco", + "citadel", + "citi", + "citic", + "city", + "cityeats", + "claims", + "cleaning", + "click", + "clinic", + "clinique", + "clothing", + "cloud", + "club", + "clubmed", + "coach", + "codes", + "coffee", + "college", + "cologne", + "comcast", + "commbank", + "community", + "company", + "compare", + "computer", + "comsec", + "condos", + "construction", + "consulting", + "contact", + "contractors", + "cooking", + "cookingchannel", + "cool", + "corsica", + "country", + "coupon", + "coupons", + "courses", + "cpa", + "credit", + "creditcard", + "creditunion", + "cricket", + "crown", + "crs", + "cruise", + "cruises", + "cuisinella", + "cymru", + "cyou", + "dabur", + "dad", + "dance", + "data", + "date", + "dating", + "datsun", + "day", + "dclk", + "dds", + "deal", + "dealer", + "deals", + "degree", + "delivery", + "dell", + "deloitte", + "delta", + "democrat", + "dental", + "dentist", + "desi", + "design", + "dev", + "dhl", + "diamonds", + "diet", + "digital", + "direct", + "directory", + "discount", + "discover", + "dish", + "diy", + "dnp", + "docs", + "doctor", + "dog", + "domains", + "dot", + "download", + "drive", + "dtv", + "dubai", + "dunlop", + "dupont", + "durban", + "dvag", + "dvr", + "earth", + "eat", + "eco", + "edeka", + "education", + "email", + "emerck", + "energy", + "engineer", + "engineering", + "enterprises", + "epson", + "equipment", + "ericsson", + "erni", + "esq", + "estate", + "etisalat", + "eurovision", + "eus", + "events", + "exchange", + "expert", + "exposed", + "express", + "extraspace", + "fage", + "fail", + "fairwinds", + "faith", + "family", + "fan", + "fans", + "farm", + "farmers", + "fashion", + "fast", + "fedex", + "feedback", + "ferrari", + "ferrero", + "fiat", + "fidelity", + "fido", + "film", + "final", + "finance", + "financial", + "fire", + "firestone", + "firmdale", + "fish", + "fishing", + "fit", + "fitness", + "flickr", + "flights", + "flir", + "florist", + "flowers", + "fly", + "foo", + "food", + "foodnetwork", + "football", + "ford", + "forex", + "forsale", + "forum", + "foundation", + "fox", + "free", + "fresenius", + "frl", + "frogans", + "frontdoor", + "frontier", + "ftr", + "fujitsu", + "fun", + "fund", + "furniture", + "futbol", + "fyi", + "gal", + "gallery", + "gallo", + "gallup", + "game", + "games", + "gap", + "garden", + "gay", + "gbiz", + "gdn", + "gea", + "gent", + "genting", + "george", + "ggee", + "gift", + "gifts", + "gives", + "giving", + "glass", + "gle", + "global", + "globo", + "gmail", + "gmbh", + "gmo", + "gmx", + "godaddy", + "gold", + "goldpoint", + "golf", + "goo", + "goodyear", + "goog", + "google", + "gop", + "got", + "grainger", + "graphics", + "gratis", + "green", + "gripe", + "grocery", + "group", + "guardian", + "gucci", + "guge", + "guide", + "guitars", + "guru", + "hair", + "hamburg", + "hangout", + "haus", + "hbo", + "hdfc", + "hdfcbank", + "health", + "healthcare", + "help", + "helsinki", + "here", + "hermes", + "hgtv", + "hiphop", + "hisamitsu", + "hitachi", + "hiv", + "hkt", + "hockey", + "holdings", + "holiday", + "homedepot", + "homegoods", + "homes", + "homesense", + "honda", + "horse", + "hospital", + "host", + "hosting", + "hot", + "hoteles", + "hotels", + "hotmail", + "house", + "how", + "hsbc", + "hughes", + "hyatt", + "hyundai", + "ibm", + "icbc", + "ice", + "icu", + "ieee", + "ifm", + "ikano", + "imamat", + "imdb", + "immo", + "immobilien", + "inc", + "industries", + "infiniti", + "ing", + "ink", + "institute", + "insurance", + "insure", + "international", + "intuit", + "investments", + "ipiranga", + "irish", + "ismaili", + "ist", + "istanbul", + "itau", + "itv", + "jaguar", + "java", + "jcb", + "jeep", + "jetzt", + "jewelry", + "jio", + "jll", + "jmp", + "jnj", + "joburg", + "jot", + "joy", + "jpmorgan", + "jprs", + "juegos", + "juniper", + "kaufen", + "kddi", + "kerryhotels", + "kerrylogistics", + "kerryproperties", + "kfh", + "kia", + "kids", + "kim", + "kinder", + "kindle", + "kitchen", + "kiwi", + "koeln", + "komatsu", + "kosher", + "kpmg", + "kpn", + "krd", + "kred", + "kuokgroup", + "kyoto", + "lacaixa", + "lamborghini", + "lamer", + "lancaster", + "lancia", + "land", + "landrover", + "lanxess", + "lasalle", + "lat", + "latino", + "latrobe", + "law", + "lawyer", + "lds", + "lease", + "leclerc", + "lefrak", + "legal", + "lego", + "lexus", + "lgbt", + "lidl", + "life", + "lifeinsurance", + "lifestyle", + "lighting", + "like", + "lilly", + "limited", + "limo", + "lincoln", + "linde", + "link", + "lipsy", + "live", + "living", + "llc", + "llp", + "loan", + "loans", + "locker", + "locus", + "loft", + "lol", + "london", + "lotte", + "lotto", + "love", + "lpl", + "lplfinancial", + "ltd", + "ltda", + "lundbeck", + "luxe", + "luxury", + "macys", + "madrid", + "maif", + "maison", + "makeup", + "man", + "management", + "mango", + "map", + "market", + "marketing", + "markets", + "marriott", + "marshalls", + "maserati", + "mattel", + "mba", + "mckinsey", + "med", + "media", + "meet", + "melbourne", + "meme", + "memorial", + "men", + "menu", + "merckmsd", + "miami", + "microsoft", + "mini", + "mint", + "mit", + "mitsubishi", + "mlb", + "mls", + "mma", + "mobile", + "moda", + "moe", + "moi", + "mom", + "monash", + "money", + "monster", + "mormon", + "mortgage", + "moscow", + "moto", + "motorcycles", + "mov", + "movie", + "msd", + "mtn", + "mtr", + "music", + "mutual", + "nab", + "nagoya", + "natura", + "navy", + "nba", + "nec", + "netbank", + "netflix", + "network", + "neustar", + "new", + "news", + "next", + "nextdirect", + "nexus", + "nfl", + "ngo", + "nhk", + "nico", + "nike", + "nikon", + "ninja", + "nissan", + "nissay", + "nokia", + "northwesternmutual", + "norton", + "now", + "nowruz", + "nowtv", + "nra", + "nrw", + "ntt", + "nyc", + "obi", + "observer", + "office", + "okinawa", + "olayan", + "olayangroup", + "oldnavy", + "ollo", + "omega", + "one", + "ong", + "onl", + "online", + "ooo", + "open", + "oracle", + "orange", + "organic", + "origins", + "osaka", + "otsuka", + "ott", + "ovh", + "page", + "panasonic", + "paris", + "pars", + "partners", + "parts", + "party", + "passagens", + "pay", + "pccw", + "pet", + "pfizer", + "pharmacy", + "phd", + "philips", + "phone", + "photo", + "photography", + "photos", + "physio", + "pics", + "pictet", + "pictures", + "pid", + "pin", + "ping", + "pink", + "pioneer", + "pizza", + "place", + "play", + "playstation", + "plumbing", + "plus", + "pnc", + "pohl", + "poker", + "politie", + "porn", + "pramerica", + "praxi", + "press", + "prime", + "prod", + "productions", + "prof", + "progressive", + "promo", + "properties", + "property", + "protection", + "pru", + "prudential", + "pub", + "pwc", + "qpon", + "quebec", + "quest", + "racing", + "radio", + "read", + "realestate", + "realtor", + "realty", + "recipes", + "red", + "redstone", + "redumbrella", + "rehab", + "reise", + "reisen", + "reit", + "reliance", + "ren", + "rent", + "rentals", + "repair", + "report", + "republican", + "rest", + "restaurant", + "review", + "reviews", + "rexroth", + "rich", + "richardli", + "ricoh", + "ril", + "rio", + "rip", + "rocher", + "rocks", + "rodeo", + "rogers", + "room", + "rsvp", + "rugby", + "ruhr", + "run", + "rwe", + "ryukyu", + "saarland", + "safe", + "safety", + "sakura", + "sale", + "salon", + "samsclub", + "samsung", + "sandvik", + "sandvikcoromant", + "sanofi", + "sap", + "sarl", + "sas", + "save", + "saxo", + "sbi", + "sbs", + "sca", + "scb", + "schaeffler", + "schmidt", + "scholarships", + "school", + "schule", + "schwarz", + "science", + "scot", + "search", + "seat", + "secure", + "security", + "seek", + "select", + "sener", + "services", + "ses", + "seven", + "sew", + "sex", + "sexy", + "sfr", + "shangrila", + "sharp", + "shaw", + "shell", + "shia", + "shiksha", + "shoes", + "shop", + "shopping", + "shouji", + "show", + "showtime", + "silk", + "sina", + "singles", + "site", + "ski", + "skin", + "sky", + "skype", + "sling", + "smart", + "smile", + "sncf", + "soccer", + "social", + "softbank", + "software", + "sohu", + "solar", + "solutions", + "song", + "sony", + "soy", + "spa", + "space", + "sport", + "spot", + "srl", + "stada", + "staples", + "star", + "statebank", + "statefarm", + "stc", + "stcgroup", + "stockholm", + "storage", + "store", + "stream", + "studio", + "study", + "style", + "sucks", + "supplies", + "supply", + "support", + "surf", + "surgery", + "suzuki", + "swatch", + "swiss", + "sydney", + "systems", + "tab", + "taipei", + "talk", + "taobao", + "target", + "tatamotors", + "tatar", + "tattoo", + "tax", + "taxi", + "tci", + "tdk", + "team", + "tech", + "technology", + "temasek", + "tennis", + "teva", + "thd", + "theater", + "theatre", + "tiaa", + "tickets", + "tienda", + "tiffany", + "tips", + "tires", + "tirol", + "tjmaxx", + "tjx", + "tkmaxx", + "tmall", + "today", + "tokyo", + "tools", + "top", + "toray", + "toshiba", + "total", + "tours", + "town", + "toyota", + "toys", + "trade", + "trading", + "training", + "travel", + "travelchannel", + "travelers", + "travelersinsurance", + "trust", + "trv", + "tube", + "tui", + "tunes", + "tushu", + "tvs", + "ubank", + "ubs", + "unicom", + "university", + "uno", + "uol", + "ups", + "vacations", + "vana", + "vanguard", + "vegas", + "ventures", + "verisign", + "versicherung", + "vet", + "viajes", + "video", + "vig", + "viking", + "villas", + "vin", + "vip", + "virgin", + "visa", + "vision", + "viva", + "vivo", + "vlaanderen", + "vodka", + "volkswagen", + "volvo", + "vote", + "voting", + "voto", + "voyage", + "vuelos", + "wales", + "walmart", + "walter", + "wang", + "wanggou", + "watch", + "watches", + "weather", + "weatherchannel", + "webcam", + "weber", + "website", + "wedding", + "weibo", + "weir", + "whoswho", + "wien", + "wiki", + "williamhill", + "win", + "windows", + "wine", + "winners", + "wme", + "wolterskluwer", + "woodside", + "work", + "works", + "world", + "wow", + "wtc", + "wtf", + "xbox", + "xerox", + "xfinity", + "xihuan", + "xin", + "\u0915\u0949\u092E", + "\u30BB\u30FC\u30EB", + "\u4F5B\u5C71", + "\u6148\u5584", + "\u96C6\u56E2", + "\u5728\u7EBF", + "\u70B9\u770B", + "\u0E04\u0E2D\u0E21", + "\u516B\u5366", + "\u0645\u0648\u0642\u0639", + "\u516C\u76CA", + "\u516C\u53F8", + "\u9999\u683C\u91CC\u62C9", + "\u7F51\u7AD9", + "\u79FB\u52A8", + "\u6211\u7231\u4F60", + "\u043C\u043E\u0441\u043A\u0432\u0430", + "\u043A\u0430\u0442\u043E\u043B\u0438\u043A", + "\u043E\u043D\u043B\u0430\u0439\u043D", + "\u0441\u0430\u0439\u0442", + "\u8054\u901A", + "\u05E7\u05D5\u05DD", + "\u65F6\u5C1A", + "\u5FAE\u535A", + "\u6DE1\u9A6C\u9521", + "\u30D5\u30A1\u30C3\u30B7\u30E7\u30F3", + "\u043E\u0440\u0433", + "\u0928\u0947\u091F", + "\u30B9\u30C8\u30A2", + "\u30A2\u30DE\u30BE\u30F3", + "\uC0BC\uC131", + "\u5546\u6807", + "\u5546\u5E97", + "\u5546\u57CE", + "\u0434\u0435\u0442\u0438", + "\u30DD\u30A4\u30F3\u30C8", + "\u65B0\u95FB", + "\u5BB6\u96FB", + "\u0643\u0648\u0645", + "\u4E2D\u6587\u7F51", + "\u4E2D\u4FE1", + "\u5A31\u4E50", + "\u8C37\u6B4C", + "\u96FB\u8A0A\u76C8\u79D1", + "\u8D2D\u7269", + "\u30AF\u30E9\u30A6\u30C9", + "\u901A\u8CA9", + "\u7F51\u5E97", + "\u0938\u0902\u0917\u0920\u0928", + "\u9910\u5385", + "\u7F51\u7EDC", + "\u043A\u043E\u043C", + "\u4E9A\u9A6C\u900A", + "\u8BFA\u57FA\u4E9A", + "\u98DF\u54C1", + "\u98DE\u5229\u6D66", + "\u624B\u673A", + "\u0627\u0631\u0627\u0645\u0643\u0648", + "\u0627\u0644\u0639\u0644\u064A\u0627\u0646", + "\u0627\u062A\u0635\u0627\u0644\u0627\u062A", + "\u0628\u0627\u0632\u0627\u0631", + "\u0627\u0628\u0648\u0638\u0628\u064A", + "\u0643\u0627\u062B\u0648\u0644\u064A\u0643", + "\u0647\u0645\u0631\u0627\u0647", + "\uB2F7\uCEF4", + "\u653F\u5E9C", + "\u0634\u0628\u0643\u0629", + "\u0628\u064A\u062A\u0643", + "\u0639\u0631\u0628", + "\u673A\u6784", + "\u7EC4\u7EC7\u673A\u6784", + "\u5065\u5EB7", + "\u62DB\u8058", + "\u0440\u0443\u0441", + "\u5927\u62FF", + "\u307F\u3093\u306A", + "\u30B0\u30FC\u30B0\u30EB", + "\u4E16\u754C", + "\u66F8\u7C4D", + "\u7F51\u5740", + "\uB2F7\uB137", + "\u30B3\u30E0", + "\u5929\u4E3B\u6559", + "\u6E38\u620F", + "verm\xF6gensberater", + "verm\xF6gensberatung", + "\u4F01\u4E1A", + "\u4FE1\u606F", + "\u5609\u91CC\u5927\u9152\u5E97", + "\u5609\u91CC", + "\u5E7F\u4E1C", + "\u653F\u52A1", + "xyz", + "yachts", + "yahoo", + "yamaxun", + "yandex", + "yodobashi", + "yoga", + "yokohama", + "you", + "youtube", + "yun", + "zappos", + "zara", + "zero", + "zip", + "zone", + "zuerich", + "cc.ua", + "inf.ua", + "ltd.ua", + "611.to", + "graphox.us", + "*.devcdnaccesso.com", + "adobeaemcloud.com", + "*.dev.adobeaemcloud.com", + "hlx.live", + "adobeaemcloud.net", + "hlx.page", + "hlx3.page", + "beep.pl", + "airkitapps.com", + "airkitapps-au.com", + "airkitapps.eu", + "aivencloud.com", + "barsy.ca", + "*.compute.estate", + "*.alces.network", + "kasserver.com", + "altervista.org", + "alwaysdata.net", + "cloudfront.net", + "*.compute.amazonaws.com", + "*.compute-1.amazonaws.com", + "*.compute.amazonaws.com.cn", + "us-east-1.amazonaws.com", + "cn-north-1.eb.amazonaws.com.cn", + "cn-northwest-1.eb.amazonaws.com.cn", + "elasticbeanstalk.com", + "ap-northeast-1.elasticbeanstalk.com", + "ap-northeast-2.elasticbeanstalk.com", + "ap-northeast-3.elasticbeanstalk.com", + "ap-south-1.elasticbeanstalk.com", + "ap-southeast-1.elasticbeanstalk.com", + "ap-southeast-2.elasticbeanstalk.com", + "ca-central-1.elasticbeanstalk.com", + "eu-central-1.elasticbeanstalk.com", + "eu-west-1.elasticbeanstalk.com", + "eu-west-2.elasticbeanstalk.com", + "eu-west-3.elasticbeanstalk.com", + "sa-east-1.elasticbeanstalk.com", + "us-east-1.elasticbeanstalk.com", + "us-east-2.elasticbeanstalk.com", + "us-gov-west-1.elasticbeanstalk.com", + "us-west-1.elasticbeanstalk.com", + "us-west-2.elasticbeanstalk.com", + "*.elb.amazonaws.com", + "*.elb.amazonaws.com.cn", + "awsglobalaccelerator.com", + "s3.amazonaws.com", + "s3-ap-northeast-1.amazonaws.com", + "s3-ap-northeast-2.amazonaws.com", + "s3-ap-south-1.amazonaws.com", + "s3-ap-southeast-1.amazonaws.com", + "s3-ap-southeast-2.amazonaws.com", + "s3-ca-central-1.amazonaws.com", + "s3-eu-central-1.amazonaws.com", + "s3-eu-west-1.amazonaws.com", + "s3-eu-west-2.amazonaws.com", + "s3-eu-west-3.amazonaws.com", + "s3-external-1.amazonaws.com", + "s3-fips-us-gov-west-1.amazonaws.com", + "s3-sa-east-1.amazonaws.com", + "s3-us-gov-west-1.amazonaws.com", + "s3-us-east-2.amazonaws.com", + "s3-us-west-1.amazonaws.com", + "s3-us-west-2.amazonaws.com", + "s3.ap-northeast-2.amazonaws.com", + "s3.ap-south-1.amazonaws.com", + "s3.cn-north-1.amazonaws.com.cn", + "s3.ca-central-1.amazonaws.com", + "s3.eu-central-1.amazonaws.com", + "s3.eu-west-2.amazonaws.com", + "s3.eu-west-3.amazonaws.com", + "s3.us-east-2.amazonaws.com", + "s3.dualstack.ap-northeast-1.amazonaws.com", + "s3.dualstack.ap-northeast-2.amazonaws.com", + "s3.dualstack.ap-south-1.amazonaws.com", + "s3.dualstack.ap-southeast-1.amazonaws.com", + "s3.dualstack.ap-southeast-2.amazonaws.com", + "s3.dualstack.ca-central-1.amazonaws.com", + "s3.dualstack.eu-central-1.amazonaws.com", + "s3.dualstack.eu-west-1.amazonaws.com", + "s3.dualstack.eu-west-2.amazonaws.com", + "s3.dualstack.eu-west-3.amazonaws.com", + "s3.dualstack.sa-east-1.amazonaws.com", + "s3.dualstack.us-east-1.amazonaws.com", + "s3.dualstack.us-east-2.amazonaws.com", + "s3-website-us-east-1.amazonaws.com", + "s3-website-us-west-1.amazonaws.com", + "s3-website-us-west-2.amazonaws.com", + "s3-website-ap-northeast-1.amazonaws.com", + "s3-website-ap-southeast-1.amazonaws.com", + "s3-website-ap-southeast-2.amazonaws.com", + "s3-website-eu-west-1.amazonaws.com", + "s3-website-sa-east-1.amazonaws.com", + "s3-website.ap-northeast-2.amazonaws.com", + "s3-website.ap-south-1.amazonaws.com", + "s3-website.ca-central-1.amazonaws.com", + "s3-website.eu-central-1.amazonaws.com", + "s3-website.eu-west-2.amazonaws.com", + "s3-website.eu-west-3.amazonaws.com", + "s3-website.us-east-2.amazonaws.com", + "t3l3p0rt.net", + "tele.amune.org", + "apigee.io", + "siiites.com", + "appspacehosted.com", + "appspaceusercontent.com", + "appudo.net", + "on-aptible.com", + "user.aseinet.ne.jp", + "gv.vc", + "d.gv.vc", + "user.party.eus", + "pimienta.org", + "poivron.org", + "potager.org", + "sweetpepper.org", + "myasustor.com", + "cdn.prod.atlassian-dev.net", + "translated.page", + "myfritz.net", + "onavstack.net", + "*.awdev.ca", + "*.advisor.ws", + "ecommerce-shop.pl", + "b-data.io", + "backplaneapp.io", + "balena-devices.com", + "rs.ba", + "*.banzai.cloud", + "app.banzaicloud.io", + "*.backyards.banzaicloud.io", + "base.ec", + "official.ec", + "buyshop.jp", + "fashionstore.jp", + "handcrafted.jp", + "kawaiishop.jp", + "supersale.jp", + "theshop.jp", + "shopselect.net", + "base.shop", + "*.beget.app", + "betainabox.com", + "bnr.la", + "bitbucket.io", + "blackbaudcdn.net", + "of.je", + "bluebite.io", + "boomla.net", + "boutir.com", + "boxfuse.io", + "square7.ch", + "bplaced.com", + "bplaced.de", + "square7.de", + "bplaced.net", + "square7.net", + "shop.brendly.rs", + "browsersafetymark.io", + "uk0.bigv.io", + "dh.bytemark.co.uk", + "vm.bytemark.co.uk", + "cafjs.com", + "mycd.eu", + "drr.ac", + "uwu.ai", + "carrd.co", + "crd.co", + "ju.mp", + "ae.org", + "br.com", + "cn.com", + "com.de", + "com.se", + "de.com", + "eu.com", + "gb.net", + "hu.net", + "jp.net", + "jpn.com", + "mex.com", + "ru.com", + "sa.com", + "se.net", + "uk.com", + "uk.net", + "us.com", + "za.bz", + "za.com", + "ar.com", + "hu.com", + "kr.com", + "no.com", + "qc.com", + "uy.com", + "africa.com", + "gr.com", + "in.net", + "web.in", + "us.org", + "co.com", + "aus.basketball", + "nz.basketball", + "radio.am", + "radio.fm", + "c.la", + "certmgr.org", + "cx.ua", + "discourse.group", + "discourse.team", + "cleverapps.io", + "clerk.app", + "clerkstage.app", + "*.lcl.dev", + "*.lclstage.dev", + "*.stg.dev", + "*.stgstage.dev", + "clickrising.net", + "c66.me", + "cloud66.ws", + "cloud66.zone", + "jdevcloud.com", + "wpdevcloud.com", + "cloudaccess.host", + "freesite.host", + "cloudaccess.net", + "cloudcontrolled.com", + "cloudcontrolapp.com", + "*.cloudera.site", + "pages.dev", + "trycloudflare.com", + "workers.dev", + "wnext.app", + "co.ca", + "*.otap.co", + "co.cz", + "c.cdn77.org", + "cdn77-ssl.net", + "r.cdn77.net", + "rsc.cdn77.org", + "ssl.origin.cdn77-secure.org", + "cloudns.asia", + "cloudns.biz", + "cloudns.club", + "cloudns.cc", + "cloudns.eu", + "cloudns.in", + "cloudns.info", + "cloudns.org", + "cloudns.pro", + "cloudns.pw", + "cloudns.us", + "cnpy.gdn", + "codeberg.page", + "co.nl", + "co.no", + "webhosting.be", + "hosting-cluster.nl", + "ac.ru", + "edu.ru", + "gov.ru", + "int.ru", + "mil.ru", + "test.ru", + "dyn.cosidns.de", + "dynamisches-dns.de", + "dnsupdater.de", + "internet-dns.de", + "l-o-g-i-n.de", + "dynamic-dns.info", + "feste-ip.net", + "knx-server.net", + "static-access.net", + "realm.cz", + "*.cryptonomic.net", + "cupcake.is", + "curv.dev", + "*.customer-oci.com", + "*.oci.customer-oci.com", + "*.ocp.customer-oci.com", + "*.ocs.customer-oci.com", + "cyon.link", + "cyon.site", + "fnwk.site", + "folionetwork.site", + "platform0.app", + "daplie.me", + "localhost.daplie.me", + "dattolocal.com", + "dattorelay.com", + "dattoweb.com", + "mydatto.com", + "dattolocal.net", + "mydatto.net", + "biz.dk", + "co.dk", + "firm.dk", + "reg.dk", + "store.dk", + "dyndns.dappnode.io", + "*.dapps.earth", + "*.bzz.dapps.earth", + "builtwithdark.com", + "demo.datadetect.com", + "instance.datadetect.com", + "edgestack.me", + "ddns5.com", + "debian.net", + "deno.dev", + "deno-staging.dev", + "dedyn.io", + "deta.app", + "deta.dev", + "*.rss.my.id", + "*.diher.solutions", + "discordsays.com", + "discordsez.com", + "jozi.biz", + "dnshome.de", + "online.th", + "shop.th", + "drayddns.com", + "shoparena.pl", + "dreamhosters.com", + "mydrobo.com", + "drud.io", + "drud.us", + "duckdns.org", + "bip.sh", + "bitbridge.net", + "dy.fi", + "tunk.org", + "dyndns-at-home.com", + "dyndns-at-work.com", + "dyndns-blog.com", + "dyndns-free.com", + "dyndns-home.com", + "dyndns-ip.com", + "dyndns-mail.com", + "dyndns-office.com", + "dyndns-pics.com", + "dyndns-remote.com", + "dyndns-server.com", + "dyndns-web.com", + "dyndns-wiki.com", + "dyndns-work.com", + "dyndns.biz", + "dyndns.info", + "dyndns.org", + "dyndns.tv", + "at-band-camp.net", + "ath.cx", + "barrel-of-knowledge.info", + "barrell-of-knowledge.info", + "better-than.tv", + "blogdns.com", + "blogdns.net", + "blogdns.org", + "blogsite.org", + "boldlygoingnowhere.org", + "broke-it.net", + "buyshouses.net", + "cechire.com", + "dnsalias.com", + "dnsalias.net", + "dnsalias.org", + "dnsdojo.com", + "dnsdojo.net", + "dnsdojo.org", + "does-it.net", + "doesntexist.com", + "doesntexist.org", + "dontexist.com", + "dontexist.net", + "dontexist.org", + "doomdns.com", + "doomdns.org", + "dvrdns.org", + "dyn-o-saur.com", + "dynalias.com", + "dynalias.net", + "dynalias.org", + "dynathome.net", + "dyndns.ws", + "endofinternet.net", + "endofinternet.org", + "endoftheinternet.org", + "est-a-la-maison.com", + "est-a-la-masion.com", + "est-le-patron.com", + "est-mon-blogueur.com", + "for-better.biz", + "for-more.biz", + "for-our.info", + "for-some.biz", + "for-the.biz", + "forgot.her.name", + "forgot.his.name", + "from-ak.com", + "from-al.com", + "from-ar.com", + "from-az.net", + "from-ca.com", + "from-co.net", + "from-ct.com", + "from-dc.com", + "from-de.com", + "from-fl.com", + "from-ga.com", + "from-hi.com", + "from-ia.com", + "from-id.com", + "from-il.com", + "from-in.com", + "from-ks.com", + "from-ky.com", + "from-la.net", + "from-ma.com", + "from-md.com", + "from-me.org", + "from-mi.com", + "from-mn.com", + "from-mo.com", + "from-ms.com", + "from-mt.com", + "from-nc.com", + "from-nd.com", + "from-ne.com", + "from-nh.com", + "from-nj.com", + "from-nm.com", + "from-nv.com", + "from-ny.net", + "from-oh.com", + "from-ok.com", + "from-or.com", + "from-pa.com", + "from-pr.com", + "from-ri.com", + "from-sc.com", + "from-sd.com", + "from-tn.com", + "from-tx.com", + "from-ut.com", + "from-va.com", + "from-vt.com", + "from-wa.com", + "from-wi.com", + "from-wv.com", + "from-wy.com", + "ftpaccess.cc", + "fuettertdasnetz.de", + "game-host.org", + "game-server.cc", + "getmyip.com", + "gets-it.net", + "go.dyndns.org", + "gotdns.com", + "gotdns.org", + "groks-the.info", + "groks-this.info", + "ham-radio-op.net", + "here-for-more.info", + "hobby-site.com", + "hobby-site.org", + "home.dyndns.org", + "homedns.org", + "homeftp.net", + "homeftp.org", + "homeip.net", + "homelinux.com", + "homelinux.net", + "homelinux.org", + "homeunix.com", + "homeunix.net", + "homeunix.org", + "iamallama.com", + "in-the-band.net", + "is-a-anarchist.com", + "is-a-blogger.com", + "is-a-bookkeeper.com", + "is-a-bruinsfan.org", + "is-a-bulls-fan.com", + "is-a-candidate.org", + "is-a-caterer.com", + "is-a-celticsfan.org", + "is-a-chef.com", + "is-a-chef.net", + "is-a-chef.org", + "is-a-conservative.com", + "is-a-cpa.com", + "is-a-cubicle-slave.com", + "is-a-democrat.com", + "is-a-designer.com", + "is-a-doctor.com", + "is-a-financialadvisor.com", + "is-a-geek.com", + "is-a-geek.net", + "is-a-geek.org", + "is-a-green.com", + "is-a-guru.com", + "is-a-hard-worker.com", + "is-a-hunter.com", + "is-a-knight.org", + "is-a-landscaper.com", + "is-a-lawyer.com", + "is-a-liberal.com", + "is-a-libertarian.com", + "is-a-linux-user.org", + "is-a-llama.com", + "is-a-musician.com", + "is-a-nascarfan.com", + "is-a-nurse.com", + "is-a-painter.com", + "is-a-patsfan.org", + "is-a-personaltrainer.com", + "is-a-photographer.com", + "is-a-player.com", + "is-a-republican.com", + "is-a-rockstar.com", + "is-a-socialist.com", + "is-a-soxfan.org", + "is-a-student.com", + "is-a-teacher.com", + "is-a-techie.com", + "is-a-therapist.com", + "is-an-accountant.com", + "is-an-actor.com", + "is-an-actress.com", + "is-an-anarchist.com", + "is-an-artist.com", + "is-an-engineer.com", + "is-an-entertainer.com", + "is-by.us", + "is-certified.com", + "is-found.org", + "is-gone.com", + "is-into-anime.com", + "is-into-cars.com", + "is-into-cartoons.com", + "is-into-games.com", + "is-leet.com", + "is-lost.org", + "is-not-certified.com", + "is-saved.org", + "is-slick.com", + "is-uberleet.com", + "is-very-bad.org", + "is-very-evil.org", + "is-very-good.org", + "is-very-nice.org", + "is-very-sweet.org", + "is-with-theband.com", + "isa-geek.com", + "isa-geek.net", + "isa-geek.org", + "isa-hockeynut.com", + "issmarterthanyou.com", + "isteingeek.de", + "istmein.de", + "kicks-ass.net", + "kicks-ass.org", + "knowsitall.info", + "land-4-sale.us", + "lebtimnetz.de", + "leitungsen.de", + "likes-pie.com", + "likescandy.com", + "merseine.nu", + "mine.nu", + "misconfused.org", + "mypets.ws", + "myphotos.cc", + "neat-url.com", + "office-on-the.net", + "on-the-web.tv", + "podzone.net", + "podzone.org", + "readmyblog.org", + "saves-the-whales.com", + "scrapper-site.net", + "scrapping.cc", + "selfip.biz", + "selfip.com", + "selfip.info", + "selfip.net", + "selfip.org", + "sells-for-less.com", + "sells-for-u.com", + "sells-it.net", + "sellsyourhome.org", + "servebbs.com", + "servebbs.net", + "servebbs.org", + "serveftp.net", + "serveftp.org", + "servegame.org", + "shacknet.nu", + "simple-url.com", + "space-to-rent.com", + "stuff-4-sale.org", + "stuff-4-sale.us", + "teaches-yoga.com", + "thruhere.net", + "traeumtgerade.de", + "webhop.biz", + "webhop.info", + "webhop.net", + "webhop.org", + "worse-than.tv", + "writesthisblog.com", + "ddnss.de", + "dyn.ddnss.de", + "dyndns.ddnss.de", + "dyndns1.de", + "dyn-ip24.de", + "home-webserver.de", + "dyn.home-webserver.de", + "myhome-server.de", + "ddnss.org", + "definima.net", + "definima.io", + "ondigitalocean.app", + "*.digitaloceanspaces.com", + "bci.dnstrace.pro", + "ddnsfree.com", + "ddnsgeek.com", + "giize.com", + "gleeze.com", + "kozow.com", + "loseyourip.com", + "ooguy.com", + "theworkpc.com", + "casacam.net", + "dynu.net", + "accesscam.org", + "camdvr.org", + "freeddns.org", + "mywire.org", + "webredirect.org", + "myddns.rocks", + "blogsite.xyz", + "dynv6.net", + "e4.cz", + "eero.online", + "eero-stage.online", + "elementor.cloud", + "elementor.cool", + "en-root.fr", + "mytuleap.com", + "tuleap-partners.com", + "encr.app", + "encoreapi.com", + "onred.one", + "staging.onred.one", + "eu.encoway.cloud", + "eu.org", + "al.eu.org", + "asso.eu.org", + "at.eu.org", + "au.eu.org", + "be.eu.org", + "bg.eu.org", + "ca.eu.org", + "cd.eu.org", + "ch.eu.org", + "cn.eu.org", + "cy.eu.org", + "cz.eu.org", + "de.eu.org", + "dk.eu.org", + "edu.eu.org", + "ee.eu.org", + "es.eu.org", + "fi.eu.org", + "fr.eu.org", + "gr.eu.org", + "hr.eu.org", + "hu.eu.org", + "ie.eu.org", + "il.eu.org", + "in.eu.org", + "int.eu.org", + "is.eu.org", + "it.eu.org", + "jp.eu.org", + "kr.eu.org", + "lt.eu.org", + "lu.eu.org", + "lv.eu.org", + "mc.eu.org", + "me.eu.org", + "mk.eu.org", + "mt.eu.org", + "my.eu.org", + "net.eu.org", + "ng.eu.org", + "nl.eu.org", + "no.eu.org", + "nz.eu.org", + "paris.eu.org", + "pl.eu.org", + "pt.eu.org", + "q-a.eu.org", + "ro.eu.org", + "ru.eu.org", + "se.eu.org", + "si.eu.org", + "sk.eu.org", + "tr.eu.org", + "uk.eu.org", + "us.eu.org", + "eurodir.ru", + "eu-1.evennode.com", + "eu-2.evennode.com", + "eu-3.evennode.com", + "eu-4.evennode.com", + "us-1.evennode.com", + "us-2.evennode.com", + "us-3.evennode.com", + "us-4.evennode.com", + "twmail.cc", + "twmail.net", + "twmail.org", + "mymailer.com.tw", + "url.tw", + "onfabrica.com", + "apps.fbsbx.com", + "ru.net", + "adygeya.ru", + "bashkiria.ru", + "bir.ru", + "cbg.ru", + "com.ru", + "dagestan.ru", + "grozny.ru", + "kalmykia.ru", + "kustanai.ru", + "marine.ru", + "mordovia.ru", + "msk.ru", + "mytis.ru", + "nalchik.ru", + "nov.ru", + "pyatigorsk.ru", + "spb.ru", + "vladikavkaz.ru", + "vladimir.ru", + "abkhazia.su", + "adygeya.su", + "aktyubinsk.su", + "arkhangelsk.su", + "armenia.su", + "ashgabad.su", + "azerbaijan.su", + "balashov.su", + "bashkiria.su", + "bryansk.su", + "bukhara.su", + "chimkent.su", + "dagestan.su", + "east-kazakhstan.su", + "exnet.su", + "georgia.su", + "grozny.su", + "ivanovo.su", + "jambyl.su", + "kalmykia.su", + "kaluga.su", + "karacol.su", + "karaganda.su", + "karelia.su", + "khakassia.su", + "krasnodar.su", + "kurgan.su", + "kustanai.su", + "lenug.su", + "mangyshlak.su", + "mordovia.su", + "msk.su", + "murmansk.su", + "nalchik.su", + "navoi.su", + "north-kazakhstan.su", + "nov.su", + "obninsk.su", + "penza.su", + "pokrovsk.su", + "sochi.su", + "spb.su", + "tashkent.su", + "termez.su", + "togliatti.su", + "troitsk.su", + "tselinograd.su", + "tula.su", + "tuva.su", + "vladikavkaz.su", + "vladimir.su", + "vologda.su", + "channelsdvr.net", + "u.channelsdvr.net", + "edgecompute.app", + "fastly-terrarium.com", + "fastlylb.net", + "map.fastlylb.net", + "freetls.fastly.net", + "map.fastly.net", + "a.prod.fastly.net", + "global.prod.fastly.net", + "a.ssl.fastly.net", + "b.ssl.fastly.net", + "global.ssl.fastly.net", + "fastvps-server.com", + "fastvps.host", + "myfast.host", + "fastvps.site", + "myfast.space", + "fedorainfracloud.org", + "fedorapeople.org", + "cloud.fedoraproject.org", + "app.os.fedoraproject.org", + "app.os.stg.fedoraproject.org", + "conn.uk", + "copro.uk", + "hosp.uk", + "mydobiss.com", + "fh-muenster.io", + "filegear.me", + "filegear-au.me", + "filegear-de.me", + "filegear-gb.me", + "filegear-ie.me", + "filegear-jp.me", + "filegear-sg.me", + "firebaseapp.com", + "fireweb.app", + "flap.id", + "onflashdrive.app", + "fldrv.com", + "fly.dev", + "edgeapp.net", + "shw.io", + "flynnhosting.net", + "forgeblocks.com", + "id.forgerock.io", + "framer.app", + "framercanvas.com", + "*.frusky.de", + "ravpage.co.il", + "0e.vc", + "freebox-os.com", + "freeboxos.com", + "fbx-os.fr", + "fbxos.fr", + "freebox-os.fr", + "freeboxos.fr", + "freedesktop.org", + "freemyip.com", + "wien.funkfeuer.at", + "*.futurecms.at", + "*.ex.futurecms.at", + "*.in.futurecms.at", + "futurehosting.at", + "futuremailing.at", + "*.ex.ortsinfo.at", + "*.kunden.ortsinfo.at", + "*.statics.cloud", + "independent-commission.uk", + "independent-inquest.uk", + "independent-inquiry.uk", + "independent-panel.uk", + "independent-review.uk", + "public-inquiry.uk", + "royal-commission.uk", + "campaign.gov.uk", + "service.gov.uk", + "api.gov.uk", + "gehirn.ne.jp", + "usercontent.jp", + "gentapps.com", + "gentlentapis.com", + "lab.ms", + "cdn-edges.net", + "ghost.io", + "gsj.bz", + "githubusercontent.com", + "githubpreview.dev", + "github.io", + "gitlab.io", + "gitapp.si", + "gitpage.si", + "glitch.me", + "nog.community", + "co.ro", + "shop.ro", + "lolipop.io", + "angry.jp", + "babyblue.jp", + "babymilk.jp", + "backdrop.jp", + "bambina.jp", + "bitter.jp", + "blush.jp", + "boo.jp", + "boy.jp", + "boyfriend.jp", + "but.jp", + "candypop.jp", + "capoo.jp", + "catfood.jp", + "cheap.jp", + "chicappa.jp", + "chillout.jp", + "chips.jp", + "chowder.jp", + "chu.jp", + "ciao.jp", + "cocotte.jp", + "coolblog.jp", + "cranky.jp", + "cutegirl.jp", + "daa.jp", + "deca.jp", + "deci.jp", + "digick.jp", + "egoism.jp", + "fakefur.jp", + "fem.jp", + "flier.jp", + "floppy.jp", + "fool.jp", + "frenchkiss.jp", + "girlfriend.jp", + "girly.jp", + "gloomy.jp", + "gonna.jp", + "greater.jp", + "hacca.jp", + "heavy.jp", + "her.jp", + "hiho.jp", + "hippy.jp", + "holy.jp", + "hungry.jp", + "icurus.jp", + "itigo.jp", + "jellybean.jp", + "kikirara.jp", + "kill.jp", + "kilo.jp", + "kuron.jp", + "littlestar.jp", + "lolipopmc.jp", + "lolitapunk.jp", + "lomo.jp", + "lovepop.jp", + "lovesick.jp", + "main.jp", + "mods.jp", + "mond.jp", + "mongolian.jp", + "moo.jp", + "namaste.jp", + "nikita.jp", + "nobushi.jp", + "noor.jp", + "oops.jp", + "parallel.jp", + "parasite.jp", + "pecori.jp", + "peewee.jp", + "penne.jp", + "pepper.jp", + "perma.jp", + "pigboat.jp", + "pinoko.jp", + "punyu.jp", + "pupu.jp", + "pussycat.jp", + "pya.jp", + "raindrop.jp", + "readymade.jp", + "sadist.jp", + "schoolbus.jp", + "secret.jp", + "staba.jp", + "stripper.jp", + "sub.jp", + "sunnyday.jp", + "thick.jp", + "tonkotsu.jp", + "under.jp", + "upper.jp", + "velvet.jp", + "verse.jp", + "versus.jp", + "vivian.jp", + "watson.jp", + "weblike.jp", + "whitesnow.jp", + "zombie.jp", + "heteml.net", + "cloudapps.digital", + "london.cloudapps.digital", + "pymnt.uk", + "homeoffice.gov.uk", + "ro.im", + "goip.de", + "run.app", + "a.run.app", + "web.app", + "*.0emm.com", + "appspot.com", + "*.r.appspot.com", + "codespot.com", + "googleapis.com", + "googlecode.com", + "pagespeedmobilizer.com", + "publishproxy.com", + "withgoogle.com", + "withyoutube.com", + "*.gateway.dev", + "cloud.goog", + "translate.goog", + "*.usercontent.goog", + "cloudfunctions.net", + "blogspot.ae", + "blogspot.al", + "blogspot.am", + "blogspot.ba", + "blogspot.be", + "blogspot.bg", + "blogspot.bj", + "blogspot.ca", + "blogspot.cf", + "blogspot.ch", + "blogspot.cl", + "blogspot.co.at", + "blogspot.co.id", + "blogspot.co.il", + "blogspot.co.ke", + "blogspot.co.nz", + "blogspot.co.uk", + "blogspot.co.za", + "blogspot.com", + "blogspot.com.ar", + "blogspot.com.au", + "blogspot.com.br", + "blogspot.com.by", + "blogspot.com.co", + "blogspot.com.cy", + "blogspot.com.ee", + "blogspot.com.eg", + "blogspot.com.es", + "blogspot.com.mt", + "blogspot.com.ng", + "blogspot.com.tr", + "blogspot.com.uy", + "blogspot.cv", + "blogspot.cz", + "blogspot.de", + "blogspot.dk", + "blogspot.fi", + "blogspot.fr", + "blogspot.gr", + "blogspot.hk", + "blogspot.hr", + "blogspot.hu", + "blogspot.ie", + "blogspot.in", + "blogspot.is", + "blogspot.it", + "blogspot.jp", + "blogspot.kr", + "blogspot.li", + "blogspot.lt", + "blogspot.lu", + "blogspot.md", + "blogspot.mk", + "blogspot.mr", + "blogspot.mx", + "blogspot.my", + "blogspot.nl", + "blogspot.no", + "blogspot.pe", + "blogspot.pt", + "blogspot.qa", + "blogspot.re", + "blogspot.ro", + "blogspot.rs", + "blogspot.ru", + "blogspot.se", + "blogspot.sg", + "blogspot.si", + "blogspot.sk", + "blogspot.sn", + "blogspot.td", + "blogspot.tw", + "blogspot.ug", + "blogspot.vn", + "goupile.fr", + "gov.nl", + "awsmppl.com", + "g\xFCnstigbestellen.de", + "g\xFCnstigliefern.de", + "fin.ci", + "free.hr", + "caa.li", + "ua.rs", + "conf.se", + "hs.zone", + "hs.run", + "hashbang.sh", + "hasura.app", + "hasura-app.io", + "pages.it.hs-heilbronn.de", + "hepforge.org", + "herokuapp.com", + "herokussl.com", + "ravendb.cloud", + "myravendb.com", + "ravendb.community", + "ravendb.me", + "development.run", + "ravendb.run", + "homesklep.pl", + "secaas.hk", + "hoplix.shop", + "orx.biz", + "biz.gl", + "col.ng", + "firm.ng", + "gen.ng", + "ltd.ng", + "ngo.ng", + "edu.scot", + "sch.so", + "hostyhosting.io", + "h\xE4kkinen.fi", + "*.moonscale.io", + "moonscale.net", + "iki.fi", + "ibxos.it", + "iliadboxos.it", + "impertrixcdn.com", + "impertrix.com", + "smushcdn.com", + "wphostedmail.com", + "wpmucdn.com", + "tempurl.host", + "wpmudev.host", + "dyn-berlin.de", + "in-berlin.de", + "in-brb.de", + "in-butter.de", + "in-dsl.de", + "in-dsl.net", + "in-dsl.org", + "in-vpn.de", + "in-vpn.net", + "in-vpn.org", + "biz.at", + "info.at", + "info.cx", + "ac.leg.br", + "al.leg.br", + "am.leg.br", + "ap.leg.br", + "ba.leg.br", + "ce.leg.br", + "df.leg.br", + "es.leg.br", + "go.leg.br", + "ma.leg.br", + "mg.leg.br", + "ms.leg.br", + "mt.leg.br", + "pa.leg.br", + "pb.leg.br", + "pe.leg.br", + "pi.leg.br", + "pr.leg.br", + "rj.leg.br", + "rn.leg.br", + "ro.leg.br", + "rr.leg.br", + "rs.leg.br", + "sc.leg.br", + "se.leg.br", + "sp.leg.br", + "to.leg.br", + "pixolino.com", + "na4u.ru", + "iopsys.se", + "ipifony.net", + "iservschule.de", + "mein-iserv.de", + "schulplattform.de", + "schulserver.de", + "test-iserv.de", + "iserv.dev", + "iobb.net", + "mel.cloudlets.com.au", + "cloud.interhostsolutions.be", + "users.scale.virtualcloud.com.br", + "mycloud.by", + "alp1.ae.flow.ch", + "appengine.flow.ch", + "es-1.axarnet.cloud", + "diadem.cloud", + "vip.jelastic.cloud", + "jele.cloud", + "it1.eur.aruba.jenv-aruba.cloud", + "it1.jenv-aruba.cloud", + "keliweb.cloud", + "cs.keliweb.cloud", + "oxa.cloud", + "tn.oxa.cloud", + "uk.oxa.cloud", + "primetel.cloud", + "uk.primetel.cloud", + "ca.reclaim.cloud", + "uk.reclaim.cloud", + "us.reclaim.cloud", + "ch.trendhosting.cloud", + "de.trendhosting.cloud", + "jele.club", + "amscompute.com", + "clicketcloud.com", + "dopaas.com", + "hidora.com", + "paas.hosted-by-previder.com", + "rag-cloud.hosteur.com", + "rag-cloud-ch.hosteur.com", + "jcloud.ik-server.com", + "jcloud-ver-jpc.ik-server.com", + "demo.jelastic.com", + "kilatiron.com", + "paas.massivegrid.com", + "jed.wafaicloud.com", + "lon.wafaicloud.com", + "ryd.wafaicloud.com", + "j.scaleforce.com.cy", + "jelastic.dogado.eu", + "fi.cloudplatform.fi", + "demo.datacenter.fi", + "paas.datacenter.fi", + "jele.host", + "mircloud.host", + "paas.beebyte.io", + "sekd1.beebyteapp.io", + "jele.io", + "cloud-fr1.unispace.io", + "jc.neen.it", + "cloud.jelastic.open.tim.it", + "jcloud.kz", + "upaas.kazteleport.kz", + "cloudjiffy.net", + "fra1-de.cloudjiffy.net", + "west1-us.cloudjiffy.net", + "jls-sto1.elastx.net", + "jls-sto2.elastx.net", + "jls-sto3.elastx.net", + "faststacks.net", + "fr-1.paas.massivegrid.net", + "lon-1.paas.massivegrid.net", + "lon-2.paas.massivegrid.net", + "ny-1.paas.massivegrid.net", + "ny-2.paas.massivegrid.net", + "sg-1.paas.massivegrid.net", + "jelastic.saveincloud.net", + "nordeste-idc.saveincloud.net", + "j.scaleforce.net", + "jelastic.tsukaeru.net", + "sdscloud.pl", + "unicloud.pl", + "mircloud.ru", + "jelastic.regruhosting.ru", + "enscaled.sg", + "jele.site", + "jelastic.team", + "orangecloud.tn", + "j.layershift.co.uk", + "phx.enscaled.us", + "mircloud.us", + "myjino.ru", + "*.hosting.myjino.ru", + "*.landing.myjino.ru", + "*.spectrum.myjino.ru", + "*.vps.myjino.ru", + "jotelulu.cloud", + "*.triton.zone", + "*.cns.joyent.com", + "js.org", + "kaas.gg", + "khplay.nl", + "ktistory.com", + "kapsi.fi", + "keymachine.de", + "kinghost.net", + "uni5.net", + "knightpoint.systems", + "koobin.events", + "oya.to", + "kuleuven.cloud", + "ezproxy.kuleuven.be", + "co.krd", + "edu.krd", + "krellian.net", + "webthings.io", + "git-repos.de", + "lcube-server.de", + "svn-repos.de", + "leadpages.co", + "lpages.co", + "lpusercontent.com", + "lelux.site", + "co.business", + "co.education", + "co.events", + "co.financial", + "co.network", + "co.place", + "co.technology", + "app.lmpm.com", + "linkyard.cloud", + "linkyard-cloud.ch", + "members.linode.com", + "*.nodebalancer.linode.com", + "*.linodeobjects.com", + "ip.linodeusercontent.com", + "we.bs", + "*.user.localcert.dev", + "localzone.xyz", + "loginline.app", + "loginline.dev", + "loginline.io", + "loginline.services", + "loginline.site", + "servers.run", + "lohmus.me", + "krasnik.pl", + "leczna.pl", + "lubartow.pl", + "lublin.pl", + "poniatowa.pl", + "swidnik.pl", + "glug.org.uk", + "lug.org.uk", + "lugs.org.uk", + "barsy.bg", + "barsy.co.uk", + "barsyonline.co.uk", + "barsycenter.com", + "barsyonline.com", + "barsy.club", + "barsy.de", + "barsy.eu", + "barsy.in", + "barsy.info", + "barsy.io", + "barsy.me", + "barsy.menu", + "barsy.mobi", + "barsy.net", + "barsy.online", + "barsy.org", + "barsy.pro", + "barsy.pub", + "barsy.ro", + "barsy.shop", + "barsy.site", + "barsy.support", + "barsy.uk", + "*.magentosite.cloud", + "mayfirst.info", + "mayfirst.org", + "hb.cldmail.ru", + "cn.vu", + "mazeplay.com", + "mcpe.me", + "mcdir.me", + "mcdir.ru", + "mcpre.ru", + "vps.mcdir.ru", + "mediatech.by", + "mediatech.dev", + "hra.health", + "miniserver.com", + "memset.net", + "messerli.app", + "*.cloud.metacentrum.cz", + "custom.metacentrum.cz", + "flt.cloud.muni.cz", + "usr.cloud.muni.cz", + "meteorapp.com", + "eu.meteorapp.com", + "co.pl", + "*.azurecontainer.io", + "azurewebsites.net", + "azure-mobile.net", + "cloudapp.net", + "azurestaticapps.net", + "1.azurestaticapps.net", + "centralus.azurestaticapps.net", + "eastasia.azurestaticapps.net", + "eastus2.azurestaticapps.net", + "westeurope.azurestaticapps.net", + "westus2.azurestaticapps.net", + "csx.cc", + "mintere.site", + "forte.id", + "mozilla-iot.org", + "bmoattachments.org", + "net.ru", + "org.ru", + "pp.ru", + "hostedpi.com", + "customer.mythic-beasts.com", + "caracal.mythic-beasts.com", + "fentiger.mythic-beasts.com", + "lynx.mythic-beasts.com", + "ocelot.mythic-beasts.com", + "oncilla.mythic-beasts.com", + "onza.mythic-beasts.com", + "sphinx.mythic-beasts.com", + "vs.mythic-beasts.com", + "x.mythic-beasts.com", + "yali.mythic-beasts.com", + "cust.retrosnub.co.uk", + "ui.nabu.casa", + "pony.club", + "of.fashion", + "in.london", + "of.london", + "from.marketing", + "with.marketing", + "for.men", + "repair.men", + "and.mom", + "for.mom", + "for.one", + "under.one", + "for.sale", + "that.win", + "from.work", + "to.work", + "cloud.nospamproxy.com", + "netlify.app", + "4u.com", + "ngrok.io", + "nh-serv.co.uk", + "nfshost.com", + "*.developer.app", + "noop.app", + "*.northflank.app", + "*.build.run", + "*.code.run", + "*.database.run", + "*.migration.run", + "noticeable.news", + "dnsking.ch", + "mypi.co", + "n4t.co", + "001www.com", + "ddnslive.com", + "myiphost.com", + "forumz.info", + "16-b.it", + "32-b.it", + "64-b.it", + "soundcast.me", + "tcp4.me", + "dnsup.net", + "hicam.net", + "now-dns.net", + "ownip.net", + "vpndns.net", + "dynserv.org", + "now-dns.org", + "x443.pw", + "now-dns.top", + "ntdll.top", + "freeddns.us", + "crafting.xyz", + "zapto.xyz", + "nsupdate.info", + "nerdpol.ovh", + "blogsyte.com", + "brasilia.me", + "cable-modem.org", + "ciscofreak.com", + "collegefan.org", + "couchpotatofries.org", + "damnserver.com", + "ddns.me", + "ditchyourip.com", + "dnsfor.me", + "dnsiskinky.com", + "dvrcam.info", + "dynns.com", + "eating-organic.net", + "fantasyleague.cc", + "geekgalaxy.com", + "golffan.us", + "health-carereform.com", + "homesecuritymac.com", + "homesecuritypc.com", + "hopto.me", + "ilovecollege.info", + "loginto.me", + "mlbfan.org", + "mmafan.biz", + "myactivedirectory.com", + "mydissent.net", + "myeffect.net", + "mymediapc.net", + "mypsx.net", + "mysecuritycamera.com", + "mysecuritycamera.net", + "mysecuritycamera.org", + "net-freaks.com", + "nflfan.org", + "nhlfan.net", + "no-ip.ca", + "no-ip.co.uk", + "no-ip.net", + "noip.us", + "onthewifi.com", + "pgafan.net", + "point2this.com", + "pointto.us", + "privatizehealthinsurance.net", + "quicksytes.com", + "read-books.org", + "securitytactics.com", + "serveexchange.com", + "servehumour.com", + "servep2p.com", + "servesarcasm.com", + "stufftoread.com", + "ufcfan.org", + "unusualperson.com", + "workisboring.com", + "3utilities.com", + "bounceme.net", + "ddns.net", + "ddnsking.com", + "gotdns.ch", + "hopto.org", + "myftp.biz", + "myftp.org", + "myvnc.com", + "no-ip.biz", + "no-ip.info", + "no-ip.org", + "noip.me", + "redirectme.net", + "servebeer.com", + "serveblog.net", + "servecounterstrike.com", + "serveftp.com", + "servegame.com", + "servehalflife.com", + "servehttp.com", + "serveirc.com", + "serveminecraft.net", + "servemp3.com", + "servepics.com", + "servequake.com", + "sytes.net", + "webhop.me", + "zapto.org", + "stage.nodeart.io", + "pcloud.host", + "nyc.mn", + "static.observableusercontent.com", + "cya.gg", + "omg.lol", + "cloudycluster.net", + "omniwe.site", + "service.one", + "nid.io", + "opensocial.site", + "opencraft.hosting", + "orsites.com", + "operaunite.com", + "tech.orange", + "authgear-staging.com", + "authgearapps.com", + "skygearapp.com", + "outsystemscloud.com", + "*.webpaas.ovh.net", + "*.hosting.ovh.net", + "ownprovider.com", + "own.pm", + "*.owo.codes", + "ox.rs", + "oy.lc", + "pgfog.com", + "pagefrontapp.com", + "pagexl.com", + "*.paywhirl.com", + "bar0.net", + "bar1.net", + "bar2.net", + "rdv.to", + "art.pl", + "gliwice.pl", + "krakow.pl", + "poznan.pl", + "wroc.pl", + "zakopane.pl", + "pantheonsite.io", + "gotpantheon.com", + "mypep.link", + "perspecta.cloud", + "lk3.ru", + "on-web.fr", + "bc.platform.sh", + "ent.platform.sh", + "eu.platform.sh", + "us.platform.sh", + "*.platformsh.site", + "*.tst.site", + "platter-app.com", + "platter-app.dev", + "platterp.us", + "pdns.page", + "plesk.page", + "pleskns.com", + "dyn53.io", + "onporter.run", + "co.bn", + "postman-echo.com", + "pstmn.io", + "mock.pstmn.io", + "httpbin.org", + "prequalifyme.today", + "xen.prgmr.com", + "priv.at", + "prvcy.page", + "*.dweb.link", + "protonet.io", + "chirurgiens-dentistes-en-france.fr", + "byen.site", + "pubtls.org", + "pythonanywhere.com", + "eu.pythonanywhere.com", + "qoto.io", + "qualifioapp.com", + "qbuser.com", + "cloudsite.builders", + "instances.spawn.cc", + "instantcloud.cn", + "ras.ru", + "qa2.com", + "qcx.io", + "*.sys.qcx.io", + "dev-myqnapcloud.com", + "alpha-myqnapcloud.com", + "myqnapcloud.com", + "*.quipelements.com", + "vapor.cloud", + "vaporcloud.io", + "rackmaze.com", + "rackmaze.net", + "g.vbrplsbx.io", + "*.on-k3s.io", + "*.on-rancher.cloud", + "*.on-rio.io", + "readthedocs.io", + "rhcloud.com", + "app.render.com", + "onrender.com", + "repl.co", + "id.repl.co", + "repl.run", + "resindevice.io", + "devices.resinstaging.io", + "hzc.io", + "wellbeingzone.eu", + "wellbeingzone.co.uk", + "adimo.co.uk", + "itcouldbewor.se", + "git-pages.rit.edu", + "rocky.page", + "\u0431\u0438\u0437.\u0440\u0443\u0441", + "\u043A\u043E\u043C.\u0440\u0443\u0441", + "\u043A\u0440\u044B\u043C.\u0440\u0443\u0441", + "\u043C\u0438\u0440.\u0440\u0443\u0441", + "\u043C\u0441\u043A.\u0440\u0443\u0441", + "\u043E\u0440\u0433.\u0440\u0443\u0441", + "\u0441\u0430\u043C\u0430\u0440\u0430.\u0440\u0443\u0441", + "\u0441\u043E\u0447\u0438.\u0440\u0443\u0441", + "\u0441\u043F\u0431.\u0440\u0443\u0441", + "\u044F.\u0440\u0443\u0441", + "*.builder.code.com", + "*.dev-builder.code.com", + "*.stg-builder.code.com", + "sandcats.io", + "logoip.de", + "logoip.com", + "fr-par-1.baremetal.scw.cloud", + "fr-par-2.baremetal.scw.cloud", + "nl-ams-1.baremetal.scw.cloud", + "fnc.fr-par.scw.cloud", + "functions.fnc.fr-par.scw.cloud", + "k8s.fr-par.scw.cloud", + "nodes.k8s.fr-par.scw.cloud", + "s3.fr-par.scw.cloud", + "s3-website.fr-par.scw.cloud", + "whm.fr-par.scw.cloud", + "priv.instances.scw.cloud", + "pub.instances.scw.cloud", + "k8s.scw.cloud", + "k8s.nl-ams.scw.cloud", + "nodes.k8s.nl-ams.scw.cloud", + "s3.nl-ams.scw.cloud", + "s3-website.nl-ams.scw.cloud", + "whm.nl-ams.scw.cloud", + "k8s.pl-waw.scw.cloud", + "nodes.k8s.pl-waw.scw.cloud", + "s3.pl-waw.scw.cloud", + "s3-website.pl-waw.scw.cloud", + "scalebook.scw.cloud", + "smartlabeling.scw.cloud", + "dedibox.fr", + "schokokeks.net", + "gov.scot", + "service.gov.scot", + "scrysec.com", + "firewall-gateway.com", + "firewall-gateway.de", + "my-gateway.de", + "my-router.de", + "spdns.de", + "spdns.eu", + "firewall-gateway.net", + "my-firewall.org", + "myfirewall.org", + "spdns.org", + "seidat.net", + "sellfy.store", + "senseering.net", + "minisite.ms", + "magnet.page", + "biz.ua", + "co.ua", + "pp.ua", + "shiftcrypto.dev", + "shiftcrypto.io", + "shiftedit.io", + "myshopblocks.com", + "myshopify.com", + "shopitsite.com", + "shopware.store", + "mo-siemens.io", + "1kapp.com", + "appchizi.com", + "applinzi.com", + "sinaapp.com", + "vipsinaapp.com", + "siteleaf.net", + "bounty-full.com", + "alpha.bounty-full.com", + "beta.bounty-full.com", + "small-web.org", + "vp4.me", + "try-snowplow.com", + "srht.site", + "stackhero-network.com", + "musician.io", + "novecore.site", + "static.land", + "dev.static.land", + "sites.static.land", + "storebase.store", + "vps-host.net", + "atl.jelastic.vps-host.net", + "njs.jelastic.vps-host.net", + "ric.jelastic.vps-host.net", + "playstation-cloud.com", + "apps.lair.io", + "*.stolos.io", + "spacekit.io", + "customer.speedpartner.de", + "myspreadshop.at", + "myspreadshop.com.au", + "myspreadshop.be", + "myspreadshop.ca", + "myspreadshop.ch", + "myspreadshop.com", + "myspreadshop.de", + "myspreadshop.dk", + "myspreadshop.es", + "myspreadshop.fi", + "myspreadshop.fr", + "myspreadshop.ie", + "myspreadshop.it", + "myspreadshop.net", + "myspreadshop.nl", + "myspreadshop.no", + "myspreadshop.pl", + "myspreadshop.se", + "myspreadshop.co.uk", + "api.stdlib.com", + "storj.farm", + "utwente.io", + "soc.srcf.net", + "user.srcf.net", + "temp-dns.com", + "supabase.co", + "supabase.in", + "supabase.net", + "su.paba.se", + "*.s5y.io", + "*.sensiosite.cloud", + "syncloud.it", + "dscloud.biz", + "direct.quickconnect.cn", + "dsmynas.com", + "familyds.com", + "diskstation.me", + "dscloud.me", + "i234.me", + "myds.me", + "synology.me", + "dscloud.mobi", + "dsmynas.net", + "familyds.net", + "dsmynas.org", + "familyds.org", + "vpnplus.to", + "direct.quickconnect.to", + "tabitorder.co.il", + "taifun-dns.de", + "beta.tailscale.net", + "ts.net", + "gda.pl", + "gdansk.pl", + "gdynia.pl", + "med.pl", + "sopot.pl", + "site.tb-hosting.com", + "edugit.io", + "s3.teckids.org", + "telebit.app", + "telebit.io", + "*.telebit.xyz", + "gwiddle.co.uk", + "*.firenet.ch", + "*.svc.firenet.ch", + "reservd.com", + "thingdustdata.com", + "cust.dev.thingdust.io", + "cust.disrec.thingdust.io", + "cust.prod.thingdust.io", + "cust.testing.thingdust.io", + "reservd.dev.thingdust.io", + "reservd.disrec.thingdust.io", + "reservd.testing.thingdust.io", + "tickets.io", + "arvo.network", + "azimuth.network", + "tlon.network", + "torproject.net", + "pages.torproject.net", + "bloxcms.com", + "townnews-staging.com", + "tbits.me", + "12hp.at", + "2ix.at", + "4lima.at", + "lima-city.at", + "12hp.ch", + "2ix.ch", + "4lima.ch", + "lima-city.ch", + "trafficplex.cloud", + "de.cool", + "12hp.de", + "2ix.de", + "4lima.de", + "lima-city.de", + "1337.pictures", + "clan.rip", + "lima-city.rocks", + "webspace.rocks", + "lima.zone", + "*.transurl.be", + "*.transurl.eu", + "*.transurl.nl", + "site.transip.me", + "tuxfamily.org", + "dd-dns.de", + "diskstation.eu", + "diskstation.org", + "dray-dns.de", + "draydns.de", + "dyn-vpn.de", + "dynvpn.de", + "mein-vigor.de", + "my-vigor.de", + "my-wan.de", + "syno-ds.de", + "synology-diskstation.de", + "synology-ds.de", + "typedream.app", + "pro.typeform.com", + "uber.space", + "*.uberspace.de", + "hk.com", + "hk.org", + "ltd.hk", + "inc.hk", + "name.pm", + "sch.tf", + "biz.wf", + "sch.wf", + "org.yt", + "virtualuser.de", + "virtual-user.de", + "upli.io", + "urown.cloud", + "dnsupdate.info", + "lib.de.us", + "2038.io", + "vercel.app", + "vercel.dev", + "now.sh", + "router.management", + "v-info.info", + "voorloper.cloud", + "neko.am", + "nyaa.am", + "be.ax", + "cat.ax", + "es.ax", + "eu.ax", + "gg.ax", + "mc.ax", + "us.ax", + "xy.ax", + "nl.ci", + "xx.gl", + "app.gp", + "blog.gt", + "de.gt", + "to.gt", + "be.gy", + "cc.hn", + "blog.kg", + "io.kg", + "jp.kg", + "tv.kg", + "uk.kg", + "us.kg", + "de.ls", + "at.md", + "de.md", + "jp.md", + "to.md", + "indie.porn", + "vxl.sh", + "ch.tc", + "me.tc", + "we.tc", + "nyan.to", + "at.vg", + "blog.vu", + "dev.vu", + "me.vu", + "v.ua", + "*.vultrobjects.com", + "wafflecell.com", + "*.webhare.dev", + "reserve-online.net", + "reserve-online.com", + "bookonline.app", + "hotelwithflight.com", + "wedeploy.io", + "wedeploy.me", + "wedeploy.sh", + "remotewd.com", + "pages.wiardweb.com", + "wmflabs.org", + "toolforge.org", + "wmcloud.org", + "panel.gg", + "daemon.panel.gg", + "messwithdns.com", + "woltlab-demo.com", + "myforum.community", + "community-pro.de", + "diskussionsbereich.de", + "community-pro.net", + "meinforum.net", + "affinitylottery.org.uk", + "raffleentry.org.uk", + "weeklylottery.org.uk", + "wpenginepowered.com", + "js.wpenginepowered.com", + "wixsite.com", + "editorx.io", + "half.host", + "xnbay.com", + "u2.xnbay.com", + "u2-local.xnbay.com", + "cistron.nl", + "demon.nl", + "xs4all.space", + "yandexcloud.net", + "storage.yandexcloud.net", + "website.yandexcloud.net", + "official.academy", + "yolasite.com", + "ybo.faith", + "yombo.me", + "homelink.one", + "ybo.party", + "ybo.review", + "ybo.science", + "ybo.trade", + "ynh.fr", + "nohost.me", + "noho.st", + "za.net", + "za.org", + "bss.design", + "basicserver.io", + "virtualserver.io", + "enterprisecloud.nu" + ]; + } +}); + +// node_modules/psl/index.js +var require_psl = __commonJS({ + "node_modules/psl/index.js"(exports) { + "use strict"; + var Punycode = require_punycode(); + var internals = {}; + internals.rules = require_rules().map(function(rule) { + return { + rule, + suffix: rule.replace(/^(\*\.|\!)/, ""), + punySuffix: -1, + wildcard: rule.charAt(0) === "*", + exception: rule.charAt(0) === "!" + }; + }); + internals.endsWith = function(str, suffix) { + return str.indexOf(suffix, str.length - suffix.length) !== -1; + }; + internals.findRule = function(domain) { + var punyDomain = Punycode.toASCII(domain); + return internals.rules.reduce(function(memo, rule) { + if (rule.punySuffix === -1) { + rule.punySuffix = Punycode.toASCII(rule.suffix); + } + if (!internals.endsWith(punyDomain, "." + rule.punySuffix) && punyDomain !== rule.punySuffix) { + return memo; + } + return rule; + }, null); + }; + exports.errorCodes = { + DOMAIN_TOO_SHORT: "Domain name too short.", + DOMAIN_TOO_LONG: "Domain name too long. It should be no more than 255 chars.", + LABEL_STARTS_WITH_DASH: "Domain name label can not start with a dash.", + LABEL_ENDS_WITH_DASH: "Domain name label can not end with a dash.", + LABEL_TOO_LONG: "Domain name label should be at most 63 chars long.", + LABEL_TOO_SHORT: "Domain name label should be at least 1 character long.", + LABEL_INVALID_CHARS: "Domain name label can only contain alphanumeric characters or dashes." + }; + internals.validate = function(input) { + var ascii = Punycode.toASCII(input); + if (ascii.length < 1) { + return "DOMAIN_TOO_SHORT"; + } + if (ascii.length > 255) { + return "DOMAIN_TOO_LONG"; + } + var labels = ascii.split("."); + var label; + for (var i = 0; i < labels.length; ++i) { + label = labels[i]; + if (!label.length) { + return "LABEL_TOO_SHORT"; + } + if (label.length > 63) { + return "LABEL_TOO_LONG"; + } + if (label.charAt(0) === "-") { + return "LABEL_STARTS_WITH_DASH"; + } + if (label.charAt(label.length - 1) === "-") { + return "LABEL_ENDS_WITH_DASH"; + } + if (!/^[a-z0-9\-]+$/.test(label)) { + return "LABEL_INVALID_CHARS"; + } + } + }; + exports.parse = function(input) { + if (typeof input !== "string") { + throw new TypeError("Domain name must be a string."); + } + var domain = input.slice(0).toLowerCase(); + if (domain.charAt(domain.length - 1) === ".") { + domain = domain.slice(0, domain.length - 1); + } + var error = internals.validate(domain); + if (error) { + return { + input, + error: { + message: exports.errorCodes[error], + code: error + } + }; + } + var parsed = { + input, + tld: null, + sld: null, + domain: null, + subdomain: null, + listed: false + }; + var domainParts = domain.split("."); + if (domainParts[domainParts.length - 1] === "local") { + return parsed; + } + var handlePunycode = function() { + if (!/xn--/.test(domain)) { + return parsed; + } + if (parsed.domain) { + parsed.domain = Punycode.toASCII(parsed.domain); + } + if (parsed.subdomain) { + parsed.subdomain = Punycode.toASCII(parsed.subdomain); + } + return parsed; + }; + var rule = internals.findRule(domain); + if (!rule) { + if (domainParts.length < 2) { + return parsed; + } + parsed.tld = domainParts.pop(); + parsed.sld = domainParts.pop(); + parsed.domain = [parsed.sld, parsed.tld].join("."); + if (domainParts.length) { + parsed.subdomain = domainParts.pop(); + } + return handlePunycode(); + } + parsed.listed = true; + var tldParts = rule.suffix.split("."); + var privateParts = domainParts.slice(0, domainParts.length - tldParts.length); + if (rule.exception) { + privateParts.push(tldParts.shift()); + } + parsed.tld = tldParts.join("."); + if (!privateParts.length) { + return handlePunycode(); + } + if (rule.wildcard) { + tldParts.unshift(privateParts.pop()); + parsed.tld = tldParts.join("."); + } + if (!privateParts.length) { + return handlePunycode(); + } + parsed.sld = privateParts.pop(); + parsed.domain = [parsed.sld, parsed.tld].join("."); + if (privateParts.length) { + parsed.subdomain = privateParts.join("."); + } + return handlePunycode(); + }; + exports.get = function(domain) { + if (!domain) { + return null; + } + return exports.parse(domain).domain || null; + }; + exports.isValid = function(domain) { + var parsed = exports.parse(domain); + return Boolean(parsed.domain && parsed.listed); + }; + } +}); + +// node_modules/tough-cookie/lib/pubsuffix-psl.js +var require_pubsuffix_psl = __commonJS({ + "node_modules/tough-cookie/lib/pubsuffix-psl.js"(exports) { + "use strict"; + var psl = require_psl(); + var SPECIAL_USE_DOMAINS = [ + "local", + "example", + "invalid", + "localhost", + "test" + ]; + var SPECIAL_TREATMENT_DOMAINS = ["localhost", "invalid"]; + function getPublicSuffix(domain, options = {}) { + const domainParts = domain.split("."); + const topLevelDomain = domainParts[domainParts.length - 1]; + const allowSpecialUseDomain = !!options.allowSpecialUseDomain; + const ignoreError = !!options.ignoreError; + if (allowSpecialUseDomain && SPECIAL_USE_DOMAINS.includes(topLevelDomain)) { + if (domainParts.length > 1) { + const secondLevelDomain = domainParts[domainParts.length - 2]; + return `${secondLevelDomain}.${topLevelDomain}`; + } else if (SPECIAL_TREATMENT_DOMAINS.includes(topLevelDomain)) { + return `${topLevelDomain}`; + } + } + if (!ignoreError && SPECIAL_USE_DOMAINS.includes(topLevelDomain)) { + throw new Error( + `Cookie has domain set to the public suffix "${topLevelDomain}" which is a special use domain. To allow this, configure your CookieJar with {allowSpecialUseDomain:true, rejectPublicSuffixes: false}.` + ); + } + return psl.get(domain); + } + exports.getPublicSuffix = getPublicSuffix; + } +}); + +// node_modules/tough-cookie/lib/store.js +var require_store = __commonJS({ + "node_modules/tough-cookie/lib/store.js"(exports) { + "use strict"; + var Store = class { + constructor() { + this.synchronous = false; + } + findCookie(domain, path, key, cb) { + throw new Error("findCookie is not implemented"); + } + findCookies(domain, path, allowSpecialUseDomain, cb) { + throw new Error("findCookies is not implemented"); + } + putCookie(cookie, cb) { + throw new Error("putCookie is not implemented"); + } + updateCookie(oldCookie, newCookie, cb) { + throw new Error("updateCookie is not implemented"); + } + removeCookie(domain, path, key, cb) { + throw new Error("removeCookie is not implemented"); + } + removeCookies(domain, path, cb) { + throw new Error("removeCookies is not implemented"); + } + removeAllCookies(cb) { + throw new Error("removeAllCookies is not implemented"); + } + getAllCookies(cb) { + throw new Error( + "getAllCookies is not implemented (therefore jar cannot be serialized)" + ); + } + }; + exports.Store = Store; + } +}); + +// node_modules/universalify/index.js +var require_universalify = __commonJS({ + "node_modules/universalify/index.js"(exports) { + "use strict"; + exports.fromCallback = function(fn) { + return Object.defineProperty(function() { + if (typeof arguments[arguments.length - 1] === "function") fn.apply(this, arguments); + else { + return new Promise((resolve, reject) => { + arguments[arguments.length] = (err, res) => { + if (err) return reject(err); + resolve(res); + }; + arguments.length++; + fn.apply(this, arguments); + }); + } + }, "name", { value: fn.name }); + }; + exports.fromPromise = function(fn) { + return Object.defineProperty(function() { + const cb = arguments[arguments.length - 1]; + if (typeof cb !== "function") return fn.apply(this, arguments); + else { + delete arguments[arguments.length - 1]; + arguments.length--; + fn.apply(this, arguments).then((r) => cb(null, r), cb); + } + }, "name", { value: fn.name }); + }; + } +}); + +// node_modules/tough-cookie/lib/permuteDomain.js +var require_permuteDomain = __commonJS({ + "node_modules/tough-cookie/lib/permuteDomain.js"(exports) { + "use strict"; + var pubsuffix = require_pubsuffix_psl(); + function permuteDomain(domain, allowSpecialUseDomain) { + const pubSuf = pubsuffix.getPublicSuffix(domain, { + allowSpecialUseDomain + }); + if (!pubSuf) { + return null; + } + if (pubSuf == domain) { + return [domain]; + } + if (domain.slice(-1) == ".") { + domain = domain.slice(0, -1); + } + const prefix = domain.slice(0, -(pubSuf.length + 1)); + const parts = prefix.split(".").reverse(); + let cur = pubSuf; + const permutations = [cur]; + while (parts.length) { + cur = `${parts.shift()}.${cur}`; + permutations.push(cur); + } + return permutations; + } + exports.permuteDomain = permuteDomain; + } +}); + +// node_modules/tough-cookie/lib/pathMatch.js +var require_pathMatch = __commonJS({ + "node_modules/tough-cookie/lib/pathMatch.js"(exports) { + "use strict"; + function pathMatch(reqPath, cookiePath) { + if (cookiePath === reqPath) { + return true; + } + const idx = reqPath.indexOf(cookiePath); + if (idx === 0) { + if (cookiePath.substr(-1) === "/") { + return true; + } + if (reqPath.substr(cookiePath.length, 1) === "/") { + return true; + } + } + return false; + } + exports.pathMatch = pathMatch; + } +}); + +// node_modules/tough-cookie/lib/utilHelper.js +var require_utilHelper = __commonJS({ + "node_modules/tough-cookie/lib/utilHelper.js"(exports) { + function requireUtil() { + try { + return __require("util"); + } catch (e) { + return null; + } + } + function lookupCustomInspectSymbol() { + return Symbol.for("nodejs.util.inspect.custom"); + } + function tryReadingCustomSymbolFromUtilInspect(options) { + const _requireUtil = options.requireUtil || requireUtil; + const util = _requireUtil(); + return util ? util.inspect.custom : null; + } + exports.getUtilInspect = function getUtilInspect(fallback, options = {}) { + const _requireUtil = options.requireUtil || requireUtil; + const util = _requireUtil(); + return function inspect(value, showHidden, depth) { + return util ? util.inspect(value, showHidden, depth) : fallback(value); + }; + }; + exports.getCustomInspectSymbol = function getCustomInspectSymbol(options = {}) { + const _lookupCustomInspectSymbol = options.lookupCustomInspectSymbol || lookupCustomInspectSymbol; + return _lookupCustomInspectSymbol() || tryReadingCustomSymbolFromUtilInspect(options); + }; + } +}); + +// node_modules/tough-cookie/lib/memstore.js +var require_memstore = __commonJS({ + "node_modules/tough-cookie/lib/memstore.js"(exports) { + "use strict"; + var { fromCallback } = require_universalify(); + var Store = require_store().Store; + var permuteDomain = require_permuteDomain().permuteDomain; + var pathMatch = require_pathMatch().pathMatch; + var { getCustomInspectSymbol, getUtilInspect } = require_utilHelper(); + var MemoryCookieStore = class extends Store { + constructor() { + super(); + this.synchronous = true; + this.idx = /* @__PURE__ */ Object.create(null); + const customInspectSymbol = getCustomInspectSymbol(); + if (customInspectSymbol) { + this[customInspectSymbol] = this.inspect; + } + } + inspect() { + const util = { inspect: getUtilInspect(inspectFallback) }; + return `{ idx: ${util.inspect(this.idx, false, 2)} }`; + } + findCookie(domain, path, key, cb) { + if (!this.idx[domain]) { + return cb(null, void 0); + } + if (!this.idx[domain][path]) { + return cb(null, void 0); + } + return cb(null, this.idx[domain][path][key] || null); + } + findCookies(domain, path, allowSpecialUseDomain, cb) { + const results = []; + if (typeof allowSpecialUseDomain === "function") { + cb = allowSpecialUseDomain; + allowSpecialUseDomain = true; + } + if (!domain) { + return cb(null, []); + } + let pathMatcher; + if (!path) { + pathMatcher = function matchAll(domainIndex) { + for (const curPath in domainIndex) { + const pathIndex = domainIndex[curPath]; + for (const key in pathIndex) { + results.push(pathIndex[key]); + } + } + }; + } else { + pathMatcher = function matchRFC(domainIndex) { + Object.keys(domainIndex).forEach((cookiePath) => { + if (pathMatch(path, cookiePath)) { + const pathIndex = domainIndex[cookiePath]; + for (const key in pathIndex) { + results.push(pathIndex[key]); + } + } + }); + }; + } + const domains = permuteDomain(domain, allowSpecialUseDomain) || [domain]; + const idx = this.idx; + domains.forEach((curDomain) => { + const domainIndex = idx[curDomain]; + if (!domainIndex) { + return; + } + pathMatcher(domainIndex); + }); + cb(null, results); + } + putCookie(cookie, cb) { + if (!this.idx[cookie.domain]) { + this.idx[cookie.domain] = /* @__PURE__ */ Object.create(null); + } + if (!this.idx[cookie.domain][cookie.path]) { + this.idx[cookie.domain][cookie.path] = /* @__PURE__ */ Object.create(null); + } + this.idx[cookie.domain][cookie.path][cookie.key] = cookie; + cb(null); + } + updateCookie(oldCookie, newCookie, cb) { + this.putCookie(newCookie, cb); + } + removeCookie(domain, path, key, cb) { + if (this.idx[domain] && this.idx[domain][path] && this.idx[domain][path][key]) { + delete this.idx[domain][path][key]; + } + cb(null); + } + removeCookies(domain, path, cb) { + if (this.idx[domain]) { + if (path) { + delete this.idx[domain][path]; + } else { + delete this.idx[domain]; + } + } + return cb(null); + } + removeAllCookies(cb) { + this.idx = /* @__PURE__ */ Object.create(null); + return cb(null); + } + getAllCookies(cb) { + const cookies = []; + const idx = this.idx; + const domains = Object.keys(idx); + domains.forEach((domain) => { + const paths = Object.keys(idx[domain]); + paths.forEach((path) => { + const keys = Object.keys(idx[domain][path]); + keys.forEach((key) => { + if (key !== null) { + cookies.push(idx[domain][path][key]); + } + }); + }); + }); + cookies.sort((a, b) => { + return (a.creationIndex || 0) - (b.creationIndex || 0); + }); + cb(null, cookies); + } + }; + [ + "findCookie", + "findCookies", + "putCookie", + "updateCookie", + "removeCookie", + "removeCookies", + "removeAllCookies", + "getAllCookies" + ].forEach((name) => { + MemoryCookieStore.prototype[name] = fromCallback( + MemoryCookieStore.prototype[name] + ); + }); + exports.MemoryCookieStore = MemoryCookieStore; + function inspectFallback(val) { + const domains = Object.keys(val); + if (domains.length === 0) { + return "[Object: null prototype] {}"; + } + let result = "[Object: null prototype] {\n"; + Object.keys(val).forEach((domain, i) => { + result += formatDomain(domain, val[domain]); + if (i < domains.length - 1) { + result += ","; + } + result += "\n"; + }); + result += "}"; + return result; + } + function formatDomain(domainName, domainValue) { + const indent = " "; + let result = `${indent}'${domainName}': [Object: null prototype] { +`; + Object.keys(domainValue).forEach((path, i, paths) => { + result += formatPath(path, domainValue[path]); + if (i < paths.length - 1) { + result += ","; + } + result += "\n"; + }); + result += `${indent}}`; + return result; + } + function formatPath(pathName, pathValue) { + const indent = " "; + let result = `${indent}'${pathName}': [Object: null prototype] { +`; + Object.keys(pathValue).forEach((cookieName, i, cookieNames) => { + const cookie = pathValue[cookieName]; + result += ` ${cookieName}: ${cookie.inspect()}`; + if (i < cookieNames.length - 1) { + result += ","; + } + result += "\n"; + }); + result += `${indent}}`; + return result; + } + exports.inspectFallback = inspectFallback; + } +}); + +// node_modules/tough-cookie/lib/validators.js +var require_validators = __commonJS({ + "node_modules/tough-cookie/lib/validators.js"(exports) { + "use strict"; + var toString = Object.prototype.toString; + function isFunction(data) { + return typeof data === "function"; + } + function isNonEmptyString(data) { + return isString(data) && data !== ""; + } + function isDate(data) { + return isInstanceStrict(data, Date) && isInteger(data.getTime()); + } + function isEmptyString(data) { + return data === "" || data instanceof String && data.toString() === ""; + } + function isString(data) { + return typeof data === "string" || data instanceof String; + } + function isObject(data) { + return toString.call(data) === "[object Object]"; + } + function isInstanceStrict(data, prototype) { + try { + return data instanceof prototype; + } catch (error) { + return false; + } + } + function isUrlStringOrObject(data) { + return isNonEmptyString(data) || isObject(data) && "hostname" in data && "pathname" in data && "protocol" in data || isInstanceStrict(data, URL); + } + function isInteger(data) { + return typeof data === "number" && data % 1 === 0; + } + function validate(bool, cb, options) { + if (!isFunction(cb)) { + options = cb; + cb = null; + } + if (!isObject(options)) options = { Error: "Failed Check" }; + if (!bool) { + if (cb) { + cb(new ParameterError(options)); + } else { + throw new ParameterError(options); + } + } + } + var ParameterError = class extends Error { + constructor(...params) { + super(...params); + } + }; + exports.ParameterError = ParameterError; + exports.isFunction = isFunction; + exports.isNonEmptyString = isNonEmptyString; + exports.isDate = isDate; + exports.isEmptyString = isEmptyString; + exports.isString = isString; + exports.isObject = isObject; + exports.isUrlStringOrObject = isUrlStringOrObject; + exports.validate = validate; + } +}); + +// node_modules/tough-cookie/lib/version.js +var require_version = __commonJS({ + "node_modules/tough-cookie/lib/version.js"(exports, module) { + module.exports = "4.1.4"; + } +}); + +// node_modules/tough-cookie/lib/cookie.js +var require_cookie = __commonJS({ + "node_modules/tough-cookie/lib/cookie.js"(exports) { + "use strict"; + var punycode = require_punycode(); + var urlParse = require_url_parse(); + var pubsuffix = require_pubsuffix_psl(); + var Store = require_store().Store; + var MemoryCookieStore = require_memstore().MemoryCookieStore; + var pathMatch = require_pathMatch().pathMatch; + var validators = require_validators(); + var VERSION = require_version(); + var { fromCallback } = require_universalify(); + var { getCustomInspectSymbol } = require_utilHelper(); + var COOKIE_OCTETS = /^[\x21\x23-\x2B\x2D-\x3A\x3C-\x5B\x5D-\x7E]+$/; + var CONTROL_CHARS = /[\x00-\x1F]/; + var TERMINATORS = ["\n", "\r", "\0"]; + var PATH_VALUE = /[\x20-\x3A\x3C-\x7E]+/; + var DATE_DELIM = /[\x09\x20-\x2F\x3B-\x40\x5B-\x60\x7B-\x7E]/; + var MONTH_TO_NUM = { + jan: 0, + feb: 1, + mar: 2, + apr: 3, + may: 4, + jun: 5, + jul: 6, + aug: 7, + sep: 8, + oct: 9, + nov: 10, + dec: 11 + }; + var MAX_TIME = 2147483647e3; + var MIN_TIME = 0; + var SAME_SITE_CONTEXT_VAL_ERR = 'Invalid sameSiteContext option for getCookies(); expected one of "strict", "lax", or "none"'; + function checkSameSiteContext(value) { + validators.validate(validators.isNonEmptyString(value), value); + const context = String(value).toLowerCase(); + if (context === "none" || context === "lax" || context === "strict") { + return context; + } else { + return null; + } + } + var PrefixSecurityEnum = Object.freeze({ + SILENT: "silent", + STRICT: "strict", + DISABLED: "unsafe-disabled" + }); + var IP_REGEX_LOWERCASE = /(?:^(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)){3}$)|(?:^(?:(?:[a-f\d]{1,4}:){7}(?:[a-f\d]{1,4}|:)|(?:[a-f\d]{1,4}:){6}(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)){3}|:[a-f\d]{1,4}|:)|(?:[a-f\d]{1,4}:){5}(?::(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)){3}|(?::[a-f\d]{1,4}){1,2}|:)|(?:[a-f\d]{1,4}:){4}(?:(?::[a-f\d]{1,4}){0,1}:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)){3}|(?::[a-f\d]{1,4}){1,3}|:)|(?:[a-f\d]{1,4}:){3}(?:(?::[a-f\d]{1,4}){0,2}:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)){3}|(?::[a-f\d]{1,4}){1,4}|:)|(?:[a-f\d]{1,4}:){2}(?:(?::[a-f\d]{1,4}){0,3}:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)){3}|(?::[a-f\d]{1,4}){1,5}|:)|(?:[a-f\d]{1,4}:){1}(?:(?::[a-f\d]{1,4}){0,4}:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)){3}|(?::[a-f\d]{1,4}){1,6}|:)|(?::(?:(?::[a-f\d]{1,4}){0,5}:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)){3}|(?::[a-f\d]{1,4}){1,7}|:)))$)/; + var IP_V6_REGEX = ` +\\[?(?: +(?:[a-fA-F\\d]{1,4}:){7}(?:[a-fA-F\\d]{1,4}|:)| +(?:[a-fA-F\\d]{1,4}:){6}(?:(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]\\d|\\d)(?:\\.(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]\\d|\\d)){3}|:[a-fA-F\\d]{1,4}|:)| +(?:[a-fA-F\\d]{1,4}:){5}(?::(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]\\d|\\d)(?:\\.(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]\\d|\\d)){3}|(?::[a-fA-F\\d]{1,4}){1,2}|:)| +(?:[a-fA-F\\d]{1,4}:){4}(?:(?::[a-fA-F\\d]{1,4}){0,1}:(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]\\d|\\d)(?:\\.(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]\\d|\\d)){3}|(?::[a-fA-F\\d]{1,4}){1,3}|:)| +(?:[a-fA-F\\d]{1,4}:){3}(?:(?::[a-fA-F\\d]{1,4}){0,2}:(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]\\d|\\d)(?:\\.(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]\\d|\\d)){3}|(?::[a-fA-F\\d]{1,4}){1,4}|:)| +(?:[a-fA-F\\d]{1,4}:){2}(?:(?::[a-fA-F\\d]{1,4}){0,3}:(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]\\d|\\d)(?:\\.(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]\\d|\\d)){3}|(?::[a-fA-F\\d]{1,4}){1,5}|:)| +(?:[a-fA-F\\d]{1,4}:){1}(?:(?::[a-fA-F\\d]{1,4}){0,4}:(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]\\d|\\d)(?:\\.(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]\\d|\\d)){3}|(?::[a-fA-F\\d]{1,4}){1,6}|:)| +(?::(?:(?::[a-fA-F\\d]{1,4}){0,5}:(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]\\d|\\d)(?:\\.(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]\\d|\\d)){3}|(?::[a-fA-F\\d]{1,4}){1,7}|:)) +)(?:%[0-9a-zA-Z]{1,})?\\]? +`.replace(/\s*\/\/.*$/gm, "").replace(/\n/g, "").trim(); + var IP_V6_REGEX_OBJECT = new RegExp(`^${IP_V6_REGEX}$`); + function parseDigits(token, minDigits, maxDigits, trailingOK) { + let count = 0; + while (count < token.length) { + const c = token.charCodeAt(count); + if (c <= 47 || c >= 58) { + break; + } + count++; + } + if (count < minDigits || count > maxDigits) { + return null; + } + if (!trailingOK && count != token.length) { + return null; + } + return parseInt(token.substr(0, count), 10); + } + function parseTime(token) { + const parts = token.split(":"); + const result = [0, 0, 0]; + if (parts.length !== 3) { + return null; + } + for (let i = 0; i < 3; i++) { + const trailingOK = i == 2; + const num = parseDigits(parts[i], 1, 2, trailingOK); + if (num === null) { + return null; + } + result[i] = num; + } + return result; + } + function parseMonth(token) { + token = String(token).substr(0, 3).toLowerCase(); + const num = MONTH_TO_NUM[token]; + return num >= 0 ? num : null; + } + function parseDate(str) { + if (!str) { + return; + } + const tokens = str.split(DATE_DELIM); + if (!tokens) { + return; + } + let hour = null; + let minute = null; + let second = null; + let dayOfMonth = null; + let month = null; + let year = null; + for (let i = 0; i < tokens.length; i++) { + const token = tokens[i].trim(); + if (!token.length) { + continue; + } + let result; + if (second === null) { + result = parseTime(token); + if (result) { + hour = result[0]; + minute = result[1]; + second = result[2]; + continue; + } + } + if (dayOfMonth === null) { + result = parseDigits(token, 1, 2, true); + if (result !== null) { + dayOfMonth = result; + continue; + } + } + if (month === null) { + result = parseMonth(token); + if (result !== null) { + month = result; + continue; + } + } + if (year === null) { + result = parseDigits(token, 2, 4, true); + if (result !== null) { + year = result; + if (year >= 70 && year <= 99) { + year += 1900; + } else if (year >= 0 && year <= 69) { + year += 2e3; + } + } + } + } + if (dayOfMonth === null || month === null || year === null || second === null || dayOfMonth < 1 || dayOfMonth > 31 || year < 1601 || hour > 23 || minute > 59 || second > 59) { + return; + } + return new Date(Date.UTC(year, month, dayOfMonth, hour, minute, second)); + } + function formatDate(date) { + validators.validate(validators.isDate(date), date); + return date.toUTCString(); + } + function canonicalDomain(str) { + if (str == null) { + return null; + } + str = str.trim().replace(/^\./, ""); + if (IP_V6_REGEX_OBJECT.test(str)) { + str = str.replace("[", "").replace("]", ""); + } + if (punycode && /[^\u0001-\u007f]/.test(str)) { + str = punycode.toASCII(str); + } + return str.toLowerCase(); + } + function domainMatch(str, domStr, canonicalize) { + if (str == null || domStr == null) { + return null; + } + if (canonicalize !== false) { + str = canonicalDomain(str); + domStr = canonicalDomain(domStr); + } + if (str == domStr) { + return true; + } + const idx = str.lastIndexOf(domStr); + if (idx <= 0) { + return false; + } + if (str.length !== domStr.length + idx) { + return false; + } + if (str.substr(idx - 1, 1) !== ".") { + return false; + } + if (IP_REGEX_LOWERCASE.test(str)) { + return false; + } + return true; + } + function defaultPath(path) { + if (!path || path.substr(0, 1) !== "/") { + return "/"; + } + if (path === "/") { + return path; + } + const rightSlash = path.lastIndexOf("/"); + if (rightSlash === 0) { + return "/"; + } + return path.slice(0, rightSlash); + } + function trimTerminator(str) { + if (validators.isEmptyString(str)) return str; + for (let t = 0; t < TERMINATORS.length; t++) { + const terminatorIdx = str.indexOf(TERMINATORS[t]); + if (terminatorIdx !== -1) { + str = str.substr(0, terminatorIdx); + } + } + return str; + } + function parseCookiePair(cookiePair, looseMode) { + cookiePair = trimTerminator(cookiePair); + validators.validate(validators.isString(cookiePair), cookiePair); + let firstEq = cookiePair.indexOf("="); + if (looseMode) { + if (firstEq === 0) { + cookiePair = cookiePair.substr(1); + firstEq = cookiePair.indexOf("="); + } + } else { + if (firstEq <= 0) { + return; + } + } + let cookieName, cookieValue; + if (firstEq <= 0) { + cookieName = ""; + cookieValue = cookiePair.trim(); + } else { + cookieName = cookiePair.substr(0, firstEq).trim(); + cookieValue = cookiePair.substr(firstEq + 1).trim(); + } + if (CONTROL_CHARS.test(cookieName) || CONTROL_CHARS.test(cookieValue)) { + return; + } + const c = new Cookie(); + c.key = cookieName; + c.value = cookieValue; + return c; + } + function parse(str, options) { + if (!options || typeof options !== "object") { + options = {}; + } + if (validators.isEmptyString(str) || !validators.isString(str)) { + return null; + } + str = str.trim(); + const firstSemi = str.indexOf(";"); + const cookiePair = firstSemi === -1 ? str : str.substr(0, firstSemi); + const c = parseCookiePair(cookiePair, !!options.loose); + if (!c) { + return; + } + if (firstSemi === -1) { + return c; + } + const unparsed = str.slice(firstSemi + 1).trim(); + if (unparsed.length === 0) { + return c; + } + const cookie_avs = unparsed.split(";"); + while (cookie_avs.length) { + const av = cookie_avs.shift().trim(); + if (av.length === 0) { + continue; + } + const av_sep = av.indexOf("="); + let av_key, av_value; + if (av_sep === -1) { + av_key = av; + av_value = null; + } else { + av_key = av.substr(0, av_sep); + av_value = av.substr(av_sep + 1); + } + av_key = av_key.trim().toLowerCase(); + if (av_value) { + av_value = av_value.trim(); + } + switch (av_key) { + case "expires": + if (av_value) { + const exp = parseDate(av_value); + if (exp) { + c.expires = exp; + } + } + break; + case "max-age": + if (av_value) { + if (/^-?[0-9]+$/.test(av_value)) { + const delta = parseInt(av_value, 10); + c.setMaxAge(delta); + } + } + break; + case "domain": + if (av_value) { + const domain = av_value.trim().replace(/^\./, ""); + if (domain) { + c.domain = domain.toLowerCase(); + } + } + break; + case "path": + c.path = av_value && av_value[0] === "/" ? av_value : null; + break; + case "secure": + c.secure = true; + break; + case "httponly": + c.httpOnly = true; + break; + case "samesite": + const enforcement = av_value ? av_value.toLowerCase() : ""; + switch (enforcement) { + case "strict": + c.sameSite = "strict"; + break; + case "lax": + c.sameSite = "lax"; + break; + case "none": + c.sameSite = "none"; + break; + default: + c.sameSite = void 0; + break; + } + break; + default: + c.extensions = c.extensions || []; + c.extensions.push(av); + break; + } + } + return c; + } + function isSecurePrefixConditionMet(cookie) { + validators.validate(validators.isObject(cookie), cookie); + return !cookie.key.startsWith("__Secure-") || cookie.secure; + } + function isHostPrefixConditionMet(cookie) { + validators.validate(validators.isObject(cookie)); + return !cookie.key.startsWith("__Host-") || cookie.secure && cookie.hostOnly && cookie.path != null && cookie.path === "/"; + } + function jsonParse(str) { + let obj; + try { + obj = JSON.parse(str); + } catch (e) { + return e; + } + return obj; + } + function fromJSON(str) { + if (!str || validators.isEmptyString(str)) { + return null; + } + let obj; + if (typeof str === "string") { + obj = jsonParse(str); + if (obj instanceof Error) { + return null; + } + } else { + obj = str; + } + const c = new Cookie(); + for (let i = 0; i < Cookie.serializableProperties.length; i++) { + const prop = Cookie.serializableProperties[i]; + if (obj[prop] === void 0 || obj[prop] === cookieDefaults[prop]) { + continue; + } + if (prop === "expires" || prop === "creation" || prop === "lastAccessed") { + if (obj[prop] === null) { + c[prop] = null; + } else { + c[prop] = obj[prop] == "Infinity" ? "Infinity" : new Date(obj[prop]); + } + } else { + c[prop] = obj[prop]; + } + } + return c; + } + function cookieCompare(a, b) { + validators.validate(validators.isObject(a), a); + validators.validate(validators.isObject(b), b); + let cmp = 0; + const aPathLen = a.path ? a.path.length : 0; + const bPathLen = b.path ? b.path.length : 0; + cmp = bPathLen - aPathLen; + if (cmp !== 0) { + return cmp; + } + const aTime = a.creation ? a.creation.getTime() : MAX_TIME; + const bTime = b.creation ? b.creation.getTime() : MAX_TIME; + cmp = aTime - bTime; + if (cmp !== 0) { + return cmp; + } + cmp = a.creationIndex - b.creationIndex; + return cmp; + } + function permutePath(path) { + validators.validate(validators.isString(path)); + if (path === "/") { + return ["/"]; + } + const permutations = [path]; + while (path.length > 1) { + const lindex = path.lastIndexOf("/"); + if (lindex === 0) { + break; + } + path = path.substr(0, lindex); + permutations.push(path); + } + permutations.push("/"); + return permutations; + } + function getCookieContext(url) { + if (url instanceof Object) { + return url; + } + try { + url = decodeURI(url); + } catch (err) { + } + return urlParse(url); + } + var cookieDefaults = { + // the order in which the RFC has them: + key: "", + value: "", + expires: "Infinity", + maxAge: null, + domain: null, + path: null, + secure: false, + httpOnly: false, + extensions: null, + // set by the CookieJar: + hostOnly: null, + pathIsDefault: null, + creation: null, + lastAccessed: null, + sameSite: void 0 + }; + var Cookie = class _Cookie { + constructor(options = {}) { + const customInspectSymbol = getCustomInspectSymbol(); + if (customInspectSymbol) { + this[customInspectSymbol] = this.inspect; + } + Object.assign(this, cookieDefaults, options); + this.creation = this.creation || /* @__PURE__ */ new Date(); + Object.defineProperty(this, "creationIndex", { + configurable: false, + enumerable: false, + // important for assert.deepEqual checks + writable: true, + value: ++_Cookie.cookiesCreated + }); + } + inspect() { + const now = Date.now(); + const hostOnly = this.hostOnly != null ? this.hostOnly : "?"; + const createAge = this.creation ? `${now - this.creation.getTime()}ms` : "?"; + const accessAge = this.lastAccessed ? `${now - this.lastAccessed.getTime()}ms` : "?"; + return `Cookie="${this.toString()}; hostOnly=${hostOnly}; aAge=${accessAge}; cAge=${createAge}"`; + } + toJSON() { + const obj = {}; + for (const prop of _Cookie.serializableProperties) { + if (this[prop] === cookieDefaults[prop]) { + continue; + } + if (prop === "expires" || prop === "creation" || prop === "lastAccessed") { + if (this[prop] === null) { + obj[prop] = null; + } else { + obj[prop] = this[prop] == "Infinity" ? "Infinity" : this[prop].toISOString(); + } + } else if (prop === "maxAge") { + if (this[prop] !== null) { + obj[prop] = this[prop] == Infinity || this[prop] == -Infinity ? this[prop].toString() : this[prop]; + } + } else { + if (this[prop] !== cookieDefaults[prop]) { + obj[prop] = this[prop]; + } + } + } + return obj; + } + clone() { + return fromJSON(this.toJSON()); + } + validate() { + if (!COOKIE_OCTETS.test(this.value)) { + return false; + } + if (this.expires != Infinity && !(this.expires instanceof Date) && !parseDate(this.expires)) { + return false; + } + if (this.maxAge != null && this.maxAge <= 0) { + return false; + } + if (this.path != null && !PATH_VALUE.test(this.path)) { + return false; + } + const cdomain = this.cdomain(); + if (cdomain) { + if (cdomain.match(/\.$/)) { + return false; + } + const suffix = pubsuffix.getPublicSuffix(cdomain); + if (suffix == null) { + return false; + } + } + return true; + } + setExpires(exp) { + if (exp instanceof Date) { + this.expires = exp; + } else { + this.expires = parseDate(exp) || "Infinity"; + } + } + setMaxAge(age) { + if (age === Infinity || age === -Infinity) { + this.maxAge = age.toString(); + } else { + this.maxAge = age; + } + } + cookieString() { + let val = this.value; + if (val == null) { + val = ""; + } + if (this.key === "") { + return val; + } + return `${this.key}=${val}`; + } + // gives Set-Cookie header format + toString() { + let str = this.cookieString(); + if (this.expires != Infinity) { + if (this.expires instanceof Date) { + str += `; Expires=${formatDate(this.expires)}`; + } else { + str += `; Expires=${this.expires}`; + } + } + if (this.maxAge != null && this.maxAge != Infinity) { + str += `; Max-Age=${this.maxAge}`; + } + if (this.domain && !this.hostOnly) { + str += `; Domain=${this.domain}`; + } + if (this.path) { + str += `; Path=${this.path}`; + } + if (this.secure) { + str += "; Secure"; + } + if (this.httpOnly) { + str += "; HttpOnly"; + } + if (this.sameSite && this.sameSite !== "none") { + const ssCanon = _Cookie.sameSiteCanonical[this.sameSite.toLowerCase()]; + str += `; SameSite=${ssCanon ? ssCanon : this.sameSite}`; + } + if (this.extensions) { + this.extensions.forEach((ext) => { + str += `; ${ext}`; + }); + } + return str; + } + // TTL() partially replaces the "expiry-time" parts of S5.3 step 3 (setCookie() + // elsewhere) + // S5.3 says to give the "latest representable date" for which we use Infinity + // For "expired" we use 0 + TTL(now) { + if (this.maxAge != null) { + return this.maxAge <= 0 ? 0 : this.maxAge * 1e3; + } + let expires = this.expires; + if (expires != Infinity) { + if (!(expires instanceof Date)) { + expires = parseDate(expires) || Infinity; + } + if (expires == Infinity) { + return Infinity; + } + return expires.getTime() - (now || Date.now()); + } + return Infinity; + } + // expiryTime() replaces the "expiry-time" parts of S5.3 step 3 (setCookie() + // elsewhere) + expiryTime(now) { + if (this.maxAge != null) { + const relativeTo = now || this.creation || /* @__PURE__ */ new Date(); + const age = this.maxAge <= 0 ? -Infinity : this.maxAge * 1e3; + return relativeTo.getTime() + age; + } + if (this.expires == Infinity) { + return Infinity; + } + return this.expires.getTime(); + } + // expiryDate() replaces the "expiry-time" parts of S5.3 step 3 (setCookie() + // elsewhere), except it returns a Date + expiryDate(now) { + const millisec = this.expiryTime(now); + if (millisec == Infinity) { + return new Date(MAX_TIME); + } else if (millisec == -Infinity) { + return new Date(MIN_TIME); + } else { + return new Date(millisec); + } + } + // This replaces the "persistent-flag" parts of S5.3 step 3 + isPersistent() { + return this.maxAge != null || this.expires != Infinity; + } + // Mostly S5.1.2 and S5.2.3: + canonicalizedDomain() { + if (this.domain == null) { + return null; + } + return canonicalDomain(this.domain); + } + cdomain() { + return this.canonicalizedDomain(); + } + }; + Cookie.cookiesCreated = 0; + Cookie.parse = parse; + Cookie.fromJSON = fromJSON; + Cookie.serializableProperties = Object.keys(cookieDefaults); + Cookie.sameSiteLevel = { + strict: 3, + lax: 2, + none: 1 + }; + Cookie.sameSiteCanonical = { + strict: "Strict", + lax: "Lax" + }; + function getNormalizedPrefixSecurity(prefixSecurity) { + if (prefixSecurity != null) { + const normalizedPrefixSecurity = prefixSecurity.toLowerCase(); + switch (normalizedPrefixSecurity) { + case PrefixSecurityEnum.STRICT: + case PrefixSecurityEnum.SILENT: + case PrefixSecurityEnum.DISABLED: + return normalizedPrefixSecurity; + } + } + return PrefixSecurityEnum.SILENT; + } + var CookieJar = class _CookieJar { + constructor(store, options = { rejectPublicSuffixes: true }) { + if (typeof options === "boolean") { + options = { rejectPublicSuffixes: options }; + } + validators.validate(validators.isObject(options), options); + this.rejectPublicSuffixes = options.rejectPublicSuffixes; + this.enableLooseMode = !!options.looseMode; + this.allowSpecialUseDomain = typeof options.allowSpecialUseDomain === "boolean" ? options.allowSpecialUseDomain : true; + this.store = store || new MemoryCookieStore(); + this.prefixSecurity = getNormalizedPrefixSecurity(options.prefixSecurity); + this._cloneSync = syncWrap("clone"); + this._importCookiesSync = syncWrap("_importCookies"); + this.getCookiesSync = syncWrap("getCookies"); + this.getCookieStringSync = syncWrap("getCookieString"); + this.getSetCookieStringsSync = syncWrap("getSetCookieStrings"); + this.removeAllCookiesSync = syncWrap("removeAllCookies"); + this.setCookieSync = syncWrap("setCookie"); + this.serializeSync = syncWrap("serialize"); + } + setCookie(cookie, url, options, cb) { + validators.validate(validators.isUrlStringOrObject(url), cb, options); + let err; + if (validators.isFunction(url)) { + cb = url; + return cb(new Error("No URL was specified")); + } + const context = getCookieContext(url); + if (validators.isFunction(options)) { + cb = options; + options = {}; + } + validators.validate(validators.isFunction(cb), cb); + if (!validators.isNonEmptyString(cookie) && !validators.isObject(cookie) && cookie instanceof String && cookie.length == 0) { + return cb(null); + } + const host = canonicalDomain(context.hostname); + const loose = options.loose || this.enableLooseMode; + let sameSiteContext = null; + if (options.sameSiteContext) { + sameSiteContext = checkSameSiteContext(options.sameSiteContext); + if (!sameSiteContext) { + return cb(new Error(SAME_SITE_CONTEXT_VAL_ERR)); + } + } + if (typeof cookie === "string" || cookie instanceof String) { + cookie = Cookie.parse(cookie, { loose }); + if (!cookie) { + err = new Error("Cookie failed to parse"); + return cb(options.ignoreError ? null : err); + } + } else if (!(cookie instanceof Cookie)) { + err = new Error( + "First argument to setCookie must be a Cookie object or string" + ); + return cb(options.ignoreError ? null : err); + } + const now = options.now || /* @__PURE__ */ new Date(); + if (this.rejectPublicSuffixes && cookie.domain) { + const suffix = pubsuffix.getPublicSuffix(cookie.cdomain(), { + allowSpecialUseDomain: this.allowSpecialUseDomain, + ignoreError: options.ignoreError + }); + if (suffix == null && !IP_V6_REGEX_OBJECT.test(cookie.domain)) { + err = new Error("Cookie has domain set to a public suffix"); + return cb(options.ignoreError ? null : err); + } + } + if (cookie.domain) { + if (!domainMatch(host, cookie.cdomain(), false)) { + err = new Error( + `Cookie not in this host's domain. Cookie:${cookie.cdomain()} Request:${host}` + ); + return cb(options.ignoreError ? null : err); + } + if (cookie.hostOnly == null) { + cookie.hostOnly = false; + } + } else { + cookie.hostOnly = true; + cookie.domain = host; + } + if (!cookie.path || cookie.path[0] !== "/") { + cookie.path = defaultPath(context.pathname); + cookie.pathIsDefault = true; + } + if (options.http === false && cookie.httpOnly) { + err = new Error("Cookie is HttpOnly and this isn't an HTTP API"); + return cb(options.ignoreError ? null : err); + } + if (cookie.sameSite !== "none" && cookie.sameSite !== void 0 && sameSiteContext) { + if (sameSiteContext === "none") { + err = new Error( + "Cookie is SameSite but this is a cross-origin request" + ); + return cb(options.ignoreError ? null : err); + } + } + const ignoreErrorForPrefixSecurity = this.prefixSecurity === PrefixSecurityEnum.SILENT; + const prefixSecurityDisabled = this.prefixSecurity === PrefixSecurityEnum.DISABLED; + if (!prefixSecurityDisabled) { + let errorFound = false; + let errorMsg; + if (!isSecurePrefixConditionMet(cookie)) { + errorFound = true; + errorMsg = "Cookie has __Secure prefix but Secure attribute is not set"; + } else if (!isHostPrefixConditionMet(cookie)) { + errorFound = true; + errorMsg = "Cookie has __Host prefix but either Secure or HostOnly attribute is not set or Path is not '/'"; + } + if (errorFound) { + return cb( + options.ignoreError || ignoreErrorForPrefixSecurity ? null : new Error(errorMsg) + ); + } + } + const store = this.store; + if (!store.updateCookie) { + store.updateCookie = function(oldCookie, newCookie, cb2) { + this.putCookie(newCookie, cb2); + }; + } + function withCookie(err2, oldCookie) { + if (err2) { + return cb(err2); + } + const next = function(err3) { + if (err3) { + return cb(err3); + } else { + cb(null, cookie); + } + }; + if (oldCookie) { + if (options.http === false && oldCookie.httpOnly) { + err2 = new Error("old Cookie is HttpOnly and this isn't an HTTP API"); + return cb(options.ignoreError ? null : err2); + } + cookie.creation = oldCookie.creation; + cookie.creationIndex = oldCookie.creationIndex; + cookie.lastAccessed = now; + store.updateCookie(oldCookie, cookie, next); + } else { + cookie.creation = cookie.lastAccessed = now; + store.putCookie(cookie, next); + } + } + store.findCookie(cookie.domain, cookie.path, cookie.key, withCookie); + } + // RFC6365 S5.4 + getCookies(url, options, cb) { + validators.validate(validators.isUrlStringOrObject(url), cb, url); + const context = getCookieContext(url); + if (validators.isFunction(options)) { + cb = options; + options = {}; + } + validators.validate(validators.isObject(options), cb, options); + validators.validate(validators.isFunction(cb), cb); + const host = canonicalDomain(context.hostname); + const path = context.pathname || "/"; + let secure = options.secure; + if (secure == null && context.protocol && (context.protocol == "https:" || context.protocol == "wss:")) { + secure = true; + } + let sameSiteLevel = 0; + if (options.sameSiteContext) { + const sameSiteContext = checkSameSiteContext(options.sameSiteContext); + sameSiteLevel = Cookie.sameSiteLevel[sameSiteContext]; + if (!sameSiteLevel) { + return cb(new Error(SAME_SITE_CONTEXT_VAL_ERR)); + } + } + let http = options.http; + if (http == null) { + http = true; + } + const now = options.now || Date.now(); + const expireCheck = options.expire !== false; + const allPaths = !!options.allPaths; + const store = this.store; + function matchingCookie(c) { + if (c.hostOnly) { + if (c.domain != host) { + return false; + } + } else { + if (!domainMatch(host, c.domain, false)) { + return false; + } + } + if (!allPaths && !pathMatch(path, c.path)) { + return false; + } + if (c.secure && !secure) { + return false; + } + if (c.httpOnly && !http) { + return false; + } + if (sameSiteLevel) { + const cookieLevel = Cookie.sameSiteLevel[c.sameSite || "none"]; + if (cookieLevel > sameSiteLevel) { + return false; + } + } + if (expireCheck && c.expiryTime() <= now) { + store.removeCookie(c.domain, c.path, c.key, () => { + }); + return false; + } + return true; + } + store.findCookies( + host, + allPaths ? null : path, + this.allowSpecialUseDomain, + (err, cookies) => { + if (err) { + return cb(err); + } + cookies = cookies.filter(matchingCookie); + if (options.sort !== false) { + cookies = cookies.sort(cookieCompare); + } + const now2 = /* @__PURE__ */ new Date(); + for (const cookie of cookies) { + cookie.lastAccessed = now2; + } + cb(null, cookies); + } + ); + } + getCookieString(...args) { + const cb = args.pop(); + validators.validate(validators.isFunction(cb), cb); + const next = function(err, cookies) { + if (err) { + cb(err); + } else { + cb( + null, + cookies.sort(cookieCompare).map((c) => c.cookieString()).join("; ") + ); + } + }; + args.push(next); + this.getCookies.apply(this, args); + } + getSetCookieStrings(...args) { + const cb = args.pop(); + validators.validate(validators.isFunction(cb), cb); + const next = function(err, cookies) { + if (err) { + cb(err); + } else { + cb( + null, + cookies.map((c) => { + return c.toString(); + }) + ); + } + }; + args.push(next); + this.getCookies.apply(this, args); + } + serialize(cb) { + validators.validate(validators.isFunction(cb), cb); + let type = this.store.constructor.name; + if (validators.isObject(type)) { + type = null; + } + const serialized = { + // The version of tough-cookie that serialized this jar. Generally a good + // practice since future versions can make data import decisions based on + // known past behavior. When/if this matters, use `semver`. + version: `tough-cookie@${VERSION}`, + // add the store type, to make humans happy: + storeType: type, + // CookieJar configuration: + rejectPublicSuffixes: !!this.rejectPublicSuffixes, + enableLooseMode: !!this.enableLooseMode, + allowSpecialUseDomain: !!this.allowSpecialUseDomain, + prefixSecurity: getNormalizedPrefixSecurity(this.prefixSecurity), + // this gets filled from getAllCookies: + cookies: [] + }; + if (!(this.store.getAllCookies && typeof this.store.getAllCookies === "function")) { + return cb( + new Error( + "store does not support getAllCookies and cannot be serialized" + ) + ); + } + this.store.getAllCookies((err, cookies) => { + if (err) { + return cb(err); + } + serialized.cookies = cookies.map((cookie) => { + cookie = cookie instanceof Cookie ? cookie.toJSON() : cookie; + delete cookie.creationIndex; + return cookie; + }); + return cb(null, serialized); + }); + } + toJSON() { + return this.serializeSync(); + } + // use the class method CookieJar.deserialize instead of calling this directly + _importCookies(serialized, cb) { + let cookies = serialized.cookies; + if (!cookies || !Array.isArray(cookies)) { + return cb(new Error("serialized jar has no cookies array")); + } + cookies = cookies.slice(); + const putNext = (err) => { + if (err) { + return cb(err); + } + if (!cookies.length) { + return cb(err, this); + } + let cookie; + try { + cookie = fromJSON(cookies.shift()); + } catch (e) { + return cb(e); + } + if (cookie === null) { + return putNext(null); + } + this.store.putCookie(cookie, putNext); + }; + putNext(); + } + clone(newStore, cb) { + if (arguments.length === 1) { + cb = newStore; + newStore = null; + } + this.serialize((err, serialized) => { + if (err) { + return cb(err); + } + _CookieJar.deserialize(serialized, newStore, cb); + }); + } + cloneSync(newStore) { + if (arguments.length === 0) { + return this._cloneSync(); + } + if (!newStore.synchronous) { + throw new Error( + "CookieJar clone destination store is not synchronous; use async API instead." + ); + } + return this._cloneSync(newStore); + } + removeAllCookies(cb) { + validators.validate(validators.isFunction(cb), cb); + const store = this.store; + if (typeof store.removeAllCookies === "function" && store.removeAllCookies !== Store.prototype.removeAllCookies) { + return store.removeAllCookies(cb); + } + store.getAllCookies((err, cookies) => { + if (err) { + return cb(err); + } + if (cookies.length === 0) { + return cb(null); + } + let completedCount = 0; + const removeErrors = []; + function removeCookieCb(removeErr) { + if (removeErr) { + removeErrors.push(removeErr); + } + completedCount++; + if (completedCount === cookies.length) { + return cb(removeErrors.length ? removeErrors[0] : null); + } + } + cookies.forEach((cookie) => { + store.removeCookie( + cookie.domain, + cookie.path, + cookie.key, + removeCookieCb + ); + }); + }); + } + static deserialize(strOrObj, store, cb) { + if (arguments.length !== 3) { + cb = store; + store = null; + } + validators.validate(validators.isFunction(cb), cb); + let serialized; + if (typeof strOrObj === "string") { + serialized = jsonParse(strOrObj); + if (serialized instanceof Error) { + return cb(serialized); + } + } else { + serialized = strOrObj; + } + const jar = new _CookieJar(store, { + rejectPublicSuffixes: serialized.rejectPublicSuffixes, + looseMode: serialized.enableLooseMode, + allowSpecialUseDomain: serialized.allowSpecialUseDomain, + prefixSecurity: serialized.prefixSecurity + }); + jar._importCookies(serialized, (err) => { + if (err) { + return cb(err); + } + cb(null, jar); + }); + } + static deserializeSync(strOrObj, store) { + const serialized = typeof strOrObj === "string" ? JSON.parse(strOrObj) : strOrObj; + const jar = new _CookieJar(store, { + rejectPublicSuffixes: serialized.rejectPublicSuffixes, + looseMode: serialized.enableLooseMode + }); + if (!jar.store.synchronous) { + throw new Error( + "CookieJar store is not synchronous; use async API instead." + ); + } + jar._importCookiesSync(serialized); + return jar; + } + }; + CookieJar.fromJSON = CookieJar.deserializeSync; + [ + "_importCookies", + "clone", + "getCookies", + "getCookieString", + "getSetCookieStrings", + "removeAllCookies", + "serialize", + "setCookie" + ].forEach((name) => { + CookieJar.prototype[name] = fromCallback(CookieJar.prototype[name]); + }); + CookieJar.deserialize = fromCallback(CookieJar.deserialize); + function syncWrap(method) { + return function(...args) { + if (!this.store.synchronous) { + throw new Error( + "CookieJar store is not synchronous; use async API instead." + ); + } + let syncErr, syncResult; + this[method](...args, (err, result) => { + syncErr = err; + syncResult = result; + }); + if (syncErr) { + throw syncErr; + } + return syncResult; + }; + } + exports.version = VERSION; + exports.CookieJar = CookieJar; + exports.Cookie = Cookie; + exports.Store = Store; + exports.MemoryCookieStore = MemoryCookieStore; + exports.parseDate = parseDate; + exports.formatDate = formatDate; + exports.parse = parse; + exports.fromJSON = fromJSON; + exports.domainMatch = domainMatch; + exports.defaultPath = defaultPath; + exports.pathMatch = pathMatch; + exports.getPublicSuffix = pubsuffix.getPublicSuffix; + exports.cookieCompare = cookieCompare; + exports.permuteDomain = require_permuteDomain().permuteDomain; + exports.permutePath = permutePath; + exports.canonicalDomain = canonicalDomain; + exports.PrefixSecurityEnum = PrefixSecurityEnum; + exports.ParameterError = validators.ParameterError; + } +}); + +// source.js +var import_tough_cookie = __toESM(require_cookie(), 1); +var source_default = import_tough_cookie.default; +export { + source_default as default +}; +/*! Bundled license information: + +tough-cookie/lib/pubsuffix-psl.js: + (*! + * Copyright (c) 2018, Salesforce.com, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of Salesforce.com nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + *) + +tough-cookie/lib/store.js: + (*! + * Copyright (c) 2015, Salesforce.com, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of Salesforce.com nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + *) + +tough-cookie/lib/permuteDomain.js: + (*! + * Copyright (c) 2015, Salesforce.com, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of Salesforce.com nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + *) + +tough-cookie/lib/pathMatch.js: + (*! + * Copyright (c) 2015, Salesforce.com, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of Salesforce.com nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + *) + +tough-cookie/lib/memstore.js: + (*! + * Copyright (c) 2015, Salesforce.com, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of Salesforce.com nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + *) + +tough-cookie/lib/cookie.js: + (*! + * Copyright (c) 2015-2020, Salesforce.com, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of Salesforce.com nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + *) +*/ diff --git a/node_modules/@bundled-es-modules/tough-cookie/index.d.ts b/node_modules/@bundled-es-modules/tough-cookie/index.d.ts new file mode 100644 index 0000000000000000000000000000000000000000..db43a5e56cbf554ccaa93c7ef64a4afd91be24fa --- /dev/null +++ b/node_modules/@bundled-es-modules/tough-cookie/index.d.ts @@ -0,0 +1,4 @@ +export * from 'tough-cookie' + +import * as toughCookie from 'tough-cookie' +export default toughCookie diff --git a/node_modules/@bundled-es-modules/tough-cookie/package.json b/node_modules/@bundled-es-modules/tough-cookie/package.json new file mode 100644 index 0000000000000000000000000000000000000000..d27ab83df4c41f10985976d916eb7296fe733ee4 --- /dev/null +++ b/node_modules/@bundled-es-modules/tough-cookie/package.json @@ -0,0 +1,39 @@ +{ + "type": "module", + "name": "@bundled-es-modules/tough-cookie", + "version": "0.1.6", + "description": "Mirror of tough-cookie, bundled and exposed as ES module", + "main": "./index-esm.js", + "typings": "./index.d.ts", + "exports": { + ".": { + "import": "./index-esm.js", + "require": "./index-cjs.cjs" + } + }, + "scripts": { + "build": "esbuild source.js --bundle --format=esm --outfile=index-esm.js", + "release": "release publish" + }, + "files": [ + "index.d.ts", + "index-esm.js", + "index-cjs.cjs" + ], + "repository": { + "type": "git", + "url": "https://github.com/bundled-es-modules/tough-cookie" + }, + "license": "ISC", + "dependencies": { + "@types/tough-cookie": "^4.0.5", + "tough-cookie": "^4.1.4" + }, + "devDependencies": { + "@ossjs/release": "^0.8.1", + "esbuild": "^0.23.0" + }, + "publishConfig": { + "access": "public" + } +} \ No newline at end of file diff --git a/node_modules/@gradio/client/CHANGELOG.md b/node_modules/@gradio/client/CHANGELOG.md new file mode 100644 index 0000000000000000000000000000000000000000..6116dcb973ffa30950ff2ffb4ba29ad6ac801a21 --- /dev/null +++ b/node_modules/@gradio/client/CHANGELOG.md @@ -0,0 +1,850 @@ +# @gradio/client + +## 1.14.1 + +### Features + +- [#10890](https://github.com/gradio-app/gradio/pull/10890) [`01b88c7`](https://github.com/gradio-app/gradio/commit/01b88c7fdedb413ba92ef6191967a8aed25e185f) - Improve API error handling in JS Client. Thanks @l2dy! + +## 1.14.0 + +### Features + +- [#10834](https://github.com/gradio-app/gradio/pull/10834) [`c05610c`](https://github.com/gradio-app/gradio/commit/c05610c87dd7f9e9fe5d0aed2fe93e40fdd32648) - Add Deep Links. Thanks @freddyaboulton! + +## 1.13.1 + +### Features + +- [#10694](https://github.com/gradio-app/gradio/pull/10694) [`16244f3`](https://github.com/gradio-app/gradio/commit/16244f3c1cb1a65ac1f719142f8fab67512fbb25) - Event Listeners in gradio sketch. Thanks @aliabid94! + +### Fixes + +- [#10719](https://github.com/gradio-app/gradio/pull/10719) [`b710d7c`](https://github.com/gradio-app/gradio/commit/b710d7cf13c1277fd18c7809cad0f707b880ef70) - Fix error display. Thanks @aliabid94! + +## 1.13.0 + +### Features + +- [#10500](https://github.com/gradio-app/gradio/pull/10500) [`16d419b`](https://github.com/gradio-app/gradio/commit/16d419b9f1f18ae4507d18a4739eb83ac4f3fae9) - Allow functions that solely update component properties to run in the frontend by setting `js=True`. Thanks @abidlabs! + +## 1.12.0 + +### Features + +- [#10492](https://github.com/gradio-app/gradio/pull/10492) [`29880d5`](https://github.com/gradio-app/gradio/commit/29880d51fbe7fbd222b0765a83c95134dc7d0e90) - Allow showing progress updates on arbitrary components. Thanks @abidlabs! + +### Fixes + +- [#10547](https://github.com/gradio-app/gradio/pull/10547) [`083d68b`](https://github.com/gradio-app/gradio/commit/083d68b223be82a65f18c553df9ae690a8118a49) - quick_fix_client. Thanks @aliabid94! + +## 1.11.0 + +### Features + +- [#10433](https://github.com/gradio-app/gradio/pull/10433) [`2e8dc74`](https://github.com/gradio-app/gradio/commit/2e8dc74f751be02f7217f78d241806b42fcdca04) - Allow building multipage Gradio apps. Thanks @aliabid94! + +## 1.10.0 + +### Features + +- [#10270](https://github.com/gradio-app/gradio/pull/10270) [`bb11a2a`](https://github.com/gradio-app/gradio/commit/bb11a2a702ca04fde245e7d54d155cbcbde7791e) - [ZeroGPU] Handshake-based postMessage. Thanks @cbensimon! + +### Fixes + +- [#10332](https://github.com/gradio-app/gradio/pull/10332) [`e742dcc`](https://github.com/gradio-app/gradio/commit/e742dcccb376692c9ddd5a6c251080e7c5936574) - Allow users to add a custom API route. Thanks @aliabid94! + +## 1.9.0 + +### Features + +- [#10262](https://github.com/gradio-app/gradio/pull/10262) [`f3bedd4`](https://github.com/gradio-app/gradio/commit/f3bedd4011bdfdecc952eb1275a9dd96af3e8d71) - add gr.Success and update windows contributing. Thanks @not-lain! +- [#10254](https://github.com/gradio-app/gradio/pull/10254) [`da07707`](https://github.com/gradio-app/gradio/commit/da0770748db9ea40194a43c9138ee2c6536b1247) - Add a `settings` link to the footer with i18n options & pwa instructions. Thanks @abidlabs! + +## 1.8.0 + +### Features + +- [#9930](https://github.com/gradio-app/gradio/pull/9930) [`eae345e`](https://github.com/gradio-app/gradio/commit/eae345e5fde39aea220b57c6a954cd7d72ff32d5) - Allow settings custom headers in js client. Thanks @elgiano! +- [#9950](https://github.com/gradio-app/gradio/pull/9950) [`fc06fe4`](https://github.com/gradio-app/gradio/commit/fc06fe41f015678a0545f4e5c99f6ae2704f0031) - Add ability to read and write from LocalStorage. Thanks @abidlabs! + +## 1.7.1 + +### Fixes + +- [#9814](https://github.com/gradio-app/gradio/pull/9814) [`6505d42`](https://github.com/gradio-app/gradio/commit/6505d4289a3e3d27d9133b1c8af41697fdc1476d) - support gradio apps on spaces served on subpaths. Thanks @pngwn! + +## 1.7.0 + +### Features + +- [#9681](https://github.com/gradio-app/gradio/pull/9681) [`2ed2361`](https://github.com/gradio-app/gradio/commit/2ed236187a9aab18e17fc4a8079eddef7dd195a5) - Allow setting title in gr.Info/Warning/Error. Thanks @ABucket! + +## 1.6.0 + +### Features + +- [#8843](https://github.com/gradio-app/gradio/pull/8843) [`6f95286`](https://github.com/gradio-app/gradio/commit/6f95286337459efbccb95c9cfac63355669df9ee) - Disable liking user message in chatbot by default but make it configurable +- [#8843](https://github.com/gradio-app/gradio/pull/8843) [`6f95286`](https://github.com/gradio-app/gradio/commit/6f95286337459efbccb95c9cfac63355669df9ee) - Open audio/image input stream only when queue is ready +- [#8843](https://github.com/gradio-app/gradio/pull/8843) [`6f95286`](https://github.com/gradio-app/gradio/commit/6f95286337459efbccb95c9cfac63355669df9ee) - Send Streaming data over Websocket if possible. Also support base64 output format for images. +- [#8843](https://github.com/gradio-app/gradio/pull/8843) [`6f95286`](https://github.com/gradio-app/gradio/commit/6f95286337459efbccb95c9cfac63355669df9ee) - Streaming inputs for 5.0 +- [#8843](https://github.com/gradio-app/gradio/pull/8843) [`6f95286`](https://github.com/gradio-app/gradio/commit/6f95286337459efbccb95c9cfac63355669df9ee) - fix SSR apps on spaces +- [#8843](https://github.com/gradio-app/gradio/pull/8843) [`6f95286`](https://github.com/gradio-app/gradio/commit/6f95286337459efbccb95c9cfac63355669df9ee) - Ssr part 2 +- [#8843](https://github.com/gradio-app/gradio/pull/8843) [`6f95286`](https://github.com/gradio-app/gradio/commit/6f95286337459efbccb95c9cfac63355669df9ee) - prefix api routes + +### Fixes + + +- [#8843](https://github.com/gradio-app/gradio/pull/8843) [`6f95286`](https://github.com/gradio-app/gradio/commit/6f95286337459efbccb95c9cfac63355669df9ee) - Trigger state change event on iterators + +## 1.6.0-beta.4 + +### Features + +- [#9483](https://github.com/gradio-app/gradio/pull/9483) [`8dc7c12`](https://github.com/gradio-app/gradio/commit/8dc7c12389311b60efcde1b9d3e3668a34d2dc00) - Send Streaming data over Websocket if possible. Also support base64 output format for images. Thanks @freddyaboulton! + +## 1.6.0-beta.3 + +### Features + +- [#9412](https://github.com/gradio-app/gradio/pull/9412) [`c2c2fd9`](https://github.com/gradio-app/gradio/commit/c2c2fd989348f826566773c07c0e0bda200199ff) - fix SSR apps on spaces. Thanks @pngwn! + +## 1.6.0-beta.2 + +### Features + +- [#9323](https://github.com/gradio-app/gradio/pull/9323) [`06babda`](https://github.com/gradio-app/gradio/commit/06babda0395fd3fbd323c1c3cb33704ecfd6deb0) - Disable liking user message in chatbot by default but make it configurable. Thanks @freddyaboulton! +- [#9339](https://github.com/gradio-app/gradio/pull/9339) [`4c8c6f2`](https://github.com/gradio-app/gradio/commit/4c8c6f2fe603081941c5fdc43f48a0632b9f31ad) - Ssr part 2. Thanks @pngwn! + +### Fixes + +- [#9299](https://github.com/gradio-app/gradio/pull/9299) [`aa35b07`](https://github.com/gradio-app/gradio/commit/aa35b0788e613fdd45446d267513e6f94fa208ea) - Trigger state change event on iterators. Thanks @freddyaboulton! + +## 1.6.0-beta.1 + +### Features + +- [#9200](https://github.com/gradio-app/gradio/pull/9200) [`2e179d3`](https://github.com/gradio-app/gradio/commit/2e179d35be6ed60a5a6bfc7303178d63e41781ad) - prefix api routes. Thanks @pngwn! + +## 1.6.0-beta.0 + +### Features + +- [#9149](https://github.com/gradio-app/gradio/pull/9149) [`3d7a9b8`](https://github.com/gradio-app/gradio/commit/3d7a9b81f6fef06187eca832471dc1692eb493a0) - Open audio/image input stream only when queue is ready. Thanks @freddyaboulton! +- [#8941](https://github.com/gradio-app/gradio/pull/8941) [`97a7bf6`](https://github.com/gradio-app/gradio/commit/97a7bf66a79179d1b91a3199d68e5c11216ca500) - Streaming inputs for 5.0. Thanks @freddyaboulton! + +## 1.5.2 + +### Fixes + +- [#9163](https://github.com/gradio-app/gradio/pull/9163) [`2b6cbf2`](https://github.com/gradio-app/gradio/commit/2b6cbf25908e42cf027324e54ef2cc0baad11a91) - fix exports and generate types. Thanks @pngwn! + +## 1.5.1 + +### Features + +- [#9118](https://github.com/gradio-app/gradio/pull/9118) [`e1c404d`](https://github.com/gradio-app/gradio/commit/e1c404da1143fb52b659d03e028bdba1badf443d) - setup npm-previews of all packages. Thanks @pngwn! + +## 1.5.0 + +### Features + +- [#8965](https://github.com/gradio-app/gradio/pull/8965) [`d30432e`](https://github.com/gradio-app/gradio/commit/d30432e9c6d4cc1e5cfd989a1a3ae4aba7e21290) - harden CI. Thanks @pngwn! + +### Fixes + +- [#8847](https://github.com/gradio-app/gradio/pull/8847) [`4d8a473`](https://github.com/gradio-app/gradio/commit/4d8a473632e388a312aee5c705b3c1f79853441b) - fix: wrong named param check for js client. Thanks @freddyaboulton! + +## 1.4.0 + +### Features + +- [#8816](https://github.com/gradio-app/gradio/pull/8816) [`9ee6839`](https://github.com/gradio-app/gradio/commit/9ee6839f94d23d685a800ed3a275206e0b0e48f6) - Change optionality of the `data` param in `submit` + `predict`. Thanks @hannahblair! + +### Fixes + +- [#8820](https://github.com/gradio-app/gradio/pull/8820) [`5050b36`](https://github.com/gradio-app/gradio/commit/5050b36221e75a18d8a5d4f74a725e70768a4c4a) - fix: wrong named param check for js client. Thanks @JacobLinCool! + +## 1.3.0 + +### Fixes + +- [#8699](https://github.com/gradio-app/gradio/pull/8699) [`012da05`](https://github.com/gradio-app/gradio/commit/012da05287846d94beb0ecdc28d7fbc48c4248ff) - Ensure JS client `status_callback` functionality works and improve status messages. Thanks @hannahblair! +- [#8505](https://github.com/gradio-app/gradio/pull/8505) [`2943d6d`](https://github.com/gradio-app/gradio/commit/2943d6d68847314885dc6c5c0247083116017ca0) - Add Timer component. Thanks @aliabid94! +- [#8715](https://github.com/gradio-app/gradio/pull/8715) [`a6b3c6c`](https://github.com/gradio-app/gradio/commit/a6b3c6ce4e1d06253860c72740024a9138e3a93a) - Ensure `@gradio/client`'s `submit` iterator releases as expected. Thanks @pngwn! +- [#8716](https://github.com/gradio-app/gradio/pull/8716) [`e834d30`](https://github.com/gradio-app/gradio/commit/e834d302e44f7a54565129bf2c11acf4e882a59b) - ensure `@gradio/client` always returns the correct data. Thanks @pngwn! +- [#8714](https://github.com/gradio-app/gradio/pull/8714) [`1b5b5b0`](https://github.com/gradio-app/gradio/commit/1b5b5b0b43e69ee84f3baad2aae59ffc9c4d995a) - Bind `fetch` and `stream` in JS client. Thanks @hannahblair! +- [#8720](https://github.com/gradio-app/gradio/pull/8720) [`936c713`](https://github.com/gradio-app/gradio/commit/936c7137a99ef59efdf75bae5dd27eea2ac1f577) - Documents auth in the guides, in the view API page, and also types the Blocks.config object. Thanks @abidlabs! + +## 1.2.1 + +### Features + +- [#8649](https://github.com/gradio-app/gradio/pull/8649) [`4b6c8b1`](https://github.com/gradio-app/gradio/commit/4b6c8b1c004cee67345a7f103ba2dc8e90b82e6c) - ensure `File` objects are handled in JS client `handle_file`. Thanks @hannahblair! + +## 1.2.0 + +### Features + +- [#8489](https://github.com/gradio-app/gradio/pull/8489) [`c2a0d05`](https://github.com/gradio-app/gradio/commit/c2a0d056d679d90631d9ccd944dadd67e7e03b7f) - Control Display of Error, Info, Warning. Thanks @freddyaboulton! +- [#8571](https://github.com/gradio-app/gradio/pull/8571) [`a77877f`](https://github.com/gradio-app/gradio/commit/a77877f62df7c610fcfac7b3b00e186a087c8ec6) - First time loading performance optimization. Thanks @baojianting! +- [#8600](https://github.com/gradio-app/gradio/pull/8600) [`7289c4b`](https://github.com/gradio-app/gradio/commit/7289c4b036d8a78c48f8c9e66ba998e6730e80d2) - Add credentials: include and Cookie header to prevent 401 error. Thanks @yinkiu602! +- [#8522](https://github.com/gradio-app/gradio/pull/8522) [`bdaa678`](https://github.com/gradio-app/gradio/commit/bdaa678d0c0a22250b41104f32e9121f98dc7437) - add handle_file docs. Thanks @pngwn! + +### Fixes + +- [#8521](https://github.com/gradio-app/gradio/pull/8521) [`900cf25`](https://github.com/gradio-app/gradio/commit/900cf25256a5b0563860097d69aac28b6afbfd8b) - Ensure frontend functions work when they don't return a value. Thanks @pngwn! +- [#8548](https://github.com/gradio-app/gradio/pull/8548) [`7fc0f51`](https://github.com/gradio-app/gradio/commit/7fc0f5149bb8d31f3d01b4151b478070499751ee) - Fix reload mode by implementing `close` on the client. Thanks @freddyaboulton! + +## 1.1.1 + +### Features + +- [#8499](https://github.com/gradio-app/gradio/pull/8499) [`c5f6e77`](https://github.com/gradio-app/gradio/commit/c5f6e7722a197d4706419ade14276ddecf3196f8) - Cache break themes on change. Thanks @aliabid94! + +## 1.1.0 + +### Features + +- [#8483](https://github.com/gradio-app/gradio/pull/8483) [`e2271e2`](https://github.com/gradio-app/gradio/commit/e2271e207d98074bf39b02ae3c5443b2f097627d) - documentation for @gradio/client. Thanks @pngwn! +- [#8485](https://github.com/gradio-app/gradio/pull/8485) [`f8ebace`](https://github.com/gradio-app/gradio/commit/f8ebaceccef60a112603d290d10072ef4e938a6a) - Ensure all status are reported internally when calling `predict`. Thanks @pngwn! + +## 1.0.0 + +### Highlights + +#### Clients 1.0 Launch! ([#8468](https://github.com/gradio-app/gradio/pull/8468) [`7cc0a0c`](https://github.com/gradio-app/gradio/commit/7cc0a0c1abea585c3f50ffb1ff78d2b08ddbdd92)) + +We're excited to unveil the first major release of the Gradio clients. +We've made it even easier to turn any Gradio application into a production endpoint thanks to the clients' **ergonomic**, **transparent**, and **portable** design. + +#### Ergonomic API 💆 + +**Stream From a Gradio app in 5 lines** + +Use the `submit` method to get a job you can iterate over: + +```python +from gradio_client import Client + +client = Client("gradio/llm_stream") + +for result in client.submit("What's the best UI framework in Python?"): + print(result) +``` + +```ts +import { Client } from "@gradio/client"; + +const client = await Client.connect("gradio/llm_stream") +const job = client.submit("/predict", {"text": "What's the best UI framework in Python?"}) + +for await (const msg of job) console.log(msg.data) +``` + +**Use the same keyword arguments as the app** + + +```python +from gradio_client import Client + +client = Client("http://127.0.0.1:7860/") +result = client.predict( + message="Hello!!", + system_prompt="You are helpful AI.", + tokens=10, + api_name="/chat" +) +print(result) +``` + +```ts +import { Client } from "@gradio/client"; + +const client = await Client.connect("http://127.0.0.1:7860/"); +const result = await client.predict("/chat", { + message: "Hello!!", + system_prompt: "Hello!!", + tokens: 10, +}); + +console.log(result.data); +``` + +**Better Error Messages** + +If something goes wrong in the upstream app, the client will raise the same exception as the app provided that `show_error=True` in the original app's `launch()` function, or it's a `gr.Error` exception. + +#### Transparent Design 🪟 + +Anything you can do in the UI, you can do with the client: +* 🔒 Authentication +* 🛑 Job Cancelling +* ℹ️ Access Queue Position and API +* 📕 View the API information + +Here's an example showing how to display the queue position of a pending job: + +```python +from gradio_client import Client + +client = Client("gradio/diffusion_model") + +job = client.submit("A cute cat") +while not job.done(): + status = job.status() + print(f"Current in position {status.rank} out of {status.queue_size}") +``` + +#### Portable Design ⛺️ + +The client can run from pretty much any python and javascript environment (node, deno, the browser, Service Workers). + +Here's an example using the client from a Flask server using gevent: + +```python +from gevent import monkey +monkey.patch_all() + +from gradio_client import Client +from flask import Flask, send_file +import time + +app = Flask(__name__) + +imageclient = Client("gradio/diffusion_model") + +@app.route("/gen") +def gen(): + result = imageclient.predict( + "A cute cat", + api_name="/predict" + ) + return send_file(result) + +if __name__ == "__main__": + app.run(host="0.0.0.0", port=5000) +``` + +#### 1.0 Migration Guide and Breaking Changes + +**Python** +- The `serialize` argument of the `Client` class was removed. Has no effect. +- The `upload_files` argument of the `Client` was removed. +- All filepaths must be wrapped in the `handle_file` method. Example: +```python +from gradio_client import Client, handle_file + +client = Client("gradio/image_captioner") +client.predict(handle_file("cute_cat.jpg")) +``` +- The `output_dir` argument was removed. It is not specified in the `download_files` argument. + + +**Javascript** +The client has been redesigned entirely. It was refactored from a function into a class. An instance can now be constructed by awaiting the `connect` method. + +```js +const app = await Client.connect("gradio/whisper") +``` +The app variable has the same methods as the python class (`submit`, `predict`, `view_api`, `duplicate`). + + + +#### Additional Changes + +- [#8243](https://github.com/gradio-app/gradio/pull/8243) - Set orig_name in python client file uploads. +- [#8264](https://github.com/gradio-app/gradio/pull/8264) - Make exceptions in the Client more specific. +- [#8247](https://github.com/gradio-app/gradio/pull/8247) - Fix api recorder. +- [#8276](https://github.com/gradio-app/gradio/pull/8276) - Fix bug where client could not connect to apps that had self signed certificates. +- [#8245](https://github.com/gradio-app/gradio/pull/8245) - Cancel server progress from the python client. +- [#8200](https://github.com/gradio-app/gradio/pull/8200) - Support custom components in gr.load +- [#8182](https://github.com/gradio-app/gradio/pull/8182) - Convert sse calls in client from async to sync. +- [#7732](https://github.com/gradio-app/gradio/pull/7732) - Adds support for kwargs and default arguments in the python client, and improves how parameter information is displayed in the "view API" page. +- [#7888](https://github.com/gradio-app/gradio/pull/7888) - Cache view_api info in server and python client. +- [#7575](https://github.com/gradio-app/gradio/pull/7575) - Files should now be supplied as `file(...)` in the Client, and some fixes to `gr.load()` as well. +- [#8401](https://github.com/gradio-app/gradio/pull/8401) - Add CDN installation to JS docs. +- [#8299](https://github.com/gradio-app/gradio/pull/8299) - Allow JS Client to work with authenticated spaces 🍪. +- [#8408](https://github.com/gradio-app/gradio/pull/8408) - Connect heartbeat if state created in render. Also fix config cleanup bug #8407. +- [#8258](https://github.com/gradio-app/gradio/pull/8258) - Improve URL handling in JS Client. +- [#8322](https://github.com/gradio-app/gradio/pull/8322) - ensure the client correctly handles all binary data. +- [#8296](https://github.com/gradio-app/gradio/pull/8296) - always create a jwt when connecting to a space if a hf_token is present. +- [#8285](https://github.com/gradio-app/gradio/pull/8285) - use the correct query param to pass the jwt to the heartbeat event. +- [#8272](https://github.com/gradio-app/gradio/pull/8272) - ensure client works for private spaces. +- [#8197](https://github.com/gradio-app/gradio/pull/8197) - Add support for passing keyword args to `data` in JS client. +- [#8252](https://github.com/gradio-app/gradio/pull/8252) - Client node fix. +- [#8209](https://github.com/gradio-app/gradio/pull/8209) - Rename `eventSource_Factory` and `fetch_implementation`. +- [#8109](https://github.com/gradio-app/gradio/pull/8109) - Implement JS Client tests. +- [#8211](https://github.com/gradio-app/gradio/pull/8211) - remove redundant event source logic. +- [#8179](https://github.com/gradio-app/gradio/pull/8179) - rework upload to be a class method + pass client into each component. +- [#8181](https://github.com/gradio-app/gradio/pull/8181) - Ensure connectivity to private HF spaces with SSE protocol. +- [#8169](https://github.com/gradio-app/gradio/pull/8169) - Only connect to heartbeat if needed. +- [#8118](https://github.com/gradio-app/gradio/pull/8118) - Add eventsource polyfill for Node.js and browser environments. +- [#7646](https://github.com/gradio-app/gradio/pull/7646) - Refactor JS Client. +- [#7974](https://github.com/gradio-app/gradio/pull/7974) - Fix heartbeat in the js client to be Lite compatible. +- [#7926](https://github.com/gradio-app/gradio/pull/7926) - Fixes streaming event race condition. + + Thanks @freddyaboulton! + +### Features + +- [#8370](https://github.com/gradio-app/gradio/pull/8370) [`48eeea4`](https://github.com/gradio-app/gradio/commit/48eeea4eaab7e24168688e3c3fbafb30e4e78d51) - Refactor Cancelling Logic To Use /cancel. Thanks @freddyaboulton! + +### Fixes + +- [#8477](https://github.com/gradio-app/gradio/pull/8477) [`d5a9604`](https://github.com/gradio-app/gradio/commit/d5a960493017a4890685af61d78ce7d3b3b12e6b) - Fix js client bundle. Thanks @pngwn! +- [#8451](https://github.com/gradio-app/gradio/pull/8451) [`9d2d605`](https://github.com/gradio-app/gradio/commit/9d2d6051caed5c8749a26a6fa7480a5ae6e6c4f3) - Change client submit API to be an AsyncIterable and support more platforms. Thanks @pngwn! +- [#8462](https://github.com/gradio-app/gradio/pull/8462) [`6447dfa`](https://github.com/gradio-app/gradio/commit/6447dface4d46db1c69460e8325a1928d0476a46) - Improve file handling in JS Client. Thanks @hannahblair! +- [#8439](https://github.com/gradio-app/gradio/pull/8439) [`63d36fb`](https://github.com/gradio-app/gradio/commit/63d36fbbf4bf6dc909be9a0ffc7b6bf6621d83e8) - Handle gradio apps using `state` in the JS Client. Thanks @hannahblair! + +## 0.20.1 + +### Features + +- [#8415](https://github.com/gradio-app/gradio/pull/8415) [`227de35`](https://github.com/gradio-app/gradio/commit/227de352982b3dcdf9384eaa28b7e9cf09afb6e8) - Fix spaces load error. Thanks @aliabid94! + +## 0.20.0 + +### Features + +- [#8401](https://github.com/gradio-app/gradio/pull/8401) [`d078621`](https://github.com/gradio-app/gradio/commit/d078621928136c09ca902d2f37594ed887c67d2e) - Add CDN installation to JS docs. Thanks @hannahblair! +- [#8243](https://github.com/gradio-app/gradio/pull/8243) [`55f664f`](https://github.com/gradio-app/gradio/commit/55f664f2979a49acc29a73cde16c6ebdfcc91db2) - Add event listener support to render blocks. Thanks @aliabid94! +- [#8398](https://github.com/gradio-app/gradio/pull/8398) [`945ac83`](https://github.com/gradio-app/gradio/commit/945ac837e779b120790814ea6f6f81bd2712f5f8) - Improve rendering. Thanks @aliabid94! +- [#8299](https://github.com/gradio-app/gradio/pull/8299) [`ab65360`](https://github.com/gradio-app/gradio/commit/ab653608045ff9462db7ad9fe63e1c60bf20e773) - Allow JS Client to work with authenticated spaces 🍪. Thanks @hannahblair! + +### Fixes + +- [#8408](https://github.com/gradio-app/gradio/pull/8408) [`e86dd01`](https://github.com/gradio-app/gradio/commit/e86dd01b6e8f7bab3d3c25b84f2ad33129138af4) - Connect heartbeat if state created in render. Also fix config cleanup bug #8407. Thanks @freddyaboulton! +- [#8258](https://github.com/gradio-app/gradio/pull/8258) [`1f8e5c4`](https://github.com/gradio-app/gradio/commit/1f8e5c44e054b943052d8f24d044696ddfd01a54) - Improve URL handling in JS Client. Thanks @hannahblair! + +## 0.19.4 + +### Fixes + +- [#8322](https://github.com/gradio-app/gradio/pull/8322) [`47012a0`](https://github.com/gradio-app/gradio/commit/47012a0c4e3e8a80fcae620aaf08b16ceb343cde) - ensure the client correctly handles all binary data. Thanks @Saghen! + +## 0.19.3 + +### Features + +- [#8229](https://github.com/gradio-app/gradio/pull/8229) [`7c81897`](https://github.com/gradio-app/gradio/commit/7c81897076ddcd0bb05e0e4ffec35bb9a986d330) - chore(deps): update dependency esbuild to ^0.21.0. Thanks @renovate! + +### Fixes + +- [#8296](https://github.com/gradio-app/gradio/pull/8296) [`929d216`](https://github.com/gradio-app/gradio/commit/929d216d49aa05614bc83f0761cf7b1cd803d8fe) - always create a jwt when connecting to a space if a hf_token is present. Thanks @pngwn! + +## 0.19.2 + +### Fixes + +- [#8285](https://github.com/gradio-app/gradio/pull/8285) [`7d9d8ea`](https://github.com/gradio-app/gradio/commit/7d9d8eab50d36cbecbb84c6a0f3cc1bca7215604) - use the correct query param to pass the jwt to the heartbeat event. Thanks @pngwn! + +## 0.19.1 + +### Fixes + +- [#8272](https://github.com/gradio-app/gradio/pull/8272) [`fbf4edd`](https://github.com/gradio-app/gradio/commit/fbf4edde7c896cdf4c903463e44c31ed96111b3c) - ensure client works for private spaces. Thanks @pngwn! + +## 0.19.0 + +### Features + +- [#8110](https://github.com/gradio-app/gradio/pull/8110) [`5436031`](https://github.com/gradio-app/gradio/commit/5436031f92c1596282eb64e1e74d555f279e9697) - Render decorator 2. Thanks @aliabid94! +- [#8197](https://github.com/gradio-app/gradio/pull/8197) [`e09b4e8`](https://github.com/gradio-app/gradio/commit/e09b4e8216b970bc1b142a0f08e7d190b954eb35) - Add support for passing keyword args to `data` in JS client. Thanks @hannahblair! + +### Fixes + +- [#8252](https://github.com/gradio-app/gradio/pull/8252) [`22df61a`](https://github.com/gradio-app/gradio/commit/22df61a26adf8023f6dd49c051979990e8d3879a) - Client node fix. Thanks @pngwn! + +## 0.18.0 + +### Features + +- [#8121](https://github.com/gradio-app/gradio/pull/8121) [`f5b710c`](https://github.com/gradio-app/gradio/commit/f5b710c919b0ce604ea955f0d5f4faa91095ca4a) - chore(deps): update dependency eslint to v9. Thanks @renovate! +- [#8209](https://github.com/gradio-app/gradio/pull/8209) [`b9afe93`](https://github.com/gradio-app/gradio/commit/b9afe93915401df5bd6737c89395c2477acfa585) - Rename `eventSource_Factory` and `fetch_implementation`. Thanks @hannahblair! +- [#8109](https://github.com/gradio-app/gradio/pull/8109) [`bed2f82`](https://github.com/gradio-app/gradio/commit/bed2f82e2297b50f7b59423a3de05af0b9910724) - Implement JS Client tests. Thanks @hannahblair! +- [#8211](https://github.com/gradio-app/gradio/pull/8211) [`91b5cd6`](https://github.com/gradio-app/gradio/commit/91b5cd6132fb8903c92f70fce0800324836a1fc3) - remove redundant event source logic. Thanks @hannahblair! + +### Fixes + +- [#8179](https://github.com/gradio-app/gradio/pull/8179) [`6a218b4`](https://github.com/gradio-app/gradio/commit/6a218b4148095aaa0c58d8c20973ba01c8764fc2) - rework upload to be a class method + pass client into each component. Thanks @pngwn! +- [#8181](https://github.com/gradio-app/gradio/pull/8181) [`cf52ca6`](https://github.com/gradio-app/gradio/commit/cf52ca6a51320ece97f009a177792840b5fbc785) - Ensure connectivity to private HF spaces with SSE protocol. Thanks @hannahblair! +- [#8169](https://github.com/gradio-app/gradio/pull/8169) [`3a6f1a5`](https://github.com/gradio-app/gradio/commit/3a6f1a50b263e0a733f609a08019fc4d05480e1a) - Only connect to heartbeat if needed. Thanks @freddyaboulton! +- [#8118](https://github.com/gradio-app/gradio/pull/8118) [`7aca673`](https://github.com/gradio-app/gradio/commit/7aca673b38a087533524b2fd8dd3a03e0e4bacfe) - Add eventsource polyfill for Node.js and browser environments. Thanks @hannahblair! + +## 0.17.0 + +### Highlights + +#### Setting File Upload Limits ([#7909](https://github.com/gradio-app/gradio/pull/7909) [`2afca65`](https://github.com/gradio-app/gradio/commit/2afca6541912b37dc84f447c7ad4af21607d7c72)) + +We have added a `max_file_size` size parameter to `launch()` that limits to size of files uploaded to the server. This limit applies to each individual file. This parameter can be specified as a string or an integer (corresponding to the size in bytes). + +The following code snippet sets a max file size of 5 megabytes. + +```python +import gradio as gr + +demo = gr.Interface(lambda x: x, "image", "image") + +demo.launch(max_file_size="5mb") +# or +demo.launch(max_file_size=5 * gr.FileSize.MB) +``` + +![max_file_size_upload](https://github.com/gradio-app/gradio/assets/41651716/7547330c-a082-4901-a291-3f150a197e45) + + +#### Error states can now be cleared + +When a component encounters an error, the error state shown in the UI can now be cleared by clicking on the `x` icon in the top right of the component. This applies to all types of errors, whether it's raised in the UI or the server. + +![error_modal_calculator](https://github.com/gradio-app/gradio/assets/41651716/16cb071c-accd-45a6-9c18-0dea27d4bd98) + + Thanks @freddyaboulton! + +### Features + +- [#8056](https://github.com/gradio-app/gradio/pull/8056) [`2e469a5`](https://github.com/gradio-app/gradio/commit/2e469a5f99e52a5011a010f46e47dde7bb0c7140) - Using keys to preserve values between reloads. Thanks @aliabid94! +- [#7646](https://github.com/gradio-app/gradio/pull/7646) [`450b8cc`](https://github.com/gradio-app/gradio/commit/450b8cc898f130f15caa3742f65c17b9f7a8f398) - Refactor JS Client. Thanks @hannahblair! +- [#8061](https://github.com/gradio-app/gradio/pull/8061) [`17e83c9`](https://github.com/gradio-app/gradio/commit/17e83c958ebb35b3e122ca486067d1bd5ce33a22) - Docs Reorg and Intro Page. Thanks @aliabd! + +### Fixes + +- [#8066](https://github.com/gradio-app/gradio/pull/8066) [`624f9b9`](https://github.com/gradio-app/gradio/commit/624f9b9477f74a581a6c14119234f9efdfcda398) - make gradio dev tools a local dependency rather than bundling. Thanks @pngwn! + +## 0.16.0 + +### Features + +- [#7845](https://github.com/gradio-app/gradio/pull/7845) [`dbb7373`](https://github.com/gradio-app/gradio/commit/dbb7373dde69d4ed2741942b5a1898f8620cec24) - ensure `ImageEditor` events work as expected. Thanks @pngwn! + +### Fixes + +- [#7974](https://github.com/gradio-app/gradio/pull/7974) [`79e0aa8`](https://github.com/gradio-app/gradio/commit/79e0aa81c94e755faa6e85d76ac5d5a666313e6a) - Fix heartbeat in the js client to be Lite compatible. Thanks @whitphx! + +## 0.15.1 + +### Fixes + +- [#7926](https://github.com/gradio-app/gradio/pull/7926) [`9666854`](https://github.com/gradio-app/gradio/commit/966685479078f59430b3bced7e6068eb8157c003) - Fixes streaming event race condition. Thanks @aliabid94! + +## 0.15.0 + +### Highlights + +#### Automatically delete state after user has disconnected from the webpage ([#7829](https://github.com/gradio-app/gradio/pull/7829) [`6a4bf7a`](https://github.com/gradio-app/gradio/commit/6a4bf7abe29059dbdc6a342e0366fdaa2e4120ee)) + +Gradio now automatically deletes `gr.State` variables stored in the server's RAM when users close their browser tab. +The deletion will happen 60 minutes after the server detected a disconnect from the user's browser. +If the user connects again in that timeframe, their state will not be deleted. + +Additionally, Gradio now includes a `Blocks.unload()` event, allowing you to run arbitrary cleanup functions when users disconnect (this does not have a 60 minute delay). +You can think of the `unload` event as the opposite of the `load` event. + + +```python +with gr.Blocks() as demo: + gr.Markdown( +"""# State Cleanup Demo +🖼️ Images are saved in a user-specific directory and deleted when the users closes the page via demo.unload. +""") + with gr.Row(): + with gr.Column(scale=1): + with gr.Row(): + img = gr.Image(label="Generated Image", height=300, width=300) + with gr.Row(): + gen = gr.Button(value="Generate") + with gr.Row(): + history = gr.Gallery(label="Previous Generations", height=500, columns=10) + state = gr.State(value=[], delete_callback=lambda v: print("STATE DELETED")) + + demo.load(generate_random_img, [state], [img, state, history]) + gen.click(generate_random_img, [state], [img, state, history]) + demo.unload(delete_directory) + + +demo.launch(auth=lambda user,pwd: True, + auth_message="Enter any username and password to continue") +``` + + Thanks @freddyaboulton! + +## 0.14.0 + +### Features + +- [#7691](https://github.com/gradio-app/gradio/pull/7691) [`84f81fe`](https://github.com/gradio-app/gradio/commit/84f81fec9287b041203a141bbf2852720f7d199c) - Closing stream from the backend. Thanks @aliabid94! + +### Fixes + +- [#7564](https://github.com/gradio-app/gradio/pull/7564) [`5d1e8da`](https://github.com/gradio-app/gradio/commit/5d1e8dae5ac23f605c3b5f41dbe18751dff380a0) - batch UI updates on a per frame basis. Thanks @pngwn! + +## 0.13.0 + +### Fixes + +- [#7575](https://github.com/gradio-app/gradio/pull/7575) [`d0688b3`](https://github.com/gradio-app/gradio/commit/d0688b3c25feabb4fc7dfa0ab86086b3af7eb337) - Files should now be supplied as `file(...)` in the Client, and some fixes to `gr.load()` as well. Thanks @abidlabs! + +## 0.12.2 + +### Features + +- [#7528](https://github.com/gradio-app/gradio/pull/7528) [`eda33b3`](https://github.com/gradio-app/gradio/commit/eda33b3763897a542acf298e523fa493dc655aee) - Refactors `get_fetchable_url_or_file()` to remove it from the frontend. Thanks [@abidlabs](https://github.com/abidlabs)! +- [#7340](https://github.com/gradio-app/gradio/pull/7340) [`4b0d589`](https://github.com/gradio-app/gradio/commit/4b0d58933057432758a54169a360eb352903d6b4) - chore(deps): update all non-major dependencies. Thanks [@renovate](https://github.com/apps/renovate)! + +## 0.12.1 + +### Fixes + +- [#7411](https://github.com/gradio-app/gradio/pull/7411) [`32b317f`](https://github.com/gradio-app/gradio/commit/32b317f24e3d43f26684bb9f3964f31efd0ea556) - Set `root` correctly for Gradio apps that are deployed behind reverse proxies. Thanks [@abidlabs](https://github.com/abidlabs)! + +## 0.12.0 + +### Features + +- [#7183](https://github.com/gradio-app/gradio/pull/7183) [`49d9c48`](https://github.com/gradio-app/gradio/commit/49d9c48537aa706bf72628e3640389470138bdc6) - [WIP] Refactor file normalization to be in the backend and remove it from the frontend of each component. Thanks [@abidlabs](https://github.com/abidlabs)! + +## 0.11.0 + +### Features + +- [#7102](https://github.com/gradio-app/gradio/pull/7102) [`68a54a7`](https://github.com/gradio-app/gradio/commit/68a54a7a310d8d7072fdae930bf1cfdf12c45a7f) - Improve chatbot streaming performance with diffs. Thanks [@aliabid94](https://github.com/aliabid94)!/n Note that this PR changes the API format for generator functions, which would be a breaking change for any clients reading the EventStream directly + +## 0.10.1 + +### Fixes + +- [#7055](https://github.com/gradio-app/gradio/pull/7055) [`3c3cf86`](https://github.com/gradio-app/gradio/commit/3c3cf8618a8cad1ef66a7f96664923d2c9f5e0e2) - Fix UI freeze on rapid generators. Thanks [@aliabid94](https://github.com/aliabid94)! + +## 0.10.0 + +### Features + +- [#6931](https://github.com/gradio-app/gradio/pull/6931) [`6c863af`](https://github.com/gradio-app/gradio/commit/6c863af92fa9ceb5c638857eb22cc5ddb718d549) - Fix functional tests. Thanks [@aliabid94](https://github.com/aliabid94)! +- [#6820](https://github.com/gradio-app/gradio/pull/6820) [`649cd4d`](https://github.com/gradio-app/gradio/commit/649cd4d68041d11fcbe31f8efa455345ac49fc74) - Use `EventSource_factory` in `open_stream()` for Wasm. Thanks [@whitphx](https://github.com/whitphx)! + +## 0.9.4 + +### Fixes + +- [#6863](https://github.com/gradio-app/gradio/pull/6863) [`d406855`](https://github.com/gradio-app/gradio/commit/d4068557953746662235d595ec435c42ceb24414) - Fix JS Client when app is running behind a proxy. Thanks [@freddyaboulton](https://github.com/freddyaboulton)! + +## 0.9.3 + +### Features + +- [#6814](https://github.com/gradio-app/gradio/pull/6814) [`828fb9e`](https://github.com/gradio-app/gradio/commit/828fb9e6ce15b6ea08318675a2361117596a1b5d) - Refactor queue so that there are separate queues for each concurrency id. Thanks [@aliabid94](https://github.com/aliabid94)! + +## 0.9.2 + +### Features + +- [#6798](https://github.com/gradio-app/gradio/pull/6798) [`245d58e`](https://github.com/gradio-app/gradio/commit/245d58eff788e8d44a59d37a2d9b26d0f08a62b4) - Improve how server/js client handle unexpected errors. Thanks [@freddyaboulton](https://github.com/freddyaboulton)! + +## 0.9.1 + +### Fixes + +- [#6693](https://github.com/gradio-app/gradio/pull/6693) [`34f9431`](https://github.com/gradio-app/gradio/commit/34f943101bf7dd6b8a8974a6131c1ed7c4a0dac0) - Python client properly handles hearbeat and log messages. Also handles responses longer than 65k. Thanks [@freddyaboulton](https://github.com/freddyaboulton)! + +## 0.9.0 + +### Features + +- [#6398](https://github.com/gradio-app/gradio/pull/6398) [`67ddd40`](https://github.com/gradio-app/gradio/commit/67ddd40b4b70d3a37cb1637c33620f8d197dbee0) - Lite v4. Thanks [@whitphx](https://github.com/whitphx)! + +### Fixes + +- [#6556](https://github.com/gradio-app/gradio/pull/6556) [`d76bcaa`](https://github.com/gradio-app/gradio/commit/d76bcaaaf0734aaf49a680f94ea9d4d22a602e70) - Fix api event drops. Thanks [@aliabid94](https://github.com/aliabid94)! + +## 0.8.2 + +### Features + +- [#6511](https://github.com/gradio-app/gradio/pull/6511) [`71f1a1f99`](https://github.com/gradio-app/gradio/commit/71f1a1f9931489d465c2c1302a5c8d768a3cd23a) - Mark `FileData.orig_name` optional on the frontend aligning the type definition on the Python side. Thanks [@whitphx](https://github.com/whitphx)! + +## 0.8.1 + +### Fixes + +- [#6383](https://github.com/gradio-app/gradio/pull/6383) [`324867f63`](https://github.com/gradio-app/gradio/commit/324867f63c920113d89a565892aa596cf8b1e486) - Fix event target. Thanks [@aliabid94](https://github.com/aliabid94)! + +## 0.8.0 + +### Features + +- [#6307](https://github.com/gradio-app/gradio/pull/6307) [`f1409f95e`](https://github.com/gradio-app/gradio/commit/f1409f95ed39c5565bed6a601e41f94e30196a57) - Provide status updates on file uploads. Thanks [@freddyaboulton](https://github.com/freddyaboulton)! + +## 0.7.2 + +### Fixes + +- [#6327](https://github.com/gradio-app/gradio/pull/6327) [`bca6c2c80`](https://github.com/gradio-app/gradio/commit/bca6c2c80f7e5062427019de45c282238388af95) - Restore query parameters in request. Thanks [@aliabid94](https://github.com/aliabid94)! + +## 0.7.1 + +### Features + +- [#6137](https://github.com/gradio-app/gradio/pull/6137) [`2ba14b284`](https://github.com/gradio-app/gradio/commit/2ba14b284f908aa13859f4337167a157075a68eb) - JS Param. Thanks [@dawoodkhan82](https://github.com/dawoodkhan82)! + +## 0.7.0 + +### Features + +- [#5498](https://github.com/gradio-app/gradio/pull/5498) [`287fe6782`](https://github.com/gradio-app/gradio/commit/287fe6782825479513e79a5cf0ba0fbfe51443d7) - fix circular dependency with client + upload. Thanks [@pngwn](https://github.com/pngwn)! +- [#5498](https://github.com/gradio-app/gradio/pull/5498) [`287fe6782`](https://github.com/gradio-app/gradio/commit/287fe6782825479513e79a5cf0ba0fbfe51443d7) - Image v4. Thanks [@pngwn](https://github.com/pngwn)! +- [#5498](https://github.com/gradio-app/gradio/pull/5498) [`287fe6782`](https://github.com/gradio-app/gradio/commit/287fe6782825479513e79a5cf0ba0fbfe51443d7) - Swap websockets for SSE. Thanks [@pngwn](https://github.com/pngwn)! + +## 0.7.0-beta.1 + +### Features + +- [#6143](https://github.com/gradio-app/gradio/pull/6143) [`e4f7b4b40`](https://github.com/gradio-app/gradio/commit/e4f7b4b409323b01aa01b39e15ce6139e29aa073) - fix circular dependency with client + upload. Thanks [@pngwn](https://github.com/pngwn)! +- [#6094](https://github.com/gradio-app/gradio/pull/6094) [`c476bd5a5`](https://github.com/gradio-app/gradio/commit/c476bd5a5b70836163b9c69bf4bfe068b17fbe13) - Image v4. Thanks [@pngwn](https://github.com/pngwn)! +- [#6069](https://github.com/gradio-app/gradio/pull/6069) [`bf127e124`](https://github.com/gradio-app/gradio/commit/bf127e1241a41401e144874ea468dff8474eb505) - Swap websockets for SSE. Thanks [@aliabid94](https://github.com/aliabid94)! + +## 0.7.0-beta.0 + +### Features + +- [#6016](https://github.com/gradio-app/gradio/pull/6016) [`83e947676`](https://github.com/gradio-app/gradio/commit/83e947676d327ca2ab6ae2a2d710c78961c771a0) - Format js in v4 branch. Thanks [@freddyaboulton](https://github.com/freddyaboulton)! + +### Fixes + +- [#6046](https://github.com/gradio-app/gradio/pull/6046) [`dbb7de5e0`](https://github.com/gradio-app/gradio/commit/dbb7de5e02c53fee05889d696d764d212cb96c74) - fix tests. Thanks [@pngwn](https://github.com/pngwn)! + +## 0.6.0 + +### Features + +- [#5972](https://github.com/gradio-app/gradio/pull/5972) [`11a300791`](https://github.com/gradio-app/gradio/commit/11a3007916071f0791844b0a37f0fb4cec69cea3) - Lite: Support opening the entrypoint HTML page directly in browser via the `file:` protocol. Thanks [@whitphx](https://github.com/whitphx)! + +## 0.5.2 + +### Fixes + +- [#5840](https://github.com/gradio-app/gradio/pull/5840) [`4e62b8493`](https://github.com/gradio-app/gradio/commit/4e62b8493dfce50bafafe49f1a5deb929d822103) - Ensure websocket polyfill doesn't load if there is already a `global.Webocket` property set. Thanks [@Jay2theWhy](https://github.com/Jay2theWhy)! + +## 0.5.1 + +### Fixes + +- [#5816](https://github.com/gradio-app/gradio/pull/5816) [`796145e2c`](https://github.com/gradio-app/gradio/commit/796145e2c48c4087bec17f8ec0be4ceee47170cb) - Fix calls to the component server so that `gr.FileExplorer` works on Spaces. Thanks [@abidlabs](https://github.com/abidlabs)! + +## 0.5.0 + +### Highlights + +#### new `FileExplorer` component ([#5672](https://github.com/gradio-app/gradio/pull/5672) [`e4a307ed6`](https://github.com/gradio-app/gradio/commit/e4a307ed6cde3bbdf4ff2f17655739addeec941e)) + +Thanks to a new capability that allows components to communicate directly with the server _without_ passing data via the value, we have created a new `FileExplorer` component. + +This component allows you to populate the explorer by passing a glob, but only provides the selected file(s) in your prediction function. + +Users can then navigate the virtual filesystem and select files which will be accessible in your predict function. This component will allow developers to build more complex spaces, with more flexible input options. + +![output](https://github.com/pngwn/MDsveX/assets/12937446/ef108f0b-0e84-4292-9984-9dc66b3e144d) + +For more information check the [`FileExplorer` documentation](https://gradio.app/docs/fileexplorer). + + Thanks [@aliabid94](https://github.com/aliabid94)! + +### Features + +- [#5787](https://github.com/gradio-app/gradio/pull/5787) [`caeee8bf7`](https://github.com/gradio-app/gradio/commit/caeee8bf7821fd5fe2f936ed82483bed00f613ec) - ensure the client does not depend on `window` when running in a node environment. Thanks [@gibiee](https://github.com/gibiee)! + +### Fixes + +- [#5776](https://github.com/gradio-app/gradio/pull/5776) [`c0fef4454`](https://github.com/gradio-app/gradio/commit/c0fef44541bfa61568bdcfcdfc7d7d79869ab1df) - Revert replica proxy logic and instead implement using the `root` variable. Thanks [@freddyaboulton](https://github.com/freddyaboulton)! + +## 0.4.2 + +### Features + +- [#5124](https://github.com/gradio-app/gradio/pull/5124) [`6e56a0d9b`](https://github.com/gradio-app/gradio/commit/6e56a0d9b0c863e76c69e1183d9d40196922b4cd) - Lite: Websocket queueing. Thanks [@whitphx](https://github.com/whitphx)! + +## 0.4.1 + +### Fixes + +- [#5705](https://github.com/gradio-app/gradio/pull/5705) [`78e7cf516`](https://github.com/gradio-app/gradio/commit/78e7cf5163e8d205e8999428fce4c02dbdece25f) - ensure internal data has updated before dispatching `success` or `then` events. Thanks [@pngwn](https://github.com/pngwn)! + +## 0.4.0 + +### Features + +- [#5682](https://github.com/gradio-app/gradio/pull/5682) [`c57f1b75e`](https://github.com/gradio-app/gradio/commit/c57f1b75e272c76b0af4d6bd0c7f44743ff34f26) - Fix functional tests. Thanks [@abidlabs](https://github.com/abidlabs)! +- [#5681](https://github.com/gradio-app/gradio/pull/5681) [`40de3d217`](https://github.com/gradio-app/gradio/commit/40de3d2178b61ebe424b6f6228f94c0c6f679bea) - add query parameters to the `gr.Request` object through the `query_params` attribute. Thanks [@DarhkVoyd](https://github.com/DarhkVoyd)! +- [#5653](https://github.com/gradio-app/gradio/pull/5653) [`ea0e00b20`](https://github.com/gradio-app/gradio/commit/ea0e00b207b4b90a10e9d054c4202d4e705a29ba) - Prevent Clients from accessing API endpoints that set `api_name=False`. Thanks [@abidlabs](https://github.com/abidlabs)! + +## 0.3.1 + +### Fixes + +- [#5412](https://github.com/gradio-app/gradio/pull/5412) [`26fef8c7`](https://github.com/gradio-app/gradio/commit/26fef8c7f85a006c7e25cdbed1792df19c512d02) - Skip view_api request in js client when auth enabled. Thanks [@freddyaboulton](https://github.com/freddyaboulton)! + +## 0.3.0 + +### Features + +- [#5267](https://github.com/gradio-app/gradio/pull/5267) [`119c8343`](https://github.com/gradio-app/gradio/commit/119c834331bfae60d4742c8f20e9cdecdd67e8c2) - Faster reload mode. Thanks [@freddyaboulton](https://github.com/freddyaboulton)! + +## 0.2.1 + +### Features + +- [#5173](https://github.com/gradio-app/gradio/pull/5173) [`730f0c1d`](https://github.com/gradio-app/gradio/commit/730f0c1d54792eb11359e40c9f2326e8a6e39203) - Ensure gradio client works as expected for functions that return nothing. Thanks [@raymondtri](https://github.com/raymondtri)! + +## 0.2.0 + +### Features + +- [#5133](https://github.com/gradio-app/gradio/pull/5133) [`61129052`](https://github.com/gradio-app/gradio/commit/61129052ed1391a75c825c891d57fa0ad6c09fc8) - Update dependency esbuild to ^0.19.0. Thanks [@renovate](https://github.com/apps/renovate)! +- [#5035](https://github.com/gradio-app/gradio/pull/5035) [`8b4eb8ca`](https://github.com/gradio-app/gradio/commit/8b4eb8cac9ea07bde31b44e2006ca2b7b5f4de36) - JS Client: Fixes cannot read properties of null (reading 'is_file'). Thanks [@raymondtri](https://github.com/raymondtri)! + +### Fixes + +- [#5075](https://github.com/gradio-app/gradio/pull/5075) [`67265a58`](https://github.com/gradio-app/gradio/commit/67265a58027ef1f9e4c0eb849a532f72eaebde48) - Allow supporting >1000 files in `gr.File()` and `gr.UploadButton()`. Thanks [@abidlabs](https://github.com/abidlabs)! + +## 0.1.4 + +### Patch Changes + +- [#4717](https://github.com/gradio-app/gradio/pull/4717) [`ab5d1ea0`](https://github.com/gradio-app/gradio/commit/ab5d1ea0de87ed888779b66fd2a705583bd29e02) Thanks [@whitphx](https://github.com/whitphx)! - Fix the package description + +## 0.1.3 + +### Patch Changes + +- [#4357](https://github.com/gradio-app/gradio/pull/4357) [`0dbd8f7f`](https://github.com/gradio-app/gradio/commit/0dbd8f7fee4b4877f783fa7bc493f98bbfc3d01d) Thanks [@pngwn](https://github.com/pngwn)! - Various internal refactors and cleanups. + +## 0.1.2 + +### Patch Changes + +- [#4273](https://github.com/gradio-app/gradio/pull/4273) [`1d0f0a9d`](https://github.com/gradio-app/gradio/commit/1d0f0a9db096552e67eb2197c932342587e9e61e) Thanks [@pngwn](https://github.com/pngwn)! - Ensure websocket error messages are correctly handled. + +- [#4315](https://github.com/gradio-app/gradio/pull/4315) [`b525b122`](https://github.com/gradio-app/gradio/commit/b525b122dd8569bbaf7e06db5b90d622d2e9073d) Thanks [@whitphx](https://github.com/whitphx)! - Refacor types. + +- [#4271](https://github.com/gradio-app/gradio/pull/4271) [`1151c525`](https://github.com/gradio-app/gradio/commit/1151c5253554cb87ebd4a44a8a470ac215ff782b) Thanks [@pngwn](https://github.com/pngwn)! - Ensure the full root path is always respected when making requests to a gradio app server. + +## 0.1.1 + +### Patch Changes + +- [#4201](https://github.com/gradio-app/gradio/pull/4201) [`da5b4ee1`](https://github.com/gradio-app/gradio/commit/da5b4ee11721175858ded96e5710225369097f74) Thanks [@pngwn](https://github.com/pngwn)! - Ensure semiver is bundled so CDN links work correctly. + +- [#4202](https://github.com/gradio-app/gradio/pull/4202) [`a26e9afd`](https://github.com/gradio-app/gradio/commit/a26e9afde319382993e6ddc77cc4e56337a31248) Thanks [@pngwn](https://github.com/pngwn)! - Ensure all URLs returned by the client are complete URLs with the correct host instead of an absolute path relative to a server. + +## 0.1.0 + +### Minor Changes + +- [#4185](https://github.com/gradio-app/gradio/pull/4185) [`67239ca9`](https://github.com/gradio-app/gradio/commit/67239ca9b2fe3796853fbf7bf865c9e4b383200d) Thanks [@pngwn](https://github.com/pngwn)! - Update client for initial release + +### Patch Changes + +- [#3692](https://github.com/gradio-app/gradio/pull/3692) [`48e8b113`](https://github.com/gradio-app/gradio/commit/48e8b113f4b55e461d9da4f153bf72aeb4adf0f1) Thanks [@pngwn](https://github.com/pngwn)! - Ensure client works in node, create ESM bundle and generate typescript declaration files. + +- [#3605](https://github.com/gradio-app/gradio/pull/3605) [`ae4277a9`](https://github.com/gradio-app/gradio/commit/ae4277a9a83d49bdadfe523b0739ba988128e73b) Thanks [@pngwn](https://github.com/pngwn)! - Update readme. \ No newline at end of file diff --git a/node_modules/@gradio/client/LICENSE b/node_modules/@gradio/client/LICENSE new file mode 100644 index 0000000000000000000000000000000000000000..261eeb9e9f8b2b4b0d119366dda99c6fd7d35c64 --- /dev/null +++ b/node_modules/@gradio/client/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/node_modules/@gradio/client/README.md b/node_modules/@gradio/client/README.md new file mode 100644 index 0000000000000000000000000000000000000000..0d2acb70f9583f6a0e16267463f7c6e17fa9a1fb --- /dev/null +++ b/node_modules/@gradio/client/README.md @@ -0,0 +1,448 @@ +## JavaScript Client Library + +Interact with Gradio APIs using our JavaScript (and TypeScript) client. + + +## Installation + +The Gradio JavaScript Client is available on npm as `@gradio/client`. You can install it as below: + +```shell +npm i @gradio/client +``` + +Or, you can include it directly in your HTML via the jsDelivr CDN: + +```shell + +``` + +## Usage + +The JavaScript Gradio Client exposes the Client class, `Client`, along with various other utility functions. `Client` is used to initialise and establish a connection to, or duplicate, a Gradio app. + +### `Client` + +The Client function connects to the API of a hosted Gradio space and returns an object that allows you to make calls to that API. + +The simplest example looks like this: + +```ts +import { Client } from "@gradio/client"; + +const app = await Client.connect("user/space-name"); +const result = await app.predict("/predict"); +``` + +This function accepts two arguments: `source` and `options`: + +#### `source` + +This is the url or name of the gradio app whose API you wish to connect to. This parameter is required and should always be a string. For example: + +```ts +Client.connect("user/space-name"); +``` + +#### `options` + +The options object can optionally be passed a second parameter. This object has two properties, `hf_token` and `status_callback`. + +##### `hf_token` + +This should be a Hugging Face personal access token and is required if you wish to make calls to a private gradio api. This option is optional and should be a string starting with `"hf_"`. + +Example: + +```ts +import { Client } from "@gradio/client"; + +const app = await Client.connect("user/space-name", { hf_token: "hf_..." }); +``` + +##### `status_callback` + +This should be a function which will notify you of the status of a space if it is not running. If the gradio API you are connecting to is not awake and running or is not hosted on Hugging Face space then this function will do nothing. + +**Additional context** + +Applications hosted on Hugging Face spaces can be in a number of different states. As spaces are a GitOps tool and will rebuild when new changes are pushed to the repository, they have various building, running and error states. If a space is not 'running' then the function passed as the `status_callback` will notify you of the current state of the space and the status of the space as it changes. Spaces that are building or sleeping can take longer than usual to respond, so you can use this information to give users feedback about the progress of their action. + +```ts +import { Client, type SpaceStatus } from "@gradio/client"; + +const app = await Client.connect("user/space-name", { + // The space_status parameter does not need to be manually annotated, this is just for illustration. + space_status: (space_status: SpaceStatus) => console.log(space_status) +}); +``` + +```ts +interface SpaceStatusNormal { + status: "sleeping" | "running" | "building" | "error" | "stopped"; + detail: + | "SLEEPING" + | "RUNNING" + | "RUNNING_BUILDING" + | "BUILDING" + | "NOT_FOUND"; + load_status: "pending" | "error" | "complete" | "generating"; + message: string; +} + +interface SpaceStatusError { + status: "space_error"; + detail: "NO_APP_FILE" | "CONFIG_ERROR" | "BUILD_ERROR" | "RUNTIME_ERROR"; + load_status: "error"; + message: string; + discussions_enabled: boolean; + +type SpaceStatus = SpaceStatusNormal | SpaceStatusError; +``` + +The gradio client returns an object with a number of methods and properties: + +#### `predict` + +The `predict` method allows you to call an api endpoint and get a prediction result: + +```ts +import { Client } from "@gradio/client"; + +const app = await Client.connect("user/space-name"); +const result = await app.predict("/predict"); +``` + +`predict` accepts two parameters, `endpoint` and `payload`. It returns a promise that resolves to the prediction result. + +##### `endpoint` + +This is the endpoint for an api request and is required. The default endpoint for a `gradio.Interface` is `"/predict"`. Explicitly named endpoints have a custom name. The endpoint names can be found on the "View API" page of a space. + +```ts +import { Client } from "@gradio/client"; + +const app = await Client.connect("user/space-name"); +const result = await app.predict("/predict"); +``` + +##### `payload` + +The `payload` argument is generally required but this depends on the API itself. If the API endpoint depends on values being passed in then the argument is required for the API request to succeed. The data that should be passed in is detailed on the "View API" page of a space, or accessible via the `view_api()` method of the client. + +```ts +import { Client } from "@gradio/client"; + +const app = await Client.connect("user/space-name"); +const result = await app.predict("/predict", { + input: 1, + word_1: "Hello", + word_2: "friends" +}); +``` + +#### `submit` + +The `submit` method provides a more flexible way to call an API endpoint, providing you with status updates about the current progress of the prediction as well as supporting more complex endpoint types. + +```ts +import { Client } from "@gradio/client"; + +const app = await Client.connect("user/space-name"); +const submission = app.submit("/predict", { name: "Chewbacca" }); +``` + +The `submit` method accepts the same [`endpoint`](#endpoint) and [`payload`](#payload) arguments as `predict`. + +The `submit` method does not return a promise and should not be awaited, instead it returns an async iterator with a `cancel` method. + +##### Accessing values + +Iterating the submission allows you to access the events related to the submitted API request. There are two types of events that can be listened for: `"data"` updates and `"status"` updates. By default only the `"data"` event is reported, but you can listen for the `"status"` event by manually passing the events you care about when instantiating the client: + +```ts +import { Client } from "@gradio/client"; + +const app = await Client.connect("user/space-name", { + events: ["data", "status"] +}); +``` + +`"data"` updates are issued when the API computes a value, the callback provided as the second argument will be called when such a value is sent to the client. The shape of the data depends on the way the API itself is constructed. This event may fire more than once if that endpoint supports emmitting new values over time. + +`"status` updates are issued when the status of a request changes. This information allows you to offer feedback to users when the queue position of the request changes, or when the request changes from queued to processing. + +The status payload look like this: + +```ts +interface Status { + queue: boolean; + code?: string; + success?: boolean; + stage: "pending" | "error" | "complete" | "generating"; + size?: number; + position?: number; + eta?: number; + message?: string; + progress_data?: Array<{ + progress: number | null; + index: number | null; + length: number | null; + unit: string | null; + desc: string | null; + }>; + time?: Date; +} +``` + +Usage looks like this: + +```ts +import { Client } from "@gradio/client"; + +const app = await Client.connect("user/space-name"); +const submission = app + .submit("/predict", { name: "Chewbacca" }) + + for await (const msg of submission) { + if (msg.type === "data") { + console.log(msg.data); + } + + if (msg.type === "status") { + console.log(msg); + } + } +``` + + +##### `cancel` + +Certain types of gradio function can run repeatedly and in some cases indefinitely. the `cancel` method will stop such an endpoints and prevent the API from issuing additional updates. + +```ts +import { Client } from "@gradio/client"; + +const app = await Client.connect("user/space-name"); +const submission = app + .submit("/predict", { name: "Chewbacca" }) + + +// later + +submission.cancel(); +``` + +#### `view_api` + +The `view_api` method provides details about the API you are connected to. It returns a JavaScript object of all named endpoints, unnamed endpoints and what values they accept and return. This method does not accept arguments. + +```ts +import { Client } from "@gradio/client"; + +const app = await Client.connect("user/space-name"); +const api_info = await app.view_api(); + +console.log(api_info); +``` + +#### `config` + +The `config` property contains the configuration for the gradio application you are connected to. This object may contain useful meta information about the application. + +```ts +import { Client } from "@gradio/client"; + +const app = await Client.connect("user/space-name"); +console.log(app.config); +``` + +### `duplicate` + +The duplicate function will attempt to duplicate the space that is referenced and return an instance of `client` connected to that space. If the space has already been duplicated then it will not create a new duplicate and will instead connect to the existing duplicated space. The huggingface token that is passed in will dictate the user under which the space is created. + +`duplicate` accepts the same arguments as `client` with the addition of a `private` options property dictating whether the duplicated space should be private or public. A huggingface token is required for duplication to work. + +```ts +import { Client } from "@gradio/client"; + +const app = await Client.duplicate("user/space-name", { + hf_token: "hf_..." +}); +``` + +This function accepts two arguments: `source` and `options`: + +#### `source` + +The space to duplicate and connect to. [See `client`'s `source` parameter](#source). + +#### `options` + +Accepts all options that `client` accepts, except `hf_token` is required. [See `client`'s `options` parameter](#source). + +`duplicate` also accepts one additional `options` property. + +##### `private` + +This is an optional property specific to `duplicate`'s options object and will determine whether the space should be public or private. Spaces duplicated via the `duplicate` method are public by default. + +```ts +import { Client } from "@gradio/client"; + +const app = await Client.duplicate("user/space-name", { + hf_token: "hf_...", + private: true +}); +``` + +##### `timeout` + +This is an optional property specific to `duplicate`'s options object and will set the timeout in minutes before the duplicated space will go to sleep. + +```ts +import { Client } from "@gradio/client"; + +const app = await Client.duplicate("user/space-name", { + hf_token: "hf_...", + private: true, + timeout: 5 +}); +``` + +##### `hardware` + +This is an optional property specific to `duplicate`'s options object and will set the hardware for the duplicated space. By default the hardware used will match that of the original space. If this cannot be obtained it will default to `"cpu-basic"`. For hardware upgrades (beyond the basic CPU tier), you may be required to provide [billing information on Hugging Face](https://huggingface.co/settings/billing). + +Possible hardware options are: + +- `"cpu-basic"` +- `"cpu-upgrade"` +- `"cpu-xl"` +- `"t4-small"` +- `"t4-medium"` +- `"a10g-small"` +- `"a10g-large"` +- `"a10g-largex2"` +- `"a10g-largex4"` +- `"a100-large"` +- `"zero-a10g"` +- `"h100"` +- `"h100x8"` + +```ts +import { Client } from "@gradio/client"; + +const app = await Client.duplicate("user/space-name", { + hf_token: "hf_...", + private: true, + hardware: "a10g-small" +}); +``` + +### `handle_file(file_or_url: File | string | Blob | Buffer)` + +This utility function is used to simplify the process of handling file inputs for the client. + +Gradio APIs expect a special file datastructure that references a location on the server. These files can be manually uploaded but figuring what to do with different file types can be difficult depending on your environment. + +This function will handle files regardless of whether or not they are local files (node only), URLs, Blobs, or Buffers. It will take in a reference and handle it accordingly,uploading the file where appropriate and generating the correct data structure for the client. + +The return value of this function can be used anywhere in the input data where a file is expected: + +```ts +import { handle_file } from "@gradio/client"; + +const app = await Client.connect("user/space-name"); +const result = await app.predict("/predict", { + single: handle_file(file), + flat: [handle_file(url), handle_file(buffer)], + nested: { + image: handle_file(url), + layers: [handle_file(buffer)] + }, + deeply_nested: { + image: handle_file(url), + layers: [{ + layer1: handle_file(buffer), + layer2: handle_file(buffer) + }] + } +}); +``` + +#### filepaths + +`handle_file` can be passed a local filepath which it will upload to the client server and return a reference that the client can understand. + +This only works in a node environment. + +Filepaths are resolved relative to the current working directory, not the location of the file that calls `handle_file`. + +```ts +import { handle_file } from "@gradio/client"; + +// not uploaded yet +const file_ref = handle_file("path/to/file"); + +const app = await Client.connect("user/space-name"); + +// upload happens here +const result = await app.predict("/predict", { + file: file_ref, +}); +``` + +#### URLs + +`handle_file` can be passed a URL which it will convert into a reference that the client can understand. + +```ts +import { handle_file } from "@gradio/client"; + +const url_ref = handle_file("https://example.com/file.png"); + +const app = await Client.connect("user/space-name"); +const result = await app.predict("/predict", { + url: url_ref, +}); +``` + +#### Blobs + +`handle_file` can be passed a Blob which it will upload to the client server and return a reference that the client can understand. + +The upload is not initiated until predict or submit are called. + +```ts +import { handle_file } from "@gradio/client"; + +// not uploaded yet +const blob_ref = handle_file(new Blob(["Hello, world!"])); + +const app = await Client.connect("user/space-name"); + +// upload happens here +const result = await app.predict("/predict", { + blob: blob_ref, +}); +``` + +#### Buffers + +`handle_file` can be passed a Buffer which it will upload to the client server and return a reference that the client can understand. + +```ts +import { handle_file } from "@gradio/client"; +import { readFileSync } from "fs"; + +// not uploaded yet +const buffer_ref = handle_file(readFileSync("file.png")); + +const app = await Client.connect("user/space-name"); + +// upload happens here +const result = await app.predict("/predict", { + buffer: buffer_ref, +}); +``` \ No newline at end of file diff --git a/node_modules/@gradio/client/dist/client.d.ts b/node_modules/@gradio/client/dist/client.d.ts new file mode 100644 index 0000000000000000000000000000000000000000..13f21d90969400e4d94c7166654c0cc8a991d001 --- /dev/null +++ b/node_modules/@gradio/client/dist/client.d.ts @@ -0,0 +1,81 @@ +import type { ApiData, ApiInfo, ClientOptions, Config, DuplicateOptions, EndpointInfo, JsApiData, PredictReturn, SpaceStatus, Status, UploadResponse, SubmitIterable, GradioEvent } from "./types"; +import { FileData } from "./upload"; +export declare class Client { + app_reference: string; + options: ClientOptions; + deep_link: string | null; + config: Config | undefined; + api_prefix: string; + api_info: ApiInfo | undefined; + api_map: Record; + session_hash: string; + jwt: string | false; + last_status: Record; + private cookies; + stream_status: { + open: boolean; + }; + closed: boolean; + pending_stream_messages: Record; + pending_diff_streams: Record; + event_callbacks: Record Promise>; + unclosed_events: Set; + heartbeat_event: EventSource | null; + abort_controller: AbortController | null; + stream_instance: EventSource | null; + current_payload: any; + ws_map: Record; + get_url_config(url?: string | null): Config; + get_page_config(page: string): Config; + fetch(input: RequestInfo | URL, init?: RequestInit): Promise; + stream(url: URL): EventSource; + view_api: () => Promise>; + upload_files: (root_url: string, files: (Blob | File)[], upload_id?: string) => Promise; + upload: (file_data: FileData[], root_url: string, upload_id?: string, max_file_size?: number) => Promise<(FileData | null)[] | null>; + handle_blob: (endpoint: string, data: unknown[], endpoint_info: EndpointInfo) => Promise; + post_data: (url: string, body: unknown, additional_headers?: any) => Promise; + submit: (endpoint: string | number, data: unknown[] | Record | undefined, event_data?: unknown, trigger_id?: number | null, all_events?: boolean) => SubmitIterable; + predict: (endpoint: string | number, data: unknown[] | Record | undefined, event_data?: unknown) => Promise; + open_stream: () => Promise; + private resolve_config; + private resolve_cookies; + constructor(app_reference: string, options?: ClientOptions); + private init; + _resolve_hearbeat(_config: Config): Promise; + static connect(app_reference: string, options?: ClientOptions): Promise; + close(): void; + set_current_payload(payload: any): void; + static duplicate(app_reference: string, options?: DuplicateOptions): Promise; + private _resolve_config; + private config_success; + handle_space_success(status: SpaceStatus): Promise; + component_server(component_id: number, fn_name: string, data: unknown[] | { + binary: boolean; + data: Record; + }): Promise; + set_cookies(raw_cookies: string): void; + private prepare_return_obj; + private connect_ws; + send_ws_message(url: string, data: any): Promise; + close_ws(url: string): Promise; +} +/** + * @deprecated This method will be removed in v1.0. Use `Client.connect()` instead. + * Creates a client instance for interacting with Gradio apps. + * + * @param {string} app_reference - The reference or URL to a Gradio space or app. + * @param {ClientOptions} options - Configuration options for the client. + * @returns {Promise} A promise that resolves to a `Client` instance. + */ +export declare function client(app_reference: string, options?: ClientOptions): Promise; +/** + * @deprecated This method will be removed in v1.0. Use `Client.duplicate()` instead. + * Creates a duplicate of a space and returns a client instance for the duplicated space. + * + * @param {string} app_reference - The reference or URL to a Gradio space or app to duplicate. + * @param {DuplicateOptions} options - Configuration options for the client. + * @returns {Promise} A promise that resolves to a `Client` instance. + */ +export declare function duplicate_space(app_reference: string, options: DuplicateOptions): Promise; +export type ClientInstance = Client; +//# sourceMappingURL=client.d.ts.map \ No newline at end of file diff --git a/node_modules/@gradio/client/dist/client.d.ts.map b/node_modules/@gradio/client/dist/client.d.ts.map new file mode 100644 index 0000000000000000000000000000000000000000..a77be4e216df097dd654c5ffb73e9bc07bf86b69 --- /dev/null +++ b/node_modules/@gradio/client/dist/client.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACX,OAAO,EACP,OAAO,EACP,aAAa,EACb,MAAM,EACN,gBAAgB,EAChB,YAAY,EACZ,SAAS,EACT,aAAa,EACb,WAAW,EACX,MAAM,EACN,cAAc,EAEd,cAAc,EACd,WAAW,EACX,MAAM,SAAS,CAAC;AAGjB,OAAO,EAAU,QAAQ,EAAE,MAAM,UAAU,CAAC;AAuB5C,qBAAa,MAAM;IAClB,aAAa,EAAE,MAAM,CAAC;IACtB,OAAO,EAAE,aAAa,CAAC;IACvB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAQ;IAEhC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC;IAC3B,UAAU,SAAM;IAChB,QAAQ,EAAE,OAAO,CAAC,SAAS,CAAC,GAAG,SAAS,CAAC;IACzC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAM;IACrC,YAAY,EAAE,MAAM,CAA2C;IAC/D,GAAG,EAAE,MAAM,GAAG,KAAK,CAAS;IAC5B,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,OAAO,CAAC,CAAC,CAAM;IAElD,OAAO,CAAC,OAAO,CAAuB;IAGtC,aAAa;;MAAmB;IAChC,MAAM,UAAS;IACf,uBAAuB,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,EAAE,EAAE,CAAC,CAAM;IACtD,oBAAoB,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,EAAE,EAAE,CAAC,CAAM;IACnD,eAAe,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,IAAI,CAAC,EAAE,OAAO,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC,CAAM;IACxE,eAAe,EAAE,GAAG,CAAC,MAAM,CAAC,CAAa;IACzC,eAAe,EAAE,WAAW,GAAG,IAAI,CAAQ;IAC3C,gBAAgB,EAAE,eAAe,GAAG,IAAI,CAAQ;IAChD,eAAe,EAAE,WAAW,GAAG,IAAI,CAAQ;IAC3C,eAAe,EAAE,GAAG,CAAC;IACrB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,SAAS,GAAG,QAAQ,CAAC,CAAM;IAElD,cAAc,CAAC,GAAG,GAAE,MAAM,GAAG,IAAW,GAAG,MAAM;IAkBjD,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM;IAqBrC,KAAK,CAAC,KAAK,EAAE,WAAW,GAAG,GAAG,EAAE,IAAI,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,QAAQ,CAAC;IActE,MAAM,CAAC,GAAG,EAAE,GAAG,GAAG,WAAW;IAsB7B,QAAQ,EAAE,MAAM,OAAO,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC;IAC5C,YAAY,EAAE,CACb,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,CAAC,IAAI,GAAG,IAAI,CAAC,EAAE,EACtB,SAAS,CAAC,EAAE,MAAM,KACd,OAAO,CAAC,cAAc,CAAC,CAAC;IAC7B,MAAM,EAAE,CACP,SAAS,EAAE,QAAQ,EAAE,EACrB,QAAQ,EAAE,MAAM,EAChB,SAAS,CAAC,EAAE,MAAM,EAClB,aAAa,CAAC,EAAE,MAAM,KAClB,OAAO,CAAC,CAAC,QAAQ,GAAG,IAAI,CAAC,EAAE,GAAG,IAAI,CAAC,CAAC;IACzC,WAAW,EAAE,CACZ,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,OAAO,EAAE,EACf,aAAa,EAAE,YAAY,CAAC,OAAO,GAAG,SAAS,CAAC,KAC5C,OAAO,CAAC,OAAO,EAAE,CAAC,CAAC;IACxB,SAAS,EAAE,CACV,GAAG,EAAE,MAAM,EACX,IAAI,EAAE,OAAO,EACb,kBAAkB,CAAC,EAAE,GAAG,KACpB,OAAO,CAAC,OAAO,EAAE,CAAC,CAAC;IACxB,MAAM,EAAE,CACP,QAAQ,EAAE,MAAM,GAAG,MAAM,EACzB,IAAI,EAAE,OAAO,EAAE,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,EACrD,UAAU,CAAC,EAAE,OAAO,EACpB,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,EAC1B,UAAU,CAAC,EAAE,OAAO,KAChB,cAAc,CAAC,WAAW,CAAC,CAAC;IACjC,OAAO,EAAE,CACR,QAAQ,EAAE,MAAM,GAAG,MAAM,EACzB,IAAI,EAAE,OAAO,EAAE,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,EACrD,UAAU,CAAC,EAAE,OAAO,KAChB,OAAO,CAAC,aAAa,CAAC,CAAC;IAC5B,WAAW,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IACjC,OAAO,CAAC,cAAc,CAAoD;IAC1E,OAAO,CAAC,eAAe,CAAsB;gBAE5C,aAAa,EAAE,MAAM,EACrB,OAAO,GAAE,aAAoC;YAyBhC,IAAI;IAqBZ,iBAAiB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;WAsC1C,OAAO,CACnB,aAAa,EAAE,MAAM,EACrB,OAAO,GAAE,aAER,GACC,OAAO,CAAC,MAAM,CAAC;IAMlB,KAAK,IAAI,IAAI;IAKb,mBAAmB,CAAC,OAAO,EAAE,GAAG,GAAG,IAAI;WAI1B,SAAS,CACrB,aAAa,EAAE,MAAM,EACrB,OAAO,GAAE,gBAER,GACC,OAAO,CAAC,MAAM,CAAC;YAIJ,eAAe;YA4Cf,cAAc;IAyBtB,oBAAoB,CAAC,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAgC1D,gBAAgB,CAC5B,YAAY,EAAE,MAAM,EACpB,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,OAAO,EAAE,GAAG;QAAE,MAAM,EAAE,OAAO,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;KAAE,GAC9D,OAAO,CAAC,OAAO,CAAC;IA6EZ,WAAW,CAAC,WAAW,EAAE,MAAM,GAAG,IAAI;IAI7C,OAAO,CAAC,kBAAkB;YAUZ,UAAU;IA+BlB,eAAe,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,GAAG,OAAO,CAAC,IAAI,CAAC;IAatD,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAS1C;AAED;;;;;;;GAOG;AACH,wBAAsB,MAAM,CAC3B,aAAa,EAAE,MAAM,EACrB,OAAO,GAAE,aAER,GACC,OAAO,CAAC,MAAM,CAAC,CAEjB;AAED;;;;;;;GAOG;AACH,wBAAsB,eAAe,CACpC,aAAa,EAAE,MAAM,EACrB,OAAO,EAAE,gBAAgB,GACvB,OAAO,CAAC,MAAM,CAAC,CAEjB;AAED,MAAM,MAAM,cAAc,GAAG,MAAM,CAAC"} \ No newline at end of file diff --git a/node_modules/@gradio/client/dist/constants.d.ts b/node_modules/@gradio/client/dist/constants.d.ts new file mode 100644 index 0000000000000000000000000000000000000000..28149a6e15210ee3f2b274d5fb5f031bb503c4c0 --- /dev/null +++ b/node_modules/@gradio/client/dist/constants.d.ts @@ -0,0 +1,33 @@ +export declare const HOST_URL = "host"; +export declare const API_URL = "predict/"; +export declare const SSE_URL_V0 = "queue/join"; +export declare const SSE_DATA_URL_V0 = "queue/data"; +export declare const SSE_URL = "queue/data"; +export declare const SSE_DATA_URL = "queue/join"; +export declare const UPLOAD_URL = "upload"; +export declare const LOGIN_URL = "login"; +export declare const CONFIG_URL = "config"; +export declare const API_INFO_URL = "info"; +export declare const RUNTIME_URL = "runtime"; +export declare const SLEEPTIME_URL = "sleeptime"; +export declare const HEARTBEAT_URL = "heartbeat"; +export declare const COMPONENT_SERVER_URL = "component_server"; +export declare const RESET_URL = "reset"; +export declare const CANCEL_URL = "cancel"; +export declare const RAW_API_INFO_URL = "info?serialize=False"; +export declare const SPACE_FETCHER_URL = "https://gradio-space-api-fetcher-v2.hf.space/api"; +export declare const SPACE_URL = "https://hf.space/{}"; +export declare const QUEUE_FULL_MSG = "This application is currently busy. Please try again. "; +export declare const BROKEN_CONNECTION_MSG = "Connection errored out. "; +export declare const CONFIG_ERROR_MSG = "Could not resolve app config. "; +export declare const SPACE_STATUS_ERROR_MSG = "Could not get space status. "; +export declare const API_INFO_ERROR_MSG = "Could not get API info. "; +export declare const SPACE_METADATA_ERROR_MSG = "Space metadata could not be loaded. "; +export declare const INVALID_URL_MSG = "Invalid URL. A full URL path is required."; +export declare const UNAUTHORIZED_MSG = "Not authorized to access this space. "; +export declare const INVALID_CREDENTIALS_MSG = "Invalid credentials. Could not login. "; +export declare const MISSING_CREDENTIALS_MSG = "Login credentials are required to access this space."; +export declare const NODEJS_FS_ERROR_MSG = "File system access is only available in Node.js environments"; +export declare const ROOT_URL_ERROR_MSG = "Root URL not found in client config"; +export declare const FILE_PROCESSING_ERROR_MSG = "Error uploading file"; +//# sourceMappingURL=constants.d.ts.map \ No newline at end of file diff --git a/node_modules/@gradio/client/dist/constants.d.ts.map b/node_modules/@gradio/client/dist/constants.d.ts.map new file mode 100644 index 0000000000000000000000000000000000000000..50b614a50b53e34defc24b056ce5f1622f03495a --- /dev/null +++ b/node_modules/@gradio/client/dist/constants.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AACA,eAAO,MAAM,QAAQ,SAAS,CAAC;AAC/B,eAAO,MAAM,OAAO,aAAa,CAAC;AAClC,eAAO,MAAM,UAAU,eAAe,CAAC;AACvC,eAAO,MAAM,eAAe,eAAe,CAAC;AAC5C,eAAO,MAAM,OAAO,eAAe,CAAC;AACpC,eAAO,MAAM,YAAY,eAAe,CAAC;AACzC,eAAO,MAAM,UAAU,WAAW,CAAC;AACnC,eAAO,MAAM,SAAS,UAAU,CAAC;AACjC,eAAO,MAAM,UAAU,WAAW,CAAC;AACnC,eAAO,MAAM,YAAY,SAAS,CAAC;AACnC,eAAO,MAAM,WAAW,YAAY,CAAC;AACrC,eAAO,MAAM,aAAa,cAAc,CAAC;AACzC,eAAO,MAAM,aAAa,cAAc,CAAC;AACzC,eAAO,MAAM,oBAAoB,qBAAqB,CAAC;AACvD,eAAO,MAAM,SAAS,UAAU,CAAC;AACjC,eAAO,MAAM,UAAU,WAAW,CAAC;AAEnC,eAAO,MAAM,gBAAgB,yBAAyB,CAAC;AACvD,eAAO,MAAM,iBAAiB,qDACqB,CAAC;AACpD,eAAO,MAAM,SAAS,wBAAwB,CAAC;AAG/C,eAAO,MAAM,cAAc,2DAC8B,CAAC;AAC1D,eAAO,MAAM,qBAAqB,6BAA6B,CAAC;AAChE,eAAO,MAAM,gBAAgB,mCAAmC,CAAC;AACjE,eAAO,MAAM,sBAAsB,iCAAiC,CAAC;AACrE,eAAO,MAAM,kBAAkB,6BAA6B,CAAC;AAC7D,eAAO,MAAM,wBAAwB,yCAAyC,CAAC;AAC/E,eAAO,MAAM,eAAe,8CAA8C,CAAC;AAC3E,eAAO,MAAM,gBAAgB,0CAA0C,CAAC;AACxE,eAAO,MAAM,uBAAuB,2CAA2C,CAAC;AAChF,eAAO,MAAM,uBAAuB,yDACmB,CAAC;AACxD,eAAO,MAAM,mBAAmB,iEAC+B,CAAC;AAChE,eAAO,MAAM,kBAAkB,wCAAwC,CAAC;AACxE,eAAO,MAAM,yBAAyB,yBAAyB,CAAC"} \ No newline at end of file diff --git a/node_modules/@gradio/client/dist/helpers/api_info.d.ts b/node_modules/@gradio/client/dist/helpers/api_info.d.ts new file mode 100644 index 0000000000000000000000000000000000000000..adcecd5e8dfa2c10d75ca6ba41a2380fb60d6ff4 --- /dev/null +++ b/node_modules/@gradio/client/dist/helpers/api_info.d.ts @@ -0,0 +1,48 @@ +import type { ApiData, ApiInfo, Config, JsApiData, EndpointInfo, Status } from "../types"; +export declare const RE_SPACE_NAME: RegExp; +export declare const RE_SPACE_DOMAIN: RegExp; +export declare function process_endpoint(app_reference: string, hf_token?: `hf_${string}`): Promise<{ + space_id: string | false; + host: string; + ws_protocol: "ws" | "wss"; + http_protocol: "http:" | "https:"; +}>; +export declare const join_urls: (...urls: string[]) => string; +export declare function transform_api_info(api_info: ApiInfo, config: Config, api_map: Record): ApiInfo; +export declare function get_type(type: { + type: any; + description: string; +}, component: string, serializer: string, signature_type: "return" | "parameter"): string | undefined; +export declare function get_description(type: { + type: any; + description: string; +}, serializer: string): string; +export declare function handle_message(data: any, last_status: Status["stage"]): { + type: "hash" | "data" | "update" | "complete" | "generating" | "log" | "none" | "heartbeat" | "streaming" | "unexpected_error"; + data?: any; + status?: Status; + original_msg?: string; +}; +/** + * Maps the provided `data` to the parameters defined by the `/info` endpoint response. + * This allows us to support both positional and keyword arguments passed to the client + * and ensures that all parameters are either directly provided or have default values assigned. + * + * @param {unknown[] | Record} data - The input data for the function, + * which can be either an array of values for positional arguments or an object + * with key-value pairs for keyword arguments. + * @param {JsApiData[]} parameters - Array of parameter descriptions retrieved from the + * `/info` endpoint. + * + * @returns {unknown[]} - Returns an array of resolved data where each element corresponds + * to the expected parameter from the API. The `parameter_default` value is used where + * a value is not provided for a parameter, and optional parameters without defaults are + * set to `undefined`. + * + * @throws {Error} - Throws an error: + * - If more arguments are provided than are defined in the parameters. + * * - If no parameter value is provided for a required parameter and no default value is defined. + * - If an argument is provided that does not match any defined parameter. + */ +export declare const map_data_to_params: (data: Record | unknown[] | undefined, endpoint_info: EndpointInfo) => unknown[]; +//# sourceMappingURL=api_info.d.ts.map \ No newline at end of file diff --git a/node_modules/@gradio/client/dist/helpers/api_info.d.ts.map b/node_modules/@gradio/client/dist/helpers/api_info.d.ts.map new file mode 100644 index 0000000000000000000000000000000000000000..f00882dc7476bf3e18e5ad2e1e3a2bee1d31431b --- /dev/null +++ b/node_modules/@gradio/client/dist/helpers/api_info.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"api_info.d.ts","sourceRoot":"","sources":["../../src/helpers/api_info.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EACX,OAAO,EACP,OAAO,EACP,MAAM,EACN,SAAS,EACT,YAAY,EACZ,MAAM,EACN,MAAM,UAAU,CAAC;AAGlB,eAAO,MAAM,aAAa,QAA2C,CAAC;AACtE,eAAO,MAAM,eAAe,QAA0B,CAAC;AAEvD,wBAAsB,gBAAgB,CACrC,aAAa,EAAE,MAAM,EACrB,QAAQ,CAAC,EAAE,MAAM,MAAM,EAAE,GACvB,OAAO,CAAC;IACV,QAAQ,EAAE,MAAM,GAAG,KAAK,CAAC;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,IAAI,GAAG,KAAK,CAAC;IAC1B,aAAa,EAAE,OAAO,GAAG,QAAQ,CAAC;CAClC,CAAC,CA4CD;AAED,eAAO,MAAM,SAAS,YAAa,MAAM,EAAE,KAAG,MAU7C,CAAC;AAEF,wBAAgB,kBAAkB,CACjC,QAAQ,EAAE,OAAO,CAAC,OAAO,CAAC,EAC1B,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAC7B,OAAO,CAAC,SAAS,CAAC,CAsFpB;AAED,wBAAgB,QAAQ,CACvB,IAAI,EAAE;IAAE,IAAI,EAAE,GAAG,CAAC;IAAC,WAAW,EAAE,MAAM,CAAA;CAAE,EACxC,SAAS,EAAE,MAAM,EACjB,UAAU,EAAE,MAAM,EAClB,cAAc,EAAE,QAAQ,GAAG,WAAW,GACpC,MAAM,GAAG,SAAS,CAkCpB;AAED,wBAAgB,eAAe,CAC9B,IAAI,EAAE;IAAE,IAAI,EAAE,GAAG,CAAC;IAAC,WAAW,EAAE,MAAM,CAAA;CAAE,EACxC,UAAU,EAAE,MAAM,GAChB,MAAM,CASR;AAGD,wBAAgB,cAAc,CAC7B,IAAI,EAAE,GAAG,EACT,WAAW,EAAE,MAAM,CAAC,OAAO,CAAC,GAC1B;IACF,IAAI,EACD,MAAM,GACN,MAAM,GACN,QAAQ,GACR,UAAU,GACV,YAAY,GACZ,KAAK,GACL,MAAM,GACN,WAAW,GACX,WAAW,GACX,kBAAkB,CAAC;IACtB,IAAI,CAAC,EAAE,GAAG,CAAC;IACX,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,YAAY,CAAC,EAAE,MAAM,CAAC;CACtB,CAwIA;AAGD;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,eAAO,MAAM,kBAAkB,yEAEf,aAAa,SAAS,GAAG,OAAO,CAAC,KAC9C,OAAO,EA4CT,CAAC"} \ No newline at end of file diff --git a/node_modules/@gradio/client/dist/helpers/data.d.ts b/node_modules/@gradio/client/dist/helpers/data.d.ts new file mode 100644 index 0000000000000000000000000000000000000000..21650e191082bbb85d3574f70acc5d0e756c37d5 --- /dev/null +++ b/node_modules/@gradio/client/dist/helpers/data.d.ts @@ -0,0 +1,22 @@ +/// +import { type ApiData, type BlobRef, type Config, type EndpointInfo, type JsApiData, type DataType, Command, type Dependency, type ComponentMeta } from "../types"; +import { FileData } from "../upload"; +export declare function update_object(object: { + [x: string]: any; +}, newValue: any, stack: (string | number)[]): void; +export declare function walk_and_store_blobs(data: DataType, type?: string | undefined, path?: string[], root?: boolean, endpoint_info?: EndpointInfo | undefined): Promise; +export declare function skip_queue(id: number, config: Config): boolean; +export declare function post_message(message: any, origin: string): Promise; +export declare function handle_file(file_or_url: File | string | Blob | Buffer): FileData | Blob | Command; +/** + * Handles the payload by filtering out state inputs and returning an array of resolved payload values. + * We send null values for state inputs to the server, but we don't want to include them in the resolved payload. + * + * @param resolved_payload - The resolved payload values received from the client or the server + * @param dependency - The dependency object. + * @param components - The array of component metadata. + * @param with_null_state - Optional. Specifies whether to include null values for state inputs. Default is false. + * @returns An array of resolved payload values, filtered based on the dependency and component metadata. + */ +export declare function handle_payload(resolved_payload: unknown[], dependency: Dependency, components: ComponentMeta[], type: "input" | "output", with_null_state?: boolean): unknown[]; +//# sourceMappingURL=data.d.ts.map \ No newline at end of file diff --git a/node_modules/@gradio/client/dist/helpers/data.d.ts.map b/node_modules/@gradio/client/dist/helpers/data.d.ts.map new file mode 100644 index 0000000000000000000000000000000000000000..8d3d80019b951ec4ea72455c8294dc250252c318 --- /dev/null +++ b/node_modules/@gradio/client/dist/helpers/data.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"data.d.ts","sourceRoot":"","sources":["../../src/helpers/data.ts"],"names":[],"mappings":";AAAA,OAAO,EACN,KAAK,OAAO,EACZ,KAAK,OAAO,EACZ,KAAK,MAAM,EACX,KAAK,YAAY,EACjB,KAAK,SAAS,EACd,KAAK,QAAQ,EACb,OAAO,EACP,KAAK,UAAU,EACf,KAAK,aAAa,EAClB,MAAM,UAAU,CAAC;AAClB,OAAO,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AAKrC,wBAAgB,aAAa,CAC5B,MAAM,EAAE;IAAE,CAAC,CAAC,EAAE,MAAM,GAAG,GAAG,CAAA;CAAE,EAC5B,QAAQ,EAAE,GAAG,EACb,KAAK,EAAE,CAAC,MAAM,GAAG,MAAM,CAAC,EAAE,GACxB,IAAI,CAgBN;AAED,wBAAsB,oBAAoB,CACzC,IAAI,EAAE,QAAQ,EACd,IAAI,GAAE,MAAM,GAAG,SAAqB,EACpC,IAAI,GAAE,MAAM,EAAO,EACnB,IAAI,UAAQ,EACZ,aAAa,GAAE,YAAY,CAAC,OAAO,GAAG,SAAS,CAAC,GAAG,SAAqB,GACtE,OAAO,CAAC,OAAO,EAAE,CAAC,CAwDpB;AAED,wBAAgB,UAAU,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAM9D;AAID,wBAAgB,YAAY,CAAC,GAAG,GAAG,GAAG,EACrC,OAAO,EAAE,GAAG,EACZ,MAAM,EAAE,MAAM,GACZ,OAAO,CAAC,GAAG,CAAC,CASd;AAED,wBAAgB,WAAW,CAC1B,WAAW,EAAE,IAAI,GAAG,MAAM,GAAG,IAAI,GAAG,MAAM,GACxC,QAAQ,GAAG,IAAI,GAAG,OAAO,CAgC3B;AAED;;;;;;;;;GASG;AACH,wBAAgB,cAAc,CAC7B,gBAAgB,EAAE,OAAO,EAAE,EAC3B,UAAU,EAAE,UAAU,EACtB,UAAU,EAAE,aAAa,EAAE,EAC3B,IAAI,EAAE,OAAO,GAAG,QAAQ,EACxB,eAAe,UAAQ,GACrB,OAAO,EAAE,CA0CX"} \ No newline at end of file diff --git a/node_modules/@gradio/client/dist/helpers/init_helpers.d.ts b/node_modules/@gradio/client/dist/helpers/init_helpers.d.ts new file mode 100644 index 0000000000000000000000000000000000000000..01057464325f0a88855cd3e6746e8dd81189c703 --- /dev/null +++ b/node_modules/@gradio/client/dist/helpers/init_helpers.d.ts @@ -0,0 +1,25 @@ +import type { Config } from "../types"; +import { Client } from ".."; +/** + * This function is used to resolve the URL for making requests when the app has a root path. + * The root path could be a path suffix like "/app" which is appended to the end of the base URL. Or + * it could be a full URL like "https://abidlabs-test-client-replica--gqf2x.hf.space" which is used when hosting + * Gradio apps on Hugging Face Spaces. + * @param {string} base_url The base URL at which the Gradio server is hosted + * @param {string} root_path The root path, which could be a path suffix (e.g. mounted in FastAPI app) or a full URL (e.g. hosted on Hugging Face Spaces) + * @param {boolean} prioritize_base Whether to prioritize the base URL over the root path. This is used when both the base path and root paths are full URLs. For example, for fetching files the root path should be prioritized, but for making requests, the base URL should be prioritized. + * @returns {string} the resolved URL + */ +export declare function resolve_root(base_url: string, root_path: string, prioritize_base: boolean): string; +export declare function get_jwt(space: string, token: `hf_${string}`, cookies?: string | null): Promise; +export declare function map_names_to_ids(fns: Config["dependencies"]): Record; +export declare function resolve_config(this: Client, endpoint: string): Promise; +export declare function resolve_cookies(this: Client): Promise; +export declare function get_cookie_header(http_protocol: string, host: string, auth: [string, string], _fetch: typeof fetch, hf_token?: `hf_${string}`): Promise; +export declare function determine_protocol(endpoint: string): { + ws_protocol: "ws" | "wss"; + http_protocol: "http:" | "https:"; + host: string; +}; +export declare const parse_and_set_cookies: (cookie_header: string) => string[]; +//# sourceMappingURL=init_helpers.d.ts.map \ No newline at end of file diff --git a/node_modules/@gradio/client/dist/helpers/init_helpers.d.ts.map b/node_modules/@gradio/client/dist/helpers/init_helpers.d.ts.map new file mode 100644 index 0000000000000000000000000000000000000000..9406886a46efe3f7b6393a2cd9cc73b7dbde2a9d --- /dev/null +++ b/node_modules/@gradio/client/dist/helpers/init_helpers.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"init_helpers.d.ts","sourceRoot":"","sources":["../../src/helpers/init_helpers.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAUvC,OAAO,EAAE,MAAM,EAAE,MAAM,IAAI,CAAC;AAG5B;;;;;;;;;GASG;AACH,wBAAgB,YAAY,CAC3B,QAAQ,EAAE,MAAM,EAChB,SAAS,EAAE,MAAM,EACjB,eAAe,EAAE,OAAO,GACtB,MAAM,CAKR;AAED,wBAAsB,OAAO,CAC5B,KAAK,EAAE,MAAM,EACb,KAAK,EAAE,MAAM,MAAM,EAAE,EACrB,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,GACrB,OAAO,CAAC,MAAM,GAAG,KAAK,CAAC,CAezB;AAED,wBAAgB,gBAAgB,CAC/B,GAAG,EAAE,MAAM,CAAC,cAAc,CAAC,GACzB,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAOxB;AAED,wBAAsB,cAAc,CACnC,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,MAAM,GACd,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAmD7B;AAED,wBAAsB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAqBjE;AAGD,wBAAsB,iBAAiB,CACtC,aAAa,EAAE,MAAM,EACrB,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,EACtB,MAAM,EAAE,OAAO,KAAK,EACpB,QAAQ,CAAC,EAAE,MAAM,MAAM,EAAE,GACvB,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAyBxB;AAED,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,MAAM,GAAG;IACrD,WAAW,EAAE,IAAI,GAAG,KAAK,CAAC;IAC1B,aAAa,EAAE,OAAO,GAAG,QAAQ,CAAC;IAClC,IAAI,EAAE,MAAM,CAAC;CACb,CA0BA;AAED,eAAO,MAAM,qBAAqB,kBAAmB,MAAM,KAAG,MAAM,EAUnE,CAAC"} \ No newline at end of file diff --git a/node_modules/@gradio/client/dist/helpers/spaces.d.ts b/node_modules/@gradio/client/dist/helpers/spaces.d.ts new file mode 100644 index 0000000000000000000000000000000000000000..6e212f2f967aa483ad6addcc4636f8b2e7e94218 --- /dev/null +++ b/node_modules/@gradio/client/dist/helpers/spaces.d.ts @@ -0,0 +1,8 @@ +import type { SpaceStatusCallback } from "../types"; +export declare function check_space_status(id: string, type: "subdomain" | "space_name", status_callback: SpaceStatusCallback): Promise; +export declare const check_and_wake_space: (space_id: string, status_callback: SpaceStatusCallback) => Promise; +export declare function discussions_enabled(space_id: string): Promise; +export declare function get_space_hardware(space_id: string, hf_token?: `hf_${string}` | undefined): Promise<(typeof hardware_types)[number]>; +export declare function set_space_timeout(space_id: string, timeout: number, hf_token?: `hf_${string}`): Promise; +export declare const hardware_types: readonly ["cpu-basic", "cpu-upgrade", "cpu-xl", "t4-small", "t4-medium", "a10g-small", "a10g-large", "a10g-largex2", "a10g-largex4", "a100-large", "zero-a10g", "h100", "h100x8"]; +//# sourceMappingURL=spaces.d.ts.map \ No newline at end of file diff --git a/node_modules/@gradio/client/dist/helpers/spaces.d.ts.map b/node_modules/@gradio/client/dist/helpers/spaces.d.ts.map new file mode 100644 index 0000000000000000000000000000000000000000..c62eef8b023bac952bca0d8702ad24206639239b --- /dev/null +++ b/node_modules/@gradio/client/dist/helpers/spaces.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"spaces.d.ts","sourceRoot":"","sources":["../../src/helpers/spaces.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,UAAU,CAAC;AAEpD,wBAAsB,kBAAkB,CACvC,EAAE,EAAE,MAAM,EACV,IAAI,EAAE,WAAW,GAAG,YAAY,EAChC,eAAe,EAAE,mBAAmB,GAClC,OAAO,CAAC,IAAI,CAAC,CAiGf;AAED,eAAO,MAAM,oBAAoB,aACtB,MAAM,mBACC,mBAAmB,KAClC,QAAQ,IAAI,CAoCd,CAAC;AAIF,wBAAsB,mBAAmB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAgB5E;AAED,wBAAsB,kBAAkB,CACvC,QAAQ,EAAE,MAAM,EAChB,QAAQ,CAAC,EAAE,MAAM,MAAM,EAAE,GAAG,SAAS,GACnC,OAAO,CAAC,CAAC,OAAO,cAAc,CAAC,CAAC,MAAM,CAAC,CAAC,CAqB1C;AAED,wBAAsB,iBAAiB,CACtC,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,MAAM,EACf,QAAQ,CAAC,EAAE,MAAM,MAAM,EAAE,GACvB,OAAO,CAAC,GAAG,CAAC,CAiCd;AAED,eAAO,MAAM,cAAc,mLAcjB,CAAC"} \ No newline at end of file diff --git a/node_modules/@gradio/client/dist/index.d.ts b/node_modules/@gradio/client/dist/index.d.ts new file mode 100644 index 0000000000000000000000000000000000000000..e68456026ae699215f5d329f2be8b8da83af865a --- /dev/null +++ b/node_modules/@gradio/client/dist/index.d.ts @@ -0,0 +1,10 @@ +export { Client } from "./client"; +export { predict } from "./utils/predict"; +export { submit } from "./utils/submit"; +export { upload_files } from "./utils/upload_files"; +export { FileData, upload, prepare_files } from "./upload"; +export { handle_file } from "./helpers/data"; +export type { SpaceStatus, StatusMessage, Status, client_return, UploadResponse, RenderMessage, LogMessage, Payload, Config } from "./types"; +export { client } from "./client"; +export { duplicate_space as duplicate } from "./client"; +//# sourceMappingURL=index.d.ts.map \ No newline at end of file diff --git a/node_modules/@gradio/client/dist/index.d.ts.map b/node_modules/@gradio/client/dist/index.d.ts.map new file mode 100644 index 0000000000000000000000000000000000000000..14c75b1ddb67eaabe0f9d5bf11bf975aad5be624 --- /dev/null +++ b/node_modules/@gradio/client/dist/index.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAElC,OAAO,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAC;AAC1C,OAAO,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAC;AACxC,OAAO,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AACpD,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAC3D,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAE7C,YAAY,EACX,WAAW,EACX,aAAa,EACb,MAAM,EACN,aAAa,EACb,cAAc,EACd,aAAa,EACb,UAAU,EACV,OAAO,EACP,MAAM,EACN,MAAM,SAAS,CAAC;AAGjB,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAClC,OAAO,EAAE,eAAe,IAAI,SAAS,EAAE,MAAM,UAAU,CAAC"} \ No newline at end of file diff --git a/node_modules/@gradio/client/dist/index.js b/node_modules/@gradio/client/dist/index.js new file mode 100644 index 0000000000000000000000000000000000000000..6dcd6f163afa154a25a2e0813a04784a11a14f07 --- /dev/null +++ b/node_modules/@gradio/client/dist/index.js @@ -0,0 +1,2674 @@ +var __defProp = Object.defineProperty; +var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; +var __publicField = (obj, key, value) => { + __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value); + return value; +}; +var __accessCheck = (obj, member, msg) => { + if (!member.has(obj)) + throw TypeError("Cannot " + msg); +}; +var __privateGet = (obj, member, getter) => { + __accessCheck(obj, member, "read from private field"); + return getter ? getter.call(obj) : member.get(obj); +}; +var __privateAdd = (obj, member, value) => { + if (member.has(obj)) + throw TypeError("Cannot add the same private member more than once"); + member instanceof WeakSet ? member.add(obj) : member.set(obj, value); +}; +var __privateSet = (obj, member, value, setter) => { + __accessCheck(obj, member, "write to private field"); + setter ? setter.call(obj, value) : member.set(obj, value); + return value; +}; +var _currentLine; +var fn = new Intl.Collator(0, { numeric: 1 }).compare; +function semiver(a, b, bool) { + a = a.split("."); + b = b.split("."); + return fn(a[0], b[0]) || fn(a[1], b[1]) || (b[2] = b.slice(2).join("."), bool = /[.-]/.test(a[2] = a.slice(2).join(".")), bool == /[.-]/.test(b[2]) ? fn(a[2], b[2]) : bool ? -1 : 1); +} +const HOST_URL = `host`; +const SSE_URL = `queue/data`; +const SSE_DATA_URL = `queue/join`; +const UPLOAD_URL = `upload`; +const LOGIN_URL = `login`; +const CONFIG_URL = `config`; +const API_INFO_URL = `info`; +const RUNTIME_URL = `runtime`; +const SLEEPTIME_URL = `sleeptime`; +const HEARTBEAT_URL = `heartbeat`; +const COMPONENT_SERVER_URL = `component_server`; +const RESET_URL = `reset`; +const CANCEL_URL = `cancel`; +const SPACE_FETCHER_URL = "https://gradio-space-api-fetcher-v2.hf.space/api"; +const QUEUE_FULL_MSG = "This application is currently busy. Please try again. "; +const BROKEN_CONNECTION_MSG = "Connection errored out. "; +const CONFIG_ERROR_MSG = "Could not resolve app config. "; +const SPACE_STATUS_ERROR_MSG = "Could not get space status. "; +const API_INFO_ERROR_MSG = "Could not get API info. "; +const SPACE_METADATA_ERROR_MSG = "Space metadata could not be loaded. "; +const INVALID_URL_MSG = "Invalid URL. A full URL path is required."; +const UNAUTHORIZED_MSG = "Not authorized to access this space. "; +const INVALID_CREDENTIALS_MSG = "Invalid credentials. Could not login. "; +const MISSING_CREDENTIALS_MSG = "Login credentials are required to access this space."; +const NODEJS_FS_ERROR_MSG = "File system access is only available in Node.js environments"; +const ROOT_URL_ERROR_MSG = "Root URL not found in client config"; +const FILE_PROCESSING_ERROR_MSG = "Error uploading file"; +function resolve_root(base_url, root_path, prioritize_base) { + if (root_path.startsWith("http://") || root_path.startsWith("https://")) { + return prioritize_base ? base_url : root_path; + } + return base_url + root_path; +} +async function get_jwt(space, token, cookies) { + try { + const r = await fetch(`https://huggingface.co/api/spaces/${space}/jwt`, { + headers: { + Authorization: `Bearer ${token}`, + ...cookies ? { Cookie: cookies } : {} + } + }); + const jwt = (await r.json()).token; + return jwt || false; + } catch (e) { + return false; + } +} +function map_names_to_ids(fns) { + let apis = {}; + fns.forEach(({ api_name, id }) => { + if (api_name) + apis[api_name] = id; + }); + return apis; +} +async function resolve_config(endpoint) { + var _a; + const headers = this.options.hf_token ? { Authorization: `Bearer ${this.options.hf_token}` } : {}; + headers["Content-Type"] = "application/json"; + if (typeof window !== "undefined" && window.gradio_config && location.origin !== "http://localhost:9876" && !window.gradio_config.dev_mode) { + const path = window.gradio_config.root; + const config = window.gradio_config; + let config_root = resolve_root(endpoint, config.root, false); + config.root = config_root; + return { ...config, path }; + } else if (endpoint) { + let config_url = join_urls( + endpoint, + this.deep_link ? CONFIG_URL + "?deep_link=" + this.deep_link : CONFIG_URL + ); + const response = await this.fetch(config_url, { + headers, + credentials: "include" + }); + if ((response == null ? void 0 : response.status) === 401 && !this.options.auth) { + throw new Error(MISSING_CREDENTIALS_MSG); + } else if ((response == null ? void 0 : response.status) === 401 && this.options.auth) { + throw new Error(INVALID_CREDENTIALS_MSG); + } + if ((response == null ? void 0 : response.status) === 200) { + let config = await response.json(); + config.path = config.path ?? ""; + config.root = endpoint; + (_a = config.dependencies) == null ? void 0 : _a.forEach((dep, i) => { + if (dep.id === void 0) { + dep.id = i; + } + }); + return config; + } else if ((response == null ? void 0 : response.status) === 401) { + throw new Error(UNAUTHORIZED_MSG); + } + throw new Error(CONFIG_ERROR_MSG); + } + throw new Error(CONFIG_ERROR_MSG); +} +async function resolve_cookies() { + const { http_protocol, host } = await process_endpoint( + this.app_reference, + this.options.hf_token + ); + try { + if (this.options.auth) { + const cookie_header = await get_cookie_header( + http_protocol, + host, + this.options.auth, + this.fetch, + this.options.hf_token + ); + if (cookie_header) + this.set_cookies(cookie_header); + } + } catch (e) { + throw Error(e.message); + } +} +async function get_cookie_header(http_protocol, host, auth, _fetch, hf_token) { + const formData = new FormData(); + formData.append("username", auth == null ? void 0 : auth[0]); + formData.append("password", auth == null ? void 0 : auth[1]); + let headers = {}; + if (hf_token) { + headers.Authorization = `Bearer ${hf_token}`; + } + const res = await _fetch(`${http_protocol}//${host}/${LOGIN_URL}`, { + headers, + method: "POST", + body: formData, + credentials: "include" + }); + if (res.status === 200) { + return res.headers.get("set-cookie"); + } else if (res.status === 401) { + throw new Error(INVALID_CREDENTIALS_MSG); + } else { + throw new Error(SPACE_METADATA_ERROR_MSG); + } +} +function determine_protocol(endpoint) { + if (endpoint.startsWith("http")) { + const { protocol, host, pathname } = new URL(endpoint); + return { + ws_protocol: protocol === "https:" ? "wss" : "ws", + http_protocol: protocol, + host: host + (pathname !== "/" ? pathname : "") + }; + } else if (endpoint.startsWith("file:")) { + return { + ws_protocol: "ws", + http_protocol: "http:", + host: "lite.local" + // Special fake hostname only used for this case. This matches the hostname allowed in `is_self_host()` in `js/wasm/network/host.ts`. + }; + } + return { + ws_protocol: "wss", + http_protocol: "https:", + host: new URL(endpoint).host + }; +} +const parse_and_set_cookies = (cookie_header) => { + let cookies = []; + const parts = cookie_header.split(/,(?=\s*[^\s=;]+=[^\s=;]+)/); + parts.forEach((cookie) => { + const [cookie_name, cookie_value] = cookie.split(";")[0].split("="); + if (cookie_name && cookie_value) { + cookies.push(`${cookie_name.trim()}=${cookie_value.trim()}`); + } + }); + return cookies; +}; +const RE_SPACE_NAME = /^[a-zA-Z0-9_\-\.]+\/[a-zA-Z0-9_\-\.]+$/; +const RE_SPACE_DOMAIN = /.*hf\.space\/{0,1}.*$/; +async function process_endpoint(app_reference, hf_token) { + const headers = {}; + if (hf_token) { + headers.Authorization = `Bearer ${hf_token}`; + } + const _app_reference = app_reference.trim().replace(/\/$/, ""); + if (RE_SPACE_NAME.test(_app_reference)) { + try { + const res = await fetch( + `https://huggingface.co/api/spaces/${_app_reference}/${HOST_URL}`, + { headers } + ); + const _host = (await res.json()).host; + return { + space_id: app_reference, + ...determine_protocol(_host) + }; + } catch (e) { + throw new Error(SPACE_METADATA_ERROR_MSG); + } + } + if (RE_SPACE_DOMAIN.test(_app_reference)) { + const { ws_protocol, http_protocol, host } = determine_protocol(_app_reference); + return { + space_id: host.split("/")[0].replace(".hf.space", ""), + ws_protocol, + http_protocol, + host + }; + } + return { + space_id: false, + ...determine_protocol(_app_reference) + }; +} +const join_urls = (...urls) => { + try { + return urls.reduce((base_url, part) => { + base_url = base_url.replace(/\/+$/, ""); + part = part.replace(/^\/+/, ""); + return new URL(part, base_url + "/").toString(); + }); + } catch (e) { + throw new Error(INVALID_URL_MSG); + } +}; +function transform_api_info(api_info, config, api_map) { + const transformed_info = { + named_endpoints: {}, + unnamed_endpoints: {} + }; + Object.keys(api_info).forEach((category) => { + if (category === "named_endpoints" || category === "unnamed_endpoints") { + transformed_info[category] = {}; + Object.entries(api_info[category]).forEach( + ([endpoint, { parameters, returns }]) => { + var _a, _b, _c, _d; + const dependencyIndex = ((_a = config.dependencies.find( + (dep) => dep.api_name === endpoint || dep.api_name === endpoint.replace("/", "") + )) == null ? void 0 : _a.id) || api_map[endpoint.replace("/", "")] || -1; + const dependencyTypes = dependencyIndex !== -1 ? (_b = config.dependencies.find((dep) => dep.id == dependencyIndex)) == null ? void 0 : _b.types : { generator: false, cancel: false }; + if (dependencyIndex !== -1 && ((_d = (_c = config.dependencies.find((dep) => dep.id == dependencyIndex)) == null ? void 0 : _c.inputs) == null ? void 0 : _d.length) !== parameters.length) { + const components = config.dependencies.find((dep) => dep.id == dependencyIndex).inputs.map( + (input) => { + var _a2; + return (_a2 = config.components.find((c) => c.id === input)) == null ? void 0 : _a2.type; + } + ); + try { + components.forEach((comp, idx) => { + if (comp === "state") { + const new_param = { + component: "state", + example: null, + parameter_default: null, + parameter_has_default: true, + parameter_name: null, + hidden: true + }; + parameters.splice(idx, 0, new_param); + } + }); + } catch (e) { + console.error(e); + } + } + const transform_type = (data, component, serializer, signature_type) => ({ + ...data, + description: get_description(data == null ? void 0 : data.type, serializer), + type: get_type(data == null ? void 0 : data.type, component, serializer, signature_type) || "" + }); + transformed_info[category][endpoint] = { + parameters: parameters.map( + (p) => transform_type(p, p == null ? void 0 : p.component, p == null ? void 0 : p.serializer, "parameter") + ), + returns: returns.map( + (r) => transform_type(r, r == null ? void 0 : r.component, r == null ? void 0 : r.serializer, "return") + ), + type: dependencyTypes + }; + } + ); + } + }); + return transformed_info; +} +function get_type(type, component, serializer, signature_type) { + if (component === "Api") + return type.type; + switch (type == null ? void 0 : type.type) { + case "string": + return "string"; + case "boolean": + return "boolean"; + case "number": + return "number"; + } + if (serializer === "JSONSerializable" || serializer === "StringSerializable") { + return "any"; + } else if (serializer === "ListStringSerializable") { + return "string[]"; + } else if (component === "Image") { + return signature_type === "parameter" ? "Blob | File | Buffer" : "string"; + } else if (serializer === "FileSerializable") { + if ((type == null ? void 0 : type.type) === "array") { + return signature_type === "parameter" ? "(Blob | File | Buffer)[]" : `{ name: string; data: string; size?: number; is_file?: boolean; orig_name?: string}[]`; + } + return signature_type === "parameter" ? "Blob | File | Buffer" : `{ name: string; data: string; size?: number; is_file?: boolean; orig_name?: string}`; + } else if (serializer === "GallerySerializable") { + return signature_type === "parameter" ? "[(Blob | File | Buffer), (string | null)][]" : `[{ name: string; data: string; size?: number; is_file?: boolean; orig_name?: string}, (string | null))][]`; + } +} +function get_description(type, serializer) { + if (serializer === "GallerySerializable") { + return "array of [file, label] tuples"; + } else if (serializer === "ListStringSerializable") { + return "array of strings"; + } else if (serializer === "FileSerializable") { + return "array of files or single file"; + } + return type == null ? void 0 : type.description; +} +function handle_message(data, last_status) { + const queue = true; + switch (data.msg) { + case "send_data": + return { type: "data" }; + case "send_hash": + return { type: "hash" }; + case "queue_full": + return { + type: "update", + status: { + queue, + message: QUEUE_FULL_MSG, + stage: "error", + code: data.code, + success: data.success + } + }; + case "heartbeat": + return { + type: "heartbeat" + }; + case "unexpected_error": + return { + type: "unexpected_error", + status: { + queue, + message: data.message, + stage: "error", + success: false + } + }; + case "estimation": + return { + type: "update", + status: { + queue, + stage: last_status || "pending", + code: data.code, + size: data.queue_size, + position: data.rank, + eta: data.rank_eta, + success: data.success + } + }; + case "progress": + return { + type: "update", + status: { + queue, + stage: "pending", + code: data.code, + progress_data: data.progress_data, + success: data.success + } + }; + case "log": + return { type: "log", data }; + case "process_generating": + return { + type: "generating", + status: { + queue, + message: !data.success ? data.output.error : null, + stage: data.success ? "generating" : "error", + code: data.code, + progress_data: data.progress_data, + eta: data.average_duration, + changed_state_ids: data.success ? data.output.changed_state_ids : void 0 + }, + data: data.success ? data.output : null + }; + case "process_streaming": + return { + type: "streaming", + status: { + queue, + message: data.output.error, + stage: "streaming", + time_limit: data.time_limit, + code: data.code, + progress_data: data.progress_data, + eta: data.eta + }, + data: data.output + }; + case "process_completed": + if ("error" in data.output) { + return { + type: "update", + status: { + queue, + title: data.output.title, + message: data.output.error, + visible: data.output.visible, + duration: data.output.duration, + stage: "error", + code: data.code, + success: data.success + } + }; + } + return { + type: "complete", + status: { + queue, + message: !data.success ? data.output.error : void 0, + stage: data.success ? "complete" : "error", + code: data.code, + progress_data: data.progress_data, + changed_state_ids: data.success ? data.output.changed_state_ids : void 0 + }, + data: data.success ? data.output : null + }; + case "process_starts": + return { + type: "update", + status: { + queue, + stage: "pending", + code: data.code, + size: data.rank, + position: 0, + success: data.success, + eta: data.eta + }, + original_msg: "process_starts" + }; + } + return { type: "none", status: { stage: "error", queue } }; +} +const map_data_to_params = (data = [], endpoint_info) => { + const parameters = endpoint_info ? endpoint_info.parameters : []; + if (Array.isArray(data)) { + if (data.length > parameters.length) { + console.warn("Too many arguments provided for the endpoint."); + } + return data; + } + const resolved_data = []; + const provided_keys = Object.keys(data); + parameters.forEach((param, index) => { + if (data.hasOwnProperty(param.parameter_name)) { + resolved_data[index] = data[param.parameter_name]; + } else if (param.parameter_has_default) { + resolved_data[index] = param.parameter_default; + } else { + throw new Error( + `No value provided for required parameter: ${param.parameter_name}` + ); + } + }); + provided_keys.forEach((key) => { + if (!parameters.some((param) => param.parameter_name === key)) { + throw new Error( + `Parameter \`${key}\` is not a valid keyword argument. Please refer to the API for usage.` + ); + } + }); + resolved_data.forEach((value, idx) => { + if (value === void 0 && !parameters[idx].parameter_has_default) { + throw new Error( + `No value provided for required parameter: ${parameters[idx].parameter_name}` + ); + } + }); + return resolved_data; +}; +async function view_api() { + if (this.api_info) + return this.api_info; + const { hf_token } = this.options; + const { config } = this; + const headers = { "Content-Type": "application/json" }; + if (hf_token) { + headers.Authorization = `Bearer ${hf_token}`; + } + if (!config) { + return; + } + try { + let response; + let api_info; + if (typeof window !== "undefined" && window.gradio_api_info) { + api_info = window.gradio_api_info; + } else { + if (semiver((config == null ? void 0 : config.version) || "2.0.0", "3.30") < 0) { + response = await this.fetch(SPACE_FETCHER_URL, { + method: "POST", + body: JSON.stringify({ + serialize: false, + config: JSON.stringify(config) + }), + headers, + credentials: "include" + }); + } else { + const url = join_urls(config.root, this.api_prefix, API_INFO_URL); + response = await this.fetch(url, { + headers, + credentials: "include" + }); + } + if (!response.ok) { + throw new Error(BROKEN_CONNECTION_MSG); + } + api_info = await response.json(); + } + if ("api" in api_info) { + api_info = api_info.api; + } + if (api_info.named_endpoints["/predict"] && !api_info.unnamed_endpoints["0"]) { + api_info.unnamed_endpoints[0] = api_info.named_endpoints["/predict"]; + } + return transform_api_info(api_info, config, this.api_map); + } catch (e) { + throw new Error("Could not get API info. " + e.message); + } +} +async function upload_files(root_url, files, upload_id) { + var _a; + const headers = {}; + if ((_a = this == null ? void 0 : this.options) == null ? void 0 : _a.hf_token) { + headers.Authorization = `Bearer ${this.options.hf_token}`; + } + const chunkSize = 1e3; + const uploadResponses = []; + let response; + for (let i = 0; i < files.length; i += chunkSize) { + const chunk = files.slice(i, i + chunkSize); + const formData = new FormData(); + chunk.forEach((file) => { + formData.append("files", file); + }); + try { + const upload_url = upload_id ? `${root_url}${this.api_prefix}/${UPLOAD_URL}?upload_id=${upload_id}` : `${root_url}${this.api_prefix}/${UPLOAD_URL}`; + response = await this.fetch(upload_url, { + method: "POST", + body: formData, + headers, + credentials: "include" + }); + } catch (e) { + throw new Error(BROKEN_CONNECTION_MSG + e.message); + } + if (!response.ok) { + const error_text = await response.text(); + return { error: `HTTP ${response.status}: ${error_text}` }; + } + const output = await response.json(); + if (output) { + uploadResponses.push(...output); + } + } + return { files: uploadResponses }; +} +async function upload(file_data, root_url, upload_id, max_file_size) { + let files = (Array.isArray(file_data) ? file_data : [file_data]).map( + (file_data2) => file_data2.blob + ); + const oversized_files = files.filter( + (f) => f.size > (max_file_size ?? Infinity) + ); + if (oversized_files.length) { + throw new Error( + `File size exceeds the maximum allowed size of ${max_file_size} bytes: ${oversized_files.map((f) => f.name).join(", ")}` + ); + } + return await Promise.all( + await this.upload_files(root_url, files, upload_id).then( + async (response) => { + if (response.error) { + throw new Error(response.error); + } else { + if (response.files) { + return response.files.map((f, i) => { + const file = new FileData({ + ...file_data[i], + path: f, + url: `${root_url}${this.api_prefix}/file=${f}` + }); + return file; + }); + } + return []; + } + } + ) + ); +} +async function prepare_files(files, is_stream) { + return files.map( + (f) => new FileData({ + path: f.name, + orig_name: f.name, + blob: f, + size: f.size, + mime_type: f.type, + is_stream + }) + ); +} +class FileData { + constructor({ + path, + url, + orig_name, + size, + blob, + is_stream, + mime_type, + alt_text, + b64 + }) { + __publicField(this, "path"); + __publicField(this, "url"); + __publicField(this, "orig_name"); + __publicField(this, "size"); + __publicField(this, "blob"); + __publicField(this, "is_stream"); + __publicField(this, "mime_type"); + __publicField(this, "alt_text"); + __publicField(this, "b64"); + __publicField(this, "meta", { _type: "gradio.FileData" }); + this.path = path; + this.url = url; + this.orig_name = orig_name; + this.size = size; + this.blob = url ? void 0 : blob; + this.is_stream = is_stream; + this.mime_type = mime_type; + this.alt_text = alt_text; + this.b64 = b64; + } +} +class Command { + constructor(command, meta) { + __publicField(this, "type"); + __publicField(this, "command"); + __publicField(this, "meta"); + __publicField(this, "fileData"); + this.type = "command"; + this.command = command; + this.meta = meta; + } +} +const is_node = typeof process !== "undefined" && process.versions && process.versions.node; +function update_object(object, newValue, stack) { + while (stack.length > 1) { + const key2 = stack.shift(); + if (typeof key2 === "string" || typeof key2 === "number") { + object = object[key2]; + } else { + throw new Error("Invalid key type"); + } + } + const key = stack.shift(); + if (typeof key === "string" || typeof key === "number") { + object[key] = newValue; + } else { + throw new Error("Invalid key type"); + } +} +async function walk_and_store_blobs(data, type = void 0, path = [], root = false, endpoint_info = void 0) { + if (Array.isArray(data)) { + let blob_refs = []; + await Promise.all( + data.map(async (_, index) => { + var _a; + let new_path = path.slice(); + new_path.push(String(index)); + const array_refs = await walk_and_store_blobs( + data[index], + root ? ((_a = endpoint_info == null ? void 0 : endpoint_info.parameters[index]) == null ? void 0 : _a.component) || void 0 : type, + new_path, + false, + endpoint_info + ); + blob_refs = blob_refs.concat(array_refs); + }) + ); + return blob_refs; + } else if (globalThis.Buffer && data instanceof globalThis.Buffer || data instanceof Blob) { + return [ + { + path, + blob: new Blob([data]), + type + } + ]; + } else if (typeof data === "object" && data !== null) { + let blob_refs = []; + for (const key of Object.keys(data)) { + const new_path = [...path, key]; + const value = data[key]; + blob_refs = blob_refs.concat( + await walk_and_store_blobs( + value, + void 0, + new_path, + false, + endpoint_info + ) + ); + } + return blob_refs; + } + return []; +} +function skip_queue(id, config) { + var _a, _b; + let fn_queue = (_b = (_a = config == null ? void 0 : config.dependencies) == null ? void 0 : _a.find((dep) => dep.id == id)) == null ? void 0 : _b.queue; + if (fn_queue != null) { + return !fn_queue; + } + return !config.enable_queue; +} +function post_message(message, origin) { + return new Promise((res, _rej) => { + const channel = new MessageChannel(); + channel.port1.onmessage = ({ data }) => { + channel.port1.close(); + res(data); + }; + window.parent.postMessage(message, origin, [channel.port2]); + }); +} +function handle_file(file_or_url) { + if (typeof file_or_url === "string") { + if (file_or_url.startsWith("http://") || file_or_url.startsWith("https://")) { + return { + path: file_or_url, + url: file_or_url, + orig_name: file_or_url.split("/").pop() ?? "unknown", + meta: { _type: "gradio.FileData" } + }; + } + if (is_node) { + return new Command("upload_file", { + path: file_or_url, + name: file_or_url, + orig_path: file_or_url + }); + } + } else if (typeof File !== "undefined" && file_or_url instanceof File) { + return new Blob([file_or_url]); + } else if (file_or_url instanceof Buffer) { + return new Blob([file_or_url]); + } else if (file_or_url instanceof Blob) { + return file_or_url; + } + throw new Error( + "Invalid input: must be a URL, File, Blob, or Buffer object." + ); +} +function handle_payload(resolved_payload, dependency, components, type, with_null_state = false) { + if (type === "input" && !with_null_state) { + throw new Error("Invalid code path. Cannot skip state inputs for input."); + } + if (type === "output" && with_null_state) { + return resolved_payload; + } + let updated_payload = []; + let payload_index = 0; + const deps = type === "input" ? dependency.inputs : dependency.outputs; + for (let i = 0; i < deps.length; i++) { + const input_id = deps[i]; + const component = components.find((c) => c.id === input_id); + if ((component == null ? void 0 : component.type) === "state") { + if (with_null_state) { + if (resolved_payload.length === deps.length) { + const value = resolved_payload[payload_index]; + updated_payload.push(value); + payload_index++; + } else { + updated_payload.push(null); + } + } else { + payload_index++; + continue; + } + continue; + } else { + const value = resolved_payload[payload_index]; + updated_payload.push(value); + payload_index++; + } + } + return updated_payload; +} +async function handle_blob(endpoint, data, api_info) { + const self = this; + await process_local_file_commands(self, data); + const blobRefs = await walk_and_store_blobs( + data, + void 0, + [], + true, + api_info + ); + const results = await Promise.all( + blobRefs.map(async ({ path, blob, type }) => { + if (!blob) + return { path, type }; + const response = await self.upload_files(endpoint, [blob]); + const file_url = response.files && response.files[0]; + return { + path, + file_url, + type, + name: typeof File !== "undefined" && blob instanceof File ? blob == null ? void 0 : blob.name : void 0 + }; + }) + ); + results.forEach(({ path, file_url, type, name }) => { + if (type === "Gallery") { + update_object(data, file_url, path); + } else if (file_url) { + const file = new FileData({ path: file_url, orig_name: name }); + update_object(data, file, path); + } + }); + return data; +} +async function process_local_file_commands(client2, data) { + var _a, _b; + const root = ((_a = client2.config) == null ? void 0 : _a.root) || ((_b = client2.config) == null ? void 0 : _b.root_url); + if (!root) { + throw new Error(ROOT_URL_ERROR_MSG); + } + await recursively_process_commands(client2, data); +} +async function recursively_process_commands(client2, data, path = []) { + for (const key in data) { + if (data[key] instanceof Command) { + await process_single_command(client2, data, key); + } else if (typeof data[key] === "object" && data[key] !== null) { + await recursively_process_commands(client2, data[key], [...path, key]); + } + } +} +async function process_single_command(client2, data, key) { + var _a, _b; + let cmd_item = data[key]; + const root = ((_a = client2.config) == null ? void 0 : _a.root) || ((_b = client2.config) == null ? void 0 : _b.root_url); + if (!root) { + throw new Error(ROOT_URL_ERROR_MSG); + } + try { + let fileBuffer; + let fullPath; + if (typeof process !== "undefined" && process.versions && process.versions.node) { + const fs = await import("fs/promises"); + const path = await import("path"); + fullPath = path.resolve(process.cwd(), cmd_item.meta.path); + fileBuffer = await fs.readFile(fullPath); + } else { + throw new Error(NODEJS_FS_ERROR_MSG); + } + const file = new Blob([fileBuffer], { type: "application/octet-stream" }); + const response = await client2.upload_files(root, [file]); + const file_url = response.files && response.files[0]; + if (file_url) { + const fileData = new FileData({ + path: file_url, + orig_name: cmd_item.meta.name || "" + }); + data[key] = fileData; + } + } catch (error) { + console.error(FILE_PROCESSING_ERROR_MSG, error); + } +} +async function post_data(url, body, additional_headers) { + const headers = { "Content-Type": "application/json" }; + if (this.options.hf_token) { + headers.Authorization = `Bearer ${this.options.hf_token}`; + } + try { + var response = await this.fetch(url, { + method: "POST", + body: JSON.stringify(body), + headers: { ...headers, ...additional_headers }, + credentials: "include" + }); + } catch (e) { + return [{ error: BROKEN_CONNECTION_MSG }, 500]; + } + let output; + let status; + try { + output = await response.json(); + status = response.status; + } catch (e) { + output = { error: `Could not parse server response: ${e}` }; + status = 500; + } + return [output, status]; +} +async function predict(endpoint, data = {}) { + let data_returned = false; + let status_complete = false; + if (!this.config) { + throw new Error("Could not resolve app config"); + } + if (typeof endpoint === "number") { + this.config.dependencies.find((dep) => dep.id == endpoint); + } else { + const trimmed_endpoint = endpoint.replace(/^\//, ""); + this.config.dependencies.find( + (dep) => dep.id == this.api_map[trimmed_endpoint] + ); + } + return new Promise(async (resolve, reject) => { + const app = this.submit(endpoint, data, null, null, true); + let result; + for await (const message of app) { + if (message.type === "data") { + if (status_complete) { + resolve(result); + } + data_returned = true; + result = message; + } + if (message.type === "status") { + if (message.stage === "error") + reject(message); + if (message.stage === "complete") { + status_complete = true; + if (data_returned) { + resolve(result); + } + } + } + } + }); +} +async function check_space_status(id, type, status_callback) { + let endpoint = type === "subdomain" ? `https://huggingface.co/api/spaces/by-subdomain/${id}` : `https://huggingface.co/api/spaces/${id}`; + let response; + let _status; + try { + response = await fetch(endpoint); + _status = response.status; + if (_status !== 200) { + throw new Error(); + } + response = await response.json(); + } catch (e) { + status_callback({ + status: "error", + load_status: "error", + message: SPACE_STATUS_ERROR_MSG, + detail: "NOT_FOUND" + }); + return; + } + if (!response || _status !== 200) + return; + const { + runtime: { stage }, + id: space_name + } = response; + switch (stage) { + case "STOPPED": + case "SLEEPING": + status_callback({ + status: "sleeping", + load_status: "pending", + message: "Space is asleep. Waking it up...", + detail: stage + }); + setTimeout(() => { + check_space_status(id, type, status_callback); + }, 1e3); + break; + case "PAUSED": + status_callback({ + status: "paused", + load_status: "error", + message: "This space has been paused by the author. If you would like to try this demo, consider duplicating the space.", + detail: stage, + discussions_enabled: await discussions_enabled(space_name) + }); + break; + case "RUNNING": + case "RUNNING_BUILDING": + status_callback({ + status: "running", + load_status: "complete", + message: "Space is running.", + detail: stage + }); + break; + case "BUILDING": + status_callback({ + status: "building", + load_status: "pending", + message: "Space is building...", + detail: stage + }); + setTimeout(() => { + check_space_status(id, type, status_callback); + }, 1e3); + break; + case "APP_STARTING": + status_callback({ + status: "starting", + load_status: "pending", + message: "Space is starting...", + detail: stage + }); + setTimeout(() => { + check_space_status(id, type, status_callback); + }, 1e3); + break; + default: + status_callback({ + status: "space_error", + load_status: "error", + message: "This space is experiencing an issue.", + detail: stage, + discussions_enabled: await discussions_enabled(space_name) + }); + break; + } +} +const check_and_wake_space = async (space_id, status_callback) => { + let retries = 0; + const max_retries = 12; + const check_interval = 5e3; + return new Promise((resolve) => { + check_space_status( + space_id, + RE_SPACE_NAME.test(space_id) ? "space_name" : "subdomain", + (status) => { + status_callback(status); + if (status.status === "running") { + resolve(); + } else if (status.status === "error" || status.status === "paused" || status.status === "space_error") { + resolve(); + } else if (status.status === "sleeping" || status.status === "building") { + if (retries < max_retries) { + retries++; + setTimeout(() => { + check_and_wake_space(space_id, status_callback).then(resolve); + }, check_interval); + } else { + resolve(); + } + } + } + ); + }); +}; +const RE_DISABLED_DISCUSSION = /^(?=[^]*\b[dD]iscussions{0,1}\b)(?=[^]*\b[dD]isabled\b)[^]*$/; +async function discussions_enabled(space_id) { + try { + const r = await fetch( + `https://huggingface.co/api/spaces/${space_id}/discussions`, + { + method: "HEAD" + } + ); + const error = r.headers.get("x-error-message"); + if (!r.ok || error && RE_DISABLED_DISCUSSION.test(error)) + return false; + return true; + } catch (e) { + return false; + } +} +async function get_space_hardware(space_id, hf_token) { + const headers = {}; + if (hf_token) { + headers.Authorization = `Bearer ${hf_token}`; + } + try { + const res = await fetch( + `https://huggingface.co/api/spaces/${space_id}/${RUNTIME_URL}`, + { headers } + ); + if (res.status !== 200) + throw new Error("Space hardware could not be obtained."); + const { hardware } = await res.json(); + return hardware.current; + } catch (e) { + throw new Error(e.message); + } +} +async function set_space_timeout(space_id, timeout, hf_token) { + const headers = {}; + if (hf_token) { + headers.Authorization = `Bearer ${hf_token}`; + } + const body = { + seconds: timeout + }; + try { + const res = await fetch( + `https://huggingface.co/api/spaces/${space_id}/${SLEEPTIME_URL}`, + { + method: "POST", + headers: { "Content-Type": "application/json", ...headers }, + body: JSON.stringify(body) + } + ); + if (res.status !== 200) { + throw new Error( + "Could not set sleep timeout on duplicated Space. Please visit *ADD HF LINK TO SETTINGS* to set a timeout manually to reduce billing charges." + ); + } + const response = await res.json(); + return response; + } catch (e) { + throw new Error(e.message); + } +} +const hardware_types = [ + "cpu-basic", + "cpu-upgrade", + "cpu-xl", + "t4-small", + "t4-medium", + "a10g-small", + "a10g-large", + "a10g-largex2", + "a10g-largex4", + "a100-large", + "zero-a10g", + "h100", + "h100x8" +]; +async function duplicate(app_reference, options) { + const { hf_token, private: _private, hardware, timeout, auth } = options; + if (hardware && !hardware_types.includes(hardware)) { + throw new Error( + `Invalid hardware type provided. Valid types are: ${hardware_types.map((v) => `"${v}"`).join(",")}.` + ); + } + const { http_protocol, host } = await process_endpoint( + app_reference, + hf_token + ); + let cookies = null; + if (auth) { + const cookie_header = await get_cookie_header( + http_protocol, + host, + auth, + fetch + ); + if (cookie_header) + cookies = parse_and_set_cookies(cookie_header); + } + const headers = { + Authorization: `Bearer ${hf_token}`, + "Content-Type": "application/json", + ...cookies ? { Cookie: cookies.join("; ") } : {} + }; + const user = (await (await fetch(`https://huggingface.co/api/whoami-v2`, { + headers + })).json()).name; + const space_name = app_reference.split("/")[1]; + const body = { + repository: `${user}/${space_name}` + }; + if (_private) { + body.private = true; + } + let original_hardware; + try { + if (!hardware) { + original_hardware = await get_space_hardware(app_reference, hf_token); + } + } catch (e) { + throw Error(SPACE_METADATA_ERROR_MSG + e.message); + } + const requested_hardware = hardware || original_hardware || "cpu-basic"; + body.hardware = requested_hardware; + try { + const response = await fetch( + `https://huggingface.co/api/spaces/${app_reference}/duplicate`, + { + method: "POST", + headers, + body: JSON.stringify(body) + } + ); + if (response.status === 409) { + try { + const client2 = await Client.connect(`${user}/${space_name}`, options); + return client2; + } catch (error) { + console.error("Failed to connect Client instance:", error); + throw error; + } + } else if (response.status !== 200) { + throw new Error(response.statusText); + } + const duplicated_space = await response.json(); + await set_space_timeout(`${user}/${space_name}`, timeout || 300, hf_token); + return await Client.connect( + get_space_reference(duplicated_space.url), + options + ); + } catch (e) { + throw new Error(e); + } +} +function get_space_reference(url) { + const regex = /https:\/\/huggingface.co\/spaces\/([^/]+\/[^/]+)/; + const match = url.match(regex); + if (match) { + return match[1]; + } +} +class TextLineStream extends TransformStream { + /** Constructs a new instance. */ + constructor(options = { allowCR: false }) { + super({ + transform: (chars, controller) => { + chars = __privateGet(this, _currentLine) + chars; + while (true) { + const lfIndex = chars.indexOf("\n"); + const crIndex = options.allowCR ? chars.indexOf("\r") : -1; + if (crIndex !== -1 && crIndex !== chars.length - 1 && (lfIndex === -1 || lfIndex - 1 > crIndex)) { + controller.enqueue(chars.slice(0, crIndex)); + chars = chars.slice(crIndex + 1); + continue; + } + if (lfIndex === -1) + break; + const endIndex = chars[lfIndex - 1] === "\r" ? lfIndex - 1 : lfIndex; + controller.enqueue(chars.slice(0, endIndex)); + chars = chars.slice(lfIndex + 1); + } + __privateSet(this, _currentLine, chars); + }, + flush: (controller) => { + if (__privateGet(this, _currentLine) === "") + return; + const currentLine = options.allowCR && __privateGet(this, _currentLine).endsWith("\r") ? __privateGet(this, _currentLine).slice(0, -1) : __privateGet(this, _currentLine); + controller.enqueue(currentLine); + } + }); + __privateAdd(this, _currentLine, ""); + } +} +_currentLine = new WeakMap(); +function stream$1(input) { + let decoder = new TextDecoderStream(); + let split2 = new TextLineStream({ allowCR: true }); + return input.pipeThrough(decoder).pipeThrough(split2); +} +function split(input) { + let rgx = /[:]\s*/; + let match = rgx.exec(input); + let idx = match && match.index; + if (idx) { + return [ + input.substring(0, idx), + input.substring(idx + match[0].length) + ]; + } +} +function fallback(headers, key, value) { + let tmp = headers.get(key); + if (!tmp) + headers.set(key, value); +} +async function* events(res, signal) { + if (!res.body) + return; + let iter = stream$1(res.body); + let line, reader = iter.getReader(); + let event; + for (; ; ) { + if (signal && signal.aborted) { + return reader.cancel(); + } + line = await reader.read(); + if (line.done) + return; + if (!line.value) { + if (event) + yield event; + event = void 0; + continue; + } + let [field, value] = split(line.value) || []; + if (!field) + continue; + if (field === "data") { + event || (event = {}); + event[field] = event[field] ? event[field] + "\n" + value : value; + } else if (field === "event") { + event || (event = {}); + event[field] = value; + } else if (field === "id") { + event || (event = {}); + event[field] = +value || value; + } else if (field === "retry") { + event || (event = {}); + event[field] = +value || void 0; + } + } +} +async function stream(input, init) { + let req = new Request(input, init); + fallback(req.headers, "Accept", "text/event-stream"); + fallback(req.headers, "Content-Type", "application/json"); + let r = await fetch(req); + if (!r.ok) + throw r; + return events(r, req.signal); +} +async function open_stream() { + let { + event_callbacks, + unclosed_events, + pending_stream_messages, + stream_status, + config, + jwt + } = this; + const that = this; + if (!config) { + throw new Error("Could not resolve app config"); + } + stream_status.open = true; + let stream2 = null; + let params = new URLSearchParams({ + session_hash: this.session_hash + }).toString(); + let url = new URL(`${config.root}${this.api_prefix}/${SSE_URL}?${params}`); + if (jwt) { + url.searchParams.set("__sign", jwt); + } + stream2 = this.stream(url); + if (!stream2) { + console.warn("Cannot connect to SSE endpoint: " + url.toString()); + return; + } + stream2.onmessage = async function(event) { + let _data = JSON.parse(event.data); + if (_data.msg === "close_stream") { + close_stream(stream_status, that.abort_controller); + return; + } + const event_id = _data.event_id; + if (!event_id) { + await Promise.all( + Object.keys(event_callbacks).map( + (event_id2) => event_callbacks[event_id2](_data) + ) + ); + } else if (event_callbacks[event_id] && config) { + if (_data.msg === "process_completed" && ["sse", "sse_v1", "sse_v2", "sse_v2.1", "sse_v3"].includes( + config.protocol + )) { + unclosed_events.delete(event_id); + } + let fn2 = event_callbacks[event_id]; + if (typeof window !== "undefined" && typeof document !== "undefined") { + setTimeout(fn2, 0, _data); + } else { + fn2(_data); + } + } else { + if (!pending_stream_messages[event_id]) { + pending_stream_messages[event_id] = []; + } + pending_stream_messages[event_id].push(_data); + } + }; + stream2.onerror = async function() { + await Promise.all( + Object.keys(event_callbacks).map( + (event_id) => event_callbacks[event_id]({ + msg: "unexpected_error", + message: BROKEN_CONNECTION_MSG + }) + ) + ); + }; +} +function close_stream(stream_status, abort_controller) { + if (stream_status) { + stream_status.open = false; + abort_controller == null ? void 0 : abort_controller.abort(); + } +} +function apply_diff_stream(pending_diff_streams, event_id, data) { + let is_first_generation = !pending_diff_streams[event_id]; + if (is_first_generation) { + pending_diff_streams[event_id] = []; + data.data.forEach((value, i) => { + pending_diff_streams[event_id][i] = value; + }); + } else { + data.data.forEach((value, i) => { + let new_data = apply_diff(pending_diff_streams[event_id][i], value); + pending_diff_streams[event_id][i] = new_data; + data.data[i] = new_data; + }); + } +} +function apply_diff(obj, diff) { + diff.forEach(([action, path, value]) => { + obj = apply_edit(obj, path, action, value); + }); + return obj; +} +function apply_edit(target, path, action, value) { + if (path.length === 0) { + if (action === "replace") { + return value; + } else if (action === "append") { + return target + value; + } + throw new Error(`Unsupported action: ${action}`); + } + let current = target; + for (let i = 0; i < path.length - 1; i++) { + current = current[path[i]]; + } + const last_path = path[path.length - 1]; + switch (action) { + case "replace": + current[last_path] = value; + break; + case "append": + current[last_path] += value; + break; + case "add": + if (Array.isArray(current)) { + current.splice(Number(last_path), 0, value); + } else { + current[last_path] = value; + } + break; + case "delete": + if (Array.isArray(current)) { + current.splice(Number(last_path), 1); + } else { + delete current[last_path]; + } + break; + default: + throw new Error(`Unknown action: ${action}`); + } + return target; +} +function readable_stream(input, init = {}) { + const instance = { + close: () => { + console.warn("Method not implemented."); + }, + onerror: null, + onmessage: null, + onopen: null, + readyState: 0, + url: input.toString(), + withCredentials: false, + CONNECTING: 0, + OPEN: 1, + CLOSED: 2, + addEventListener: () => { + throw new Error("Method not implemented."); + }, + dispatchEvent: () => { + throw new Error("Method not implemented."); + }, + removeEventListener: () => { + throw new Error("Method not implemented."); + } + }; + stream(input, init).then(async (res) => { + instance.readyState = instance.OPEN; + try { + for await (const chunk of res) { + instance.onmessage && instance.onmessage(chunk); + } + instance.readyState = instance.CLOSED; + } catch (e) { + instance.onerror && instance.onerror(e); + instance.readyState = instance.CLOSED; + } + }).catch((e) => { + console.error(e); + instance.onerror && instance.onerror(e); + instance.readyState = instance.CLOSED; + }); + return instance; +} +function submit(endpoint, data = {}, event_data, trigger_id, all_events) { + var _a; + try { + let fire_event = function(event) { + if (all_events || events_to_publish[event.type]) { + push_event(event); + } + }, close = function() { + done = true; + while (resolvers.length > 0) + resolvers.shift()({ + value: void 0, + done: true + }); + }, push = function(data2) { + if (done) + return; + if (resolvers.length > 0) { + resolvers.shift()(data2); + } else { + values.push(data2); + } + }, push_error = function(error) { + push(thenable_reject(error)); + close(); + }, push_event = function(event) { + push({ value: event, done: false }); + }, next = function() { + if (values.length > 0) + return Promise.resolve(values.shift()); + if (done) + return Promise.resolve({ value: void 0, done: true }); + return new Promise((resolve) => resolvers.push(resolve)); + }; + const { hf_token } = this.options; + const { + fetch: fetch2, + app_reference, + config, + session_hash, + api_info, + api_map, + stream_status, + pending_stream_messages, + pending_diff_streams, + event_callbacks, + unclosed_events, + post_data: post_data2, + options, + api_prefix + } = this; + const that = this; + if (!api_info) + throw new Error("No API found"); + if (!config) + throw new Error("Could not resolve app config"); + let { fn_index, endpoint_info, dependency } = get_endpoint_info( + api_info, + endpoint, + api_map, + config + ); + let resolved_data = map_data_to_params(data, endpoint_info); + let websocket; + let stream2; + let protocol = config.protocol ?? "ws"; + let event_id_final = ""; + let event_id_cb = () => event_id_final; + const _endpoint = typeof endpoint === "number" ? "/predict" : endpoint; + let payload; + let event_id = null; + let complete = false; + let last_status = {}; + let url_params = typeof window !== "undefined" && typeof document !== "undefined" ? new URLSearchParams(window.location.search).toString() : ""; + const events_to_publish = ((_a = options == null ? void 0 : options.events) == null ? void 0 : _a.reduce( + (acc, event) => { + acc[event] = true; + return acc; + }, + {} + )) || {}; + async function cancel() { + const _status = { + stage: "complete", + queue: false, + time: /* @__PURE__ */ new Date() + }; + complete = _status; + fire_event({ + ..._status, + type: "status", + endpoint: _endpoint, + fn_index + }); + let reset_request = {}; + let cancel_request = {}; + if (protocol === "ws") { + if (websocket && websocket.readyState === 0) { + websocket.addEventListener("open", () => { + websocket.close(); + }); + } else { + websocket.close(); + } + reset_request = { fn_index, session_hash }; + } else { + close_stream(stream_status, that.abort_controller); + close(); + reset_request = { event_id }; + cancel_request = { event_id, session_hash, fn_index }; + } + try { + if (!config) { + throw new Error("Could not resolve app config"); + } + if ("event_id" in cancel_request) { + await fetch2(`${config.root}${api_prefix}/${CANCEL_URL}`, { + headers: { "Content-Type": "application/json" }, + method: "POST", + body: JSON.stringify(cancel_request) + }); + } + await fetch2(`${config.root}${api_prefix}/${RESET_URL}`, { + headers: { "Content-Type": "application/json" }, + method: "POST", + body: JSON.stringify(reset_request) + }); + } catch (e) { + console.warn( + "The `/reset` endpoint could not be called. Subsequent endpoint results may be unreliable." + ); + } + } + const resolve_heartbeat = async (config2) => { + await this._resolve_hearbeat(config2); + }; + async function handle_render_config(render_config) { + if (!config) + return; + let render_id = render_config.render_id; + config.components = [ + ...config.components.filter((c) => c.props.rendered_in !== render_id), + ...render_config.components + ]; + config.dependencies = [ + ...config.dependencies.filter((d) => d.rendered_in !== render_id), + ...render_config.dependencies + ]; + const any_state = config.components.some((c) => c.type === "state"); + const any_unload = config.dependencies.some( + (d) => d.targets.some((t) => t[1] === "unload") + ); + config.connect_heartbeat = any_state || any_unload; + await resolve_heartbeat(config); + fire_event({ + type: "render", + data: render_config, + endpoint: _endpoint, + fn_index + }); + } + this.handle_blob(config.root, resolved_data, endpoint_info).then( + async (_payload) => { + var _a2; + let input_data = handle_payload( + _payload, + dependency, + config.components, + "input", + true + ); + payload = { + data: input_data || [], + event_data, + fn_index, + trigger_id + }; + if (skip_queue(fn_index, config)) { + fire_event({ + type: "status", + endpoint: _endpoint, + stage: "pending", + queue: false, + fn_index, + time: /* @__PURE__ */ new Date() + }); + post_data2( + `${config.root}${api_prefix}/run${_endpoint.startsWith("/") ? _endpoint : `/${_endpoint}`}${url_params ? "?" + url_params : ""}`, + { + ...payload, + session_hash + } + ).then(([output, status_code]) => { + const data2 = output.data; + if (status_code == 200) { + fire_event({ + type: "data", + endpoint: _endpoint, + fn_index, + data: handle_payload( + data2, + dependency, + config.components, + "output", + options.with_null_state + ), + time: /* @__PURE__ */ new Date(), + event_data, + trigger_id + }); + if (output.render_config) { + handle_render_config(output.render_config); + } + fire_event({ + type: "status", + endpoint: _endpoint, + fn_index, + stage: "complete", + eta: output.average_duration, + queue: false, + time: /* @__PURE__ */ new Date() + }); + } else { + fire_event({ + type: "status", + stage: "error", + endpoint: _endpoint, + fn_index, + message: output.error, + queue: false, + time: /* @__PURE__ */ new Date() + }); + } + }).catch((e) => { + fire_event({ + type: "status", + stage: "error", + message: e.message, + endpoint: _endpoint, + fn_index, + queue: false, + time: /* @__PURE__ */ new Date() + }); + }); + } else if (protocol == "ws") { + const { ws_protocol, host } = await process_endpoint( + app_reference, + hf_token + ); + fire_event({ + type: "status", + stage: "pending", + queue: true, + endpoint: _endpoint, + fn_index, + time: /* @__PURE__ */ new Date() + }); + let url = new URL( + `${ws_protocol}://${resolve_root( + host, + config.path, + true + )}/queue/join${url_params ? "?" + url_params : ""}` + ); + if (this.jwt) { + url.searchParams.set("__sign", this.jwt); + } + websocket = new WebSocket(url); + websocket.onclose = (evt) => { + if (!evt.wasClean) { + fire_event({ + type: "status", + stage: "error", + broken: true, + message: BROKEN_CONNECTION_MSG, + queue: true, + endpoint: _endpoint, + fn_index, + time: /* @__PURE__ */ new Date() + }); + } + }; + websocket.onmessage = function(event) { + const _data = JSON.parse(event.data); + const { type, status, data: data2 } = handle_message( + _data, + last_status[fn_index] + ); + if (type === "update" && status && !complete) { + fire_event({ + type: "status", + endpoint: _endpoint, + fn_index, + time: /* @__PURE__ */ new Date(), + ...status + }); + if (status.stage === "error") { + websocket.close(); + } + } else if (type === "hash") { + websocket.send(JSON.stringify({ fn_index, session_hash })); + return; + } else if (type === "data") { + websocket.send(JSON.stringify({ ...payload, session_hash })); + } else if (type === "complete") { + complete = status; + } else if (type === "log") { + fire_event({ + type: "log", + title: data2.title, + log: data2.log, + level: data2.level, + endpoint: _endpoint, + duration: data2.duration, + visible: data2.visible, + fn_index + }); + } else if (type === "generating") { + fire_event({ + type: "status", + time: /* @__PURE__ */ new Date(), + ...status, + stage: status == null ? void 0 : status.stage, + queue: true, + endpoint: _endpoint, + fn_index + }); + } + if (data2) { + fire_event({ + type: "data", + time: /* @__PURE__ */ new Date(), + data: handle_payload( + data2.data, + dependency, + config.components, + "output", + options.with_null_state + ), + endpoint: _endpoint, + fn_index, + event_data, + trigger_id + }); + if (complete) { + fire_event({ + type: "status", + time: /* @__PURE__ */ new Date(), + ...complete, + stage: status == null ? void 0 : status.stage, + queue: true, + endpoint: _endpoint, + fn_index + }); + websocket.close(); + } + } + }; + if (semiver(config.version || "2.0.0", "3.6") < 0) { + addEventListener( + "open", + () => websocket.send(JSON.stringify({ hash: session_hash })) + ); + } + } else if (protocol == "sse") { + fire_event({ + type: "status", + stage: "pending", + queue: true, + endpoint: _endpoint, + fn_index, + time: /* @__PURE__ */ new Date() + }); + var params = new URLSearchParams({ + fn_index: fn_index.toString(), + session_hash + }).toString(); + let url = new URL( + `${config.root}${api_prefix}/${SSE_URL}?${url_params ? url_params + "&" : ""}${params}` + ); + if (this.jwt) { + url.searchParams.set("__sign", this.jwt); + } + stream2 = this.stream(url); + if (!stream2) { + return Promise.reject( + new Error("Cannot connect to SSE endpoint: " + url.toString()) + ); + } + stream2.onmessage = async function(event) { + const _data = JSON.parse(event.data); + const { type, status, data: data2 } = handle_message( + _data, + last_status[fn_index] + ); + if (type === "update" && status && !complete) { + fire_event({ + type: "status", + endpoint: _endpoint, + fn_index, + time: /* @__PURE__ */ new Date(), + ...status + }); + if (status.stage === "error") { + stream2 == null ? void 0 : stream2.close(); + close(); + } + } else if (type === "data") { + let [_, status2] = await post_data2( + `${config.root}${api_prefix}/queue/data`, + { + ...payload, + session_hash, + event_id + } + ); + if (status2 !== 200) { + fire_event({ + type: "status", + stage: "error", + message: BROKEN_CONNECTION_MSG, + queue: true, + endpoint: _endpoint, + fn_index, + time: /* @__PURE__ */ new Date() + }); + stream2 == null ? void 0 : stream2.close(); + close(); + } + } else if (type === "complete") { + complete = status; + } else if (type === "log") { + fire_event({ + type: "log", + title: data2.title, + log: data2.log, + level: data2.level, + endpoint: _endpoint, + duration: data2.duration, + visible: data2.visible, + fn_index + }); + } else if (type === "generating" || type === "streaming") { + fire_event({ + type: "status", + time: /* @__PURE__ */ new Date(), + ...status, + stage: status == null ? void 0 : status.stage, + queue: true, + endpoint: _endpoint, + fn_index + }); + } + if (data2) { + fire_event({ + type: "data", + time: /* @__PURE__ */ new Date(), + data: handle_payload( + data2.data, + dependency, + config.components, + "output", + options.with_null_state + ), + endpoint: _endpoint, + fn_index, + event_data, + trigger_id + }); + if (complete) { + fire_event({ + type: "status", + time: /* @__PURE__ */ new Date(), + ...complete, + stage: status == null ? void 0 : status.stage, + queue: true, + endpoint: _endpoint, + fn_index + }); + stream2 == null ? void 0 : stream2.close(); + close(); + } + } + }; + } else if (protocol == "sse_v1" || protocol == "sse_v2" || protocol == "sse_v2.1" || protocol == "sse_v3") { + fire_event({ + type: "status", + stage: "pending", + queue: true, + endpoint: _endpoint, + fn_index, + time: /* @__PURE__ */ new Date() + }); + let hostname = ""; + if (typeof window !== "undefined" && typeof document !== "undefined") { + hostname = (_a2 = window == null ? void 0 : window.location) == null ? void 0 : _a2.hostname; + } + let hfhubdev = "dev.spaces.huggingface.tech"; + const origin = hostname.includes(".dev.") ? `https://moon-${hostname.split(".")[1]}.${hfhubdev}` : `https://huggingface.co`; + const is_zerogpu_iframe = typeof window !== "undefined" && typeof document !== "undefined" && window.parent != window && window.supports_zerogpu_headers; + const zerogpu_auth_promise = is_zerogpu_iframe ? post_message("zerogpu-headers", origin) : Promise.resolve(null); + const post_data_promise = zerogpu_auth_promise.then((headers) => { + return post_data2( + `${config.root}${api_prefix}/${SSE_DATA_URL}?${url_params}`, + { + ...payload, + session_hash + }, + headers + ); + }); + post_data_promise.then(async ([response, status]) => { + if (status === 503) { + fire_event({ + type: "status", + stage: "error", + message: QUEUE_FULL_MSG, + queue: true, + endpoint: _endpoint, + fn_index, + time: /* @__PURE__ */ new Date() + }); + } else if (status !== 200) { + fire_event({ + type: "status", + stage: "error", + message: BROKEN_CONNECTION_MSG, + queue: true, + endpoint: _endpoint, + fn_index, + time: /* @__PURE__ */ new Date() + }); + } else { + event_id = response.event_id; + event_id_final = event_id; + let callback = async function(_data) { + try { + const { type, status: status2, data: data2, original_msg } = handle_message( + _data, + last_status[fn_index] + ); + if (type == "heartbeat") { + return; + } + if (type === "update" && status2 && !complete) { + fire_event({ + type: "status", + endpoint: _endpoint, + fn_index, + time: /* @__PURE__ */ new Date(), + original_msg, + ...status2 + }); + } else if (type === "complete") { + complete = status2; + } else if (type == "unexpected_error") { + console.error("Unexpected error", status2 == null ? void 0 : status2.message); + fire_event({ + type: "status", + stage: "error", + message: (status2 == null ? void 0 : status2.message) || "An Unexpected Error Occurred!", + queue: true, + endpoint: _endpoint, + fn_index, + time: /* @__PURE__ */ new Date() + }); + } else if (type === "log") { + fire_event({ + type: "log", + title: data2.title, + log: data2.log, + level: data2.level, + endpoint: _endpoint, + duration: data2.duration, + visible: data2.visible, + fn_index + }); + return; + } else if (type === "generating" || type === "streaming") { + fire_event({ + type: "status", + time: /* @__PURE__ */ new Date(), + ...status2, + stage: status2 == null ? void 0 : status2.stage, + queue: true, + endpoint: _endpoint, + fn_index + }); + if (data2 && dependency.connection !== "stream" && ["sse_v2", "sse_v2.1", "sse_v3"].includes(protocol)) { + apply_diff_stream(pending_diff_streams, event_id, data2); + } + } + if (data2) { + fire_event({ + type: "data", + time: /* @__PURE__ */ new Date(), + data: handle_payload( + data2.data, + dependency, + config.components, + "output", + options.with_null_state + ), + endpoint: _endpoint, + fn_index + }); + if (data2.render_config) { + await handle_render_config(data2.render_config); + } + if (complete) { + fire_event({ + type: "status", + time: /* @__PURE__ */ new Date(), + ...complete, + stage: status2 == null ? void 0 : status2.stage, + queue: true, + endpoint: _endpoint, + fn_index + }); + close(); + } + } + if ((status2 == null ? void 0 : status2.stage) === "complete" || (status2 == null ? void 0 : status2.stage) === "error") { + if (event_callbacks[event_id]) { + delete event_callbacks[event_id]; + } + if (event_id in pending_diff_streams) { + delete pending_diff_streams[event_id]; + } + } + } catch (e) { + console.error("Unexpected client exception", e); + fire_event({ + type: "status", + stage: "error", + message: "An Unexpected Error Occurred!", + queue: true, + endpoint: _endpoint, + fn_index, + time: /* @__PURE__ */ new Date() + }); + if (["sse_v2", "sse_v2.1", "sse_v3"].includes(protocol)) { + close_stream(stream_status, that.abort_controller); + stream_status.open = false; + close(); + } + } + }; + if (event_id in pending_stream_messages) { + pending_stream_messages[event_id].forEach( + (msg) => callback(msg) + ); + delete pending_stream_messages[event_id]; + } + event_callbacks[event_id] = callback; + unclosed_events.add(event_id); + if (!stream_status.open) { + await this.open_stream(); + } + } + }); + } + } + ); + let done = false; + const values = []; + const resolvers = []; + const iterator = { + [Symbol.asyncIterator]: () => iterator, + next, + throw: async (value) => { + push_error(value); + return next(); + }, + return: async () => { + close(); + return next(); + }, + cancel, + event_id: event_id_cb + }; + return iterator; + } catch (error) { + console.error("Submit function encountered an error:", error); + throw error; + } +} +function thenable_reject(error) { + return { + then: (resolve, reject) => reject(error) + }; +} +function get_endpoint_info(api_info, endpoint, api_map, config) { + let fn_index; + let endpoint_info; + let dependency; + if (typeof endpoint === "number") { + fn_index = endpoint; + endpoint_info = api_info.unnamed_endpoints[fn_index]; + dependency = config.dependencies.find((dep) => dep.id == endpoint); + } else { + const trimmed_endpoint = endpoint.replace(/^\//, ""); + fn_index = api_map[trimmed_endpoint]; + endpoint_info = api_info.named_endpoints[endpoint.trim()]; + dependency = config.dependencies.find( + (dep) => dep.id == api_map[trimmed_endpoint] + ); + } + if (typeof fn_index !== "number") { + throw new Error( + "There is no endpoint matching that name of fn_index matching that number." + ); + } + return { fn_index, endpoint_info, dependency }; +} +class Client { + constructor(app_reference, options = { events: ["data"] }) { + __publicField(this, "app_reference"); + __publicField(this, "options"); + __publicField(this, "deep_link", null); + __publicField(this, "config"); + __publicField(this, "api_prefix", ""); + __publicField(this, "api_info"); + __publicField(this, "api_map", {}); + __publicField(this, "session_hash", Math.random().toString(36).substring(2)); + __publicField(this, "jwt", false); + __publicField(this, "last_status", {}); + __publicField(this, "cookies", null); + // streaming + __publicField(this, "stream_status", { open: false }); + __publicField(this, "closed", false); + __publicField(this, "pending_stream_messages", {}); + __publicField(this, "pending_diff_streams", {}); + __publicField(this, "event_callbacks", {}); + __publicField(this, "unclosed_events", /* @__PURE__ */ new Set()); + __publicField(this, "heartbeat_event", null); + __publicField(this, "abort_controller", null); + __publicField(this, "stream_instance", null); + __publicField(this, "current_payload"); + __publicField(this, "ws_map", {}); + __publicField(this, "view_api"); + __publicField(this, "upload_files"); + __publicField(this, "upload"); + __publicField(this, "handle_blob"); + __publicField(this, "post_data"); + __publicField(this, "submit"); + __publicField(this, "predict"); + __publicField(this, "open_stream"); + __publicField(this, "resolve_config"); + __publicField(this, "resolve_cookies"); + var _a; + this.app_reference = app_reference; + this.deep_link = ((_a = options.query_params) == null ? void 0 : _a.deep_link) || null; + if (!options.events) { + options.events = ["data"]; + } + this.options = options; + this.current_payload = {}; + this.view_api = view_api.bind(this); + this.upload_files = upload_files.bind(this); + this.handle_blob = handle_blob.bind(this); + this.post_data = post_data.bind(this); + this.submit = submit.bind(this); + this.predict = predict.bind(this); + this.open_stream = open_stream.bind(this); + this.resolve_config = resolve_config.bind(this); + this.resolve_cookies = resolve_cookies.bind(this); + this.upload = upload.bind(this); + this.fetch = this.fetch.bind(this); + this.handle_space_success = this.handle_space_success.bind(this); + this.stream = this.stream.bind(this); + } + get_url_config(url = null) { + if (!this.config) { + throw new Error(CONFIG_ERROR_MSG); + } + if (url === null) { + url = window.location.href; + } + const stripSlashes = (str) => str.replace(/^\/+|\/+$/g, ""); + let root_path = stripSlashes(new URL(this.config.root).pathname); + let url_path = stripSlashes(new URL(url).pathname); + let page; + if (!url_path.startsWith(root_path)) { + page = ""; + } else { + page = stripSlashes(url_path.substring(root_path.length)); + } + return this.get_page_config(page); + } + get_page_config(page) { + if (!this.config) { + throw new Error(CONFIG_ERROR_MSG); + } + let config = this.config; + if (!(page in config.page)) { + page = ""; + } + return { + ...config, + current_page: page, + layout: config.page[page].layout, + components: config.components.filter( + (c) => config.page[page].components.includes(c.id) + ), + dependencies: this.config.dependencies.filter( + (d) => config.page[page].dependencies.includes(d.id) + ) + }; + } + fetch(input, init) { + const headers = new Headers((init == null ? void 0 : init.headers) || {}); + if (this && this.cookies) { + headers.append("Cookie", this.cookies); + } + if (this && this.options.headers) { + for (const name in this.options.headers) { + headers.append(name, this.options.headers[name]); + } + } + return fetch(input, { ...init, headers }); + } + stream(url) { + const headers = new Headers(); + if (this && this.cookies) { + headers.append("Cookie", this.cookies); + } + if (this && this.options.headers) { + for (const name in this.options.headers) { + headers.append(name, this.options.headers[name]); + } + } + this.abort_controller = new AbortController(); + this.stream_instance = readable_stream(url.toString(), { + credentials: "include", + headers, + signal: this.abort_controller.signal + }); + return this.stream_instance; + } + async init() { + var _a; + if ((typeof window === "undefined" || !("WebSocket" in window)) && !global.WebSocket) { + const ws = await import("./wrapper-CviSselG.js"); + global.WebSocket = ws.WebSocket; + } + if (this.options.auth) { + await this.resolve_cookies(); + } + await this._resolve_config().then( + ({ config }) => this._resolve_hearbeat(config) + ); + this.api_info = await this.view_api(); + this.api_map = map_names_to_ids(((_a = this.config) == null ? void 0 : _a.dependencies) || []); + } + async _resolve_hearbeat(_config) { + if (_config) { + this.config = _config; + this.api_prefix = _config.api_prefix || ""; + if (this.config && this.config.connect_heartbeat) { + if (this.config.space_id && this.options.hf_token) { + this.jwt = await get_jwt( + this.config.space_id, + this.options.hf_token, + this.cookies + ); + } + } + } + if (_config.space_id && this.options.hf_token) { + this.jwt = await get_jwt(_config.space_id, this.options.hf_token); + } + if (this.config && this.config.connect_heartbeat) { + const heartbeat_url = new URL( + `${this.config.root}${this.api_prefix}/${HEARTBEAT_URL}/${this.session_hash}` + ); + if (this.jwt) { + heartbeat_url.searchParams.set("__sign", this.jwt); + } + if (!this.heartbeat_event) { + this.heartbeat_event = this.stream(heartbeat_url); + } + } + } + static async connect(app_reference, options = { + events: ["data"] + }) { + const client2 = new this(app_reference, options); + await client2.init(); + return client2; + } + close() { + this.closed = true; + close_stream(this.stream_status, this.abort_controller); + } + set_current_payload(payload) { + this.current_payload = payload; + } + static async duplicate(app_reference, options = { + events: ["data"] + }) { + return duplicate(app_reference, options); + } + async _resolve_config() { + const { http_protocol, host, space_id } = await process_endpoint( + this.app_reference, + this.options.hf_token + ); + const { status_callback } = this.options; + if (space_id && status_callback) { + await check_and_wake_space(space_id, status_callback); + } + let config; + try { + let configUrl = `${http_protocol}//${host}`; + config = await this.resolve_config(configUrl); + if (!config) { + throw new Error(CONFIG_ERROR_MSG); + } + return this.config_success(config); + } catch (e) { + if (space_id && status_callback) { + check_space_status( + space_id, + RE_SPACE_NAME.test(space_id) ? "space_name" : "subdomain", + this.handle_space_success + ); + } else { + if (status_callback) + status_callback({ + status: "error", + message: "Could not load this space.", + load_status: "error", + detail: "NOT_FOUND" + }); + throw Error(e); + } + } + } + async config_success(_config) { + this.config = _config; + this.api_prefix = _config.api_prefix || ""; + if (typeof window !== "undefined" && typeof document !== "undefined") { + if (window.location.protocol === "https:") { + this.config.root = this.config.root.replace("http://", "https://"); + } + } + if (this.config.auth_required) { + return this.prepare_return_obj(); + } + try { + this.api_info = await this.view_api(); + } catch (e) { + console.error(API_INFO_ERROR_MSG + e.message); + } + return this.prepare_return_obj(); + } + async handle_space_success(status) { + var _a; + if (!this) { + throw new Error(CONFIG_ERROR_MSG); + } + const { status_callback } = this.options; + if (status_callback) + status_callback(status); + if (status.status === "running") { + try { + this.config = await this._resolve_config(); + this.api_prefix = ((_a = this == null ? void 0 : this.config) == null ? void 0 : _a.api_prefix) || ""; + if (!this.config) { + throw new Error(CONFIG_ERROR_MSG); + } + const _config = await this.config_success(this.config); + return _config; + } catch (e) { + if (status_callback) { + status_callback({ + status: "error", + message: "Could not load this space.", + load_status: "error", + detail: "NOT_FOUND" + }); + } + throw e; + } + } + } + async component_server(component_id, fn_name, data) { + var _a; + if (!this.config) { + throw new Error(CONFIG_ERROR_MSG); + } + const headers = {}; + const { hf_token } = this.options; + const { session_hash } = this; + if (hf_token) { + headers.Authorization = `Bearer ${this.options.hf_token}`; + } + let root_url; + let component = this.config.components.find( + (comp) => comp.id === component_id + ); + if ((_a = component == null ? void 0 : component.props) == null ? void 0 : _a.root_url) { + root_url = component.props.root_url; + } else { + root_url = this.config.root; + } + let body; + if ("binary" in data) { + body = new FormData(); + for (const key in data.data) { + if (key === "binary") + continue; + body.append(key, data.data[key]); + } + body.set("component_id", component_id.toString()); + body.set("fn_name", fn_name); + body.set("session_hash", session_hash); + } else { + body = JSON.stringify({ + data, + component_id, + fn_name, + session_hash + }); + headers["Content-Type"] = "application/json"; + } + if (hf_token) { + headers.Authorization = `Bearer ${hf_token}`; + } + try { + const response = await this.fetch( + `${root_url}${this.api_prefix}/${COMPONENT_SERVER_URL}/`, + { + method: "POST", + body, + headers, + credentials: "include" + } + ); + if (!response.ok) { + throw new Error( + "Could not connect to component server: " + response.statusText + ); + } + const output = await response.json(); + return output; + } catch (e) { + console.warn(e); + } + } + set_cookies(raw_cookies) { + this.cookies = parse_and_set_cookies(raw_cookies).join("; "); + } + prepare_return_obj() { + return { + config: this.config, + predict: this.predict, + submit: this.submit, + view_api: this.view_api, + component_server: this.component_server + }; + } + async connect_ws(url) { + return new Promise((resolve, reject) => { + let ws; + try { + ws = new WebSocket(url); + } catch (e) { + this.ws_map[url] = "failed"; + return; + } + ws.onopen = () => { + resolve(); + }; + ws.onerror = (error) => { + console.error("WebSocket error:", error); + this.close_ws(url); + this.ws_map[url] = "failed"; + resolve(); + }; + ws.onclose = () => { + delete this.ws_map[url]; + this.ws_map[url] = "failed"; + }; + ws.onmessage = (event) => { + }; + this.ws_map[url] = ws; + }); + } + async send_ws_message(url, data) { + if (!(url in this.ws_map)) { + await this.connect_ws(url); + } + const ws = this.ws_map[url]; + if (ws instanceof WebSocket) { + ws.send(JSON.stringify(data)); + } else { + this.post_data(url, data); + } + } + async close_ws(url) { + if (url in this.ws_map) { + const ws = this.ws_map[url]; + if (ws instanceof WebSocket) { + ws.close(); + delete this.ws_map[url]; + } + } + } +} +async function client(app_reference, options = { + events: ["data"] +}) { + return await Client.connect(app_reference, options); +} +async function duplicate_space(app_reference, options) { + return await Client.duplicate(app_reference, options); +} +export { + Client, + FileData, + client, + duplicate_space as duplicate, + handle_file, + predict, + prepare_files, + submit, + upload, + upload_files +}; diff --git a/node_modules/@gradio/client/dist/test/handlers.d.ts b/node_modules/@gradio/client/dist/test/handlers.d.ts new file mode 100644 index 0000000000000000000000000000000000000000..379dbe7871f6d0e74290139b977598640ed6e2a3 --- /dev/null +++ b/node_modules/@gradio/client/dist/test/handlers.d.ts @@ -0,0 +1,4 @@ +import { RequestHandler } from "msw"; +export declare const direct_space_url = "https://hmb-hello-world.hf.space"; +export declare const handlers: RequestHandler[]; +//# sourceMappingURL=handlers.d.ts.map \ No newline at end of file diff --git a/node_modules/@gradio/client/dist/test/handlers.d.ts.map b/node_modules/@gradio/client/dist/test/handlers.d.ts.map new file mode 100644 index 0000000000000000000000000000000000000000..af40fffe69b02ab37140d82f30cf211e48a63467 --- /dev/null +++ b/node_modules/@gradio/client/dist/test/handlers.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"handlers.d.ts","sourceRoot":"","sources":["../../src/test/handlers.ts"],"names":[],"mappings":"AAAA,OAAO,EAAsB,cAAc,EAAE,MAAM,KAAK,CAAC;AAuBzD,eAAO,MAAM,gBAAgB,qCAAqC,CAAC;AAqBnE,eAAO,MAAM,QAAQ,EAAE,cAAc,EAwoBpC,CAAC"} \ No newline at end of file diff --git a/node_modules/@gradio/client/dist/test/mock_eventsource.d.ts b/node_modules/@gradio/client/dist/test/mock_eventsource.d.ts new file mode 100644 index 0000000000000000000000000000000000000000..fecaa636c8deed45b2f0cebced58e709815d94db --- /dev/null +++ b/node_modules/@gradio/client/dist/test/mock_eventsource.d.ts @@ -0,0 +1,2 @@ +export {}; +//# sourceMappingURL=mock_eventsource.d.ts.map \ No newline at end of file diff --git a/node_modules/@gradio/client/dist/test/mock_eventsource.d.ts.map b/node_modules/@gradio/client/dist/test/mock_eventsource.d.ts.map new file mode 100644 index 0000000000000000000000000000000000000000..5a249f5a4ae9c0a41b8a6f26d27eb2d227927793 --- /dev/null +++ b/node_modules/@gradio/client/dist/test/mock_eventsource.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"mock_eventsource.d.ts","sourceRoot":"","sources":["../../src/test/mock_eventsource.ts"],"names":[],"mappings":""} \ No newline at end of file diff --git a/node_modules/@gradio/client/dist/test/server.d.ts b/node_modules/@gradio/client/dist/test/server.d.ts new file mode 100644 index 0000000000000000000000000000000000000000..e7b6d7385d7c54cc5ccea7f30f30ab24ce407242 --- /dev/null +++ b/node_modules/@gradio/client/dist/test/server.d.ts @@ -0,0 +1,2 @@ +export declare function initialise_server(): any; +//# sourceMappingURL=server.d.ts.map \ No newline at end of file diff --git a/node_modules/@gradio/client/dist/test/server.d.ts.map b/node_modules/@gradio/client/dist/test/server.d.ts.map new file mode 100644 index 0000000000000000000000000000000000000000..da108d064bf287d0e7756476543e476bf7dcc8e6 --- /dev/null +++ b/node_modules/@gradio/client/dist/test/server.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/test/server.ts"],"names":[],"mappings":"AAGA,wBAAgB,iBAAiB,IAAI,GAAG,CAEvC"} \ No newline at end of file diff --git a/node_modules/@gradio/client/dist/test/test_data.d.ts b/node_modules/@gradio/client/dist/test/test_data.d.ts new file mode 100644 index 0000000000000000000000000000000000000000..992f31d292809e5ee921bf176724a75553a68f9f --- /dev/null +++ b/node_modules/@gradio/client/dist/test/test_data.d.ts @@ -0,0 +1,76 @@ +import { ApiData, ApiInfo, Config, EndpointInfo } from "../types"; +export declare const runtime_response: { + stage: string; + hardware: { + current: string; + requested: string; + }; + storage: { + current: null; + requested: null; + }; + gcTimeout: number; + replicas: { + current: number; + requested: number; + }; + devMode: boolean; + domains: { + domain: string; + isCustom: boolean; + stage: string; + }[]; +}; +export declare const transformed_api_info: ApiInfo; +export declare const response_api_info: ApiInfo; +export declare const config_response: Config; +export declare const whoami_response: { + type: string; + id: string; + name: string; + fullname: string; + email: string; + emailVerified: boolean; + canPay: boolean; + periodEnd: number; + isPro: boolean; + avatarUrl: string; + orgs: never[]; + auth: { + type: string; + accessToken: { + displayName: string; + role: string; + }; + }; +}; +export declare const duplicate_response: { + url: string; +}; +export declare const hardware_sleeptime_response: { + stage: string; + hardware: { + current: string; + requested: string; + }; + storage: null; + gcTimeout: number; + replicas: { + current: number; + requested: number; + }; + devMode: boolean; + domains: { + domain: string; + isCustom: boolean; + stage: string; + }[]; +}; +export declare const endpoint_info: EndpointInfo; +export declare const discussions_response: { + discussions: never[]; + count: number; + start: number; + numClosedDiscussions: number; +}; +//# sourceMappingURL=test_data.d.ts.map \ No newline at end of file diff --git a/node_modules/@gradio/client/dist/test/test_data.d.ts.map b/node_modules/@gradio/client/dist/test/test_data.d.ts.map new file mode 100644 index 0000000000000000000000000000000000000000..98ed3064c7b350a5dee83871e45a12eb946159f0 --- /dev/null +++ b/node_modules/@gradio/client/dist/test/test_data.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"test_data.d.ts","sourceRoot":"","sources":["../../src/test/test_data.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AAElE,eAAO,MAAM,gBAAgB;;;;;;;;;;;;;;;;;;;;;CAuB5B,CAAC;AAEF,eAAO,MAAM,oBAAoB,EAAE,OAAO,CAAC,OAAO,CA6CjD,CAAC;AAEF,eAAO,MAAM,iBAAiB,EAAE,OAAO,CAAC,OAAO,CAiC9C,CAAC;AAEF,eAAO,MAAM,eAAe,EAAE,MA+V7B,CAAC;AAEF,eAAO,MAAM,eAAe;;;;;;;;;;;;;;;;;;;CAmB3B,CAAC;AAEF,eAAO,MAAM,kBAAkB;;CAE9B,CAAC;AAEF,eAAO,MAAM,2BAA2B;;;;;;;;;;;;;;;;;;CAoBvC,CAAC;AAEF,eAAO,MAAM,aAAa,EAAE,YAAY,CAAC,OAAO,CAyC/C,CAAC;AAEF,eAAO,MAAM,oBAAoB;;;;;CAKhC,CAAC"} \ No newline at end of file diff --git a/node_modules/@gradio/client/dist/types.d.ts b/node_modules/@gradio/client/dist/types.d.ts new file mode 100644 index 0000000000000000000000000000000000000000..73f171dc756520f87db75dd854e79babfd063724 --- /dev/null +++ b/node_modules/@gradio/client/dist/types.d.ts @@ -0,0 +1,330 @@ +/// +import { hardware_types } from "./helpers/spaces"; +import type { SvelteComponent } from "svelte"; +import type { ComponentType } from "svelte"; +export interface ApiData { + label: string; + parameter_name: string; + parameter_default?: any; + parameter_has_default?: boolean; + type: { + type: any; + description: string; + }; + component: string; + example_input?: any; + python_type: { + type: string; + description: string; + }; + serializer: string; +} +export interface JsApiData { + label: string; + parameter_name: string; + parameter_default?: any; + parameter_has_default?: boolean; + type: string; + description: string; + component: string; + example_input?: any; + serializer: string; + python_type: { + type: string; + description: string; + }; +} +export interface EndpointInfo { + parameters: T[]; + returns: T[]; + type?: DependencyTypes; +} +export interface ApiInfo { + named_endpoints: Record>; + unnamed_endpoints: Record>; +} +export interface BlobRef { + path: string[]; + type: string | undefined; + blob: Blob | File | false; +} +export type DataType = string | Buffer | Record | any[]; +export declare class Command { + type: string; + command: string; + meta: { + path: string; + name: string; + orig_path: string; + }; + fileData?: FileData; + constructor(command: string, meta: { + path: string; + name: string; + orig_path: string; + }); +} +export type SubmitFunction = (endpoint: string | number, data?: unknown[] | Record, event_data?: unknown, trigger_id?: number | null) => SubmitIterable; +export type PredictFunction = (endpoint: string | number, data?: unknown[] | Record, event_data?: unknown) => Promise; +export type client_return = { + config: Config | undefined; + predict: PredictFunction; + submit: SubmitFunction; + component_server: (component_id: number, fn_name: string, data: unknown[]) => any; + view_api: (_fetch: typeof fetch) => Promise>; +}; +export interface SubmitIterable extends AsyncIterable { + [Symbol.asyncIterator](): AsyncIterator; + cancel: () => Promise; + event_id: () => string; +} +export type PredictReturn = { + type: EventType; + time: Date; + data: unknown; + endpoint: string; + fn_index: number; +}; +export type SpaceStatus = SpaceStatusNormal | SpaceStatusError; +export interface SpaceStatusNormal { + status: "sleeping" | "running" | "building" | "error" | "stopped" | "starting"; + detail: "SLEEPING" | "RUNNING" | "RUNNING_BUILDING" | "BUILDING" | "APP_STARTING" | "NOT_FOUND"; + load_status: "pending" | "error" | "complete" | "generating"; + message: string; +} +export interface SpaceStatusError { + status: "space_error" | "paused"; + detail: "NO_APP_FILE" | "CONFIG_ERROR" | "BUILD_ERROR" | "RUNTIME_ERROR" | "PAUSED"; + load_status: "error"; + message: string; + discussions_enabled: boolean; +} +export type SpaceStatusCallback = (a: SpaceStatus) => void; +export interface Config { + deep_link_state?: "none" | "valid" | "invalid"; + auth_required?: true; + analytics_enabled: boolean; + connect_heartbeat: boolean; + auth_message: string; + components: ComponentMeta[]; + css: string | null; + js: string | null; + head: string | null; + dependencies: Dependency[]; + dev_mode: boolean; + enable_queue: boolean; + show_error: boolean; + layout: any; + mode: "blocks" | "interface"; + root: string; + root_url?: string; + theme: string; + title: string; + version: string; + space_id: string | null; + is_space: boolean; + is_colab: boolean; + show_api: boolean; + stylesheets: string[]; + path: string; + current_page: string; + page: Record; + pages: [string, string][]; + protocol: "sse_v3" | "sse_v2.1" | "sse_v2" | "sse_v1" | "sse" | "ws"; + max_file_size?: number; + theme_hash?: number; + username: string | null; + api_prefix?: string; + fill_height?: boolean; + fill_width?: boolean; + pwa?: boolean; +} +export interface ComponentMeta { + type: string; + id: number; + has_modes: boolean; + props: SharedProps; + instance: SvelteComponent; + component: ComponentType; + documentation?: Documentation; + children?: ComponentMeta[]; + parent?: ComponentMeta; + value?: any; + component_class_id: string; + key: string | number | null; + rendered_in?: number; +} +interface SharedProps { + elem_id?: string; + elem_classes?: string[]; + components?: string[]; + server_fns?: string[]; + interactive: boolean; + [key: string]: unknown; + root_url?: string; +} +export interface Documentation { + type?: TypeDescription; + description?: TypeDescription; + example_data?: string; +} +interface TypeDescription { + input_payload?: string; + response_object?: string; + payload?: string; +} +export interface Dependency { + id: number; + targets: [number, string][]; + inputs: number[]; + outputs: number[]; + backend_fn: boolean; + js: string | null; + scroll_to_output: boolean; + trigger: "click" | "load" | string; + max_batch_size: number; + show_progress: "full" | "minimal" | "hidden"; + show_progress_on: number[] | null; + frontend_fn: ((...args: unknown[]) => Promise) | null; + status?: string; + queue: boolean | null; + every: number | null; + batch: boolean; + api_name: string | null; + cancels: number[]; + types: DependencyTypes; + collects_event_data: boolean; + pending_request?: boolean; + trigger_after?: number; + trigger_only_on_success?: boolean; + trigger_mode: "once" | "multiple" | "always_last"; + final_event: Payload | null; + show_api: boolean; + rendered_in: number | null; + render_id: number | null; + connection: "stream" | "sse"; + time_limit: number; + stream_every: number; + like_user_message: boolean; + event_specific_args: string[]; + js_implementation: string | null; +} +export interface DependencyTypes { + generator: boolean; + cancel: boolean; +} +export interface Payload { + fn_index: number; + data: unknown[]; + time?: Date; + event_data?: unknown; + trigger_id?: number | null; +} +export interface PostResponse { + error?: string; + [x: string]: any; +} +export interface UploadResponse { + error?: string; + files?: string[]; +} +export interface DuplicateOptions extends ClientOptions { + private?: boolean; + hardware?: (typeof hardware_types)[number]; + timeout?: number; +} +export interface ClientOptions { + hf_token?: `hf_${string}`; + status_callback?: SpaceStatusCallback | null; + auth?: [string, string] | null; + with_null_state?: boolean; + events?: EventType[]; + headers?: Record; + query_params?: Record; +} +export interface FileData { + name: string; + orig_name?: string; + size?: number; + data: string; + blob?: File; + is_file?: boolean; + mime_type?: string; + alt_text?: string; +} +export type EventType = "data" | "status" | "log" | "render"; +export interface EventMap { + data: PayloadMessage; + status: StatusMessage; + log: LogMessage; + render: RenderMessage; +} +export type GradioEvent = { + [P in EventType]: EventMap[P]; +}[EventType]; +export interface Log { + log: string; + title: string; + level: "warning" | "info" | "success"; +} +export interface Render { + data: { + components: any[]; + layout: any; + dependencies: Dependency[]; + render_id: number; + }; +} +export interface Status { + queue: boolean; + code?: string; + success?: boolean; + stage: "pending" | "error" | "complete" | "generating" | "streaming"; + duration?: number; + visible?: boolean; + broken?: boolean; + size?: number; + position?: number; + eta?: number; + title?: string; + message?: string; + progress_data?: { + progress: number | null; + index: number | null; + length: number | null; + unit: string | null; + desc: string | null; + }[]; + time?: Date; + changed_state_ids?: number[]; + time_limit?: number; +} +export interface StatusMessage extends Status { + type: "status"; + endpoint: string; + fn_index: number; + original_msg?: string; +} +export interface PayloadMessage extends Payload { + type: "data"; + endpoint: string; + fn_index: number; +} +export interface LogMessage extends Log { + type: "log"; + endpoint: string; + fn_index: number; + duration: number | null; + visible: boolean; +} +export interface RenderMessage extends Render { + type: "render"; + endpoint: string; + fn_index: number; +} +export {}; +//# sourceMappingURL=types.d.ts.map \ No newline at end of file diff --git a/node_modules/@gradio/client/dist/types.d.ts.map b/node_modules/@gradio/client/dist/types.d.ts.map new file mode 100644 index 0000000000000000000000000000000000000000..2a33ff585b8bac362def71a1b9e20fc0fb1060f6 --- /dev/null +++ b/node_modules/@gradio/client/dist/types.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/node_modules/@gradio/client/dist/upload.d.ts b/node_modules/@gradio/client/dist/upload.d.ts new file mode 100644 index 0000000000000000000000000000000000000000..892975493f6e18597ac9a9db764e9f16e2b18644 --- /dev/null +++ b/node_modules/@gradio/client/dist/upload.d.ts @@ -0,0 +1,29 @@ +import type { Client } from "./client"; +export declare function upload(this: Client, file_data: FileData[], root_url: string, upload_id?: string, max_file_size?: number): Promise<(FileData | null)[] | null>; +export declare function prepare_files(files: File[], is_stream?: boolean): Promise; +export declare class FileData { + path: string; + url?: string; + orig_name?: string; + size?: number; + blob?: File; + is_stream?: boolean; + mime_type?: string; + alt_text?: string; + b64?: string; + readonly meta: { + _type: string; + }; + constructor({ path, url, orig_name, size, blob, is_stream, mime_type, alt_text, b64 }: { + path: string; + url?: string; + orig_name?: string; + size?: number; + blob?: File; + is_stream?: boolean; + mime_type?: string; + alt_text?: string; + b64?: string; + }); +} +//# sourceMappingURL=upload.d.ts.map \ No newline at end of file diff --git a/node_modules/@gradio/client/dist/upload.d.ts.map b/node_modules/@gradio/client/dist/upload.d.ts.map new file mode 100644 index 0000000000000000000000000000000000000000..a208f2332b9932d9bab03eff5840bb91b8090dca --- /dev/null +++ b/node_modules/@gradio/client/dist/upload.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"upload.d.ts","sourceRoot":"","sources":["../src/upload.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAEvC,wBAAsB,MAAM,CAC3B,IAAI,EAAE,MAAM,EACZ,SAAS,EAAE,QAAQ,EAAE,EACrB,QAAQ,EAAE,MAAM,EAChB,SAAS,CAAC,EAAE,MAAM,EAClB,aAAa,CAAC,EAAE,MAAM,GACpB,OAAO,CAAC,CAAC,QAAQ,GAAG,IAAI,CAAC,EAAE,GAAG,IAAI,CAAC,CAsCrC;AAED,wBAAsB,aAAa,CAClC,KAAK,EAAE,IAAI,EAAE,EACb,SAAS,CAAC,EAAE,OAAO,GACjB,OAAO,CAAC,QAAQ,EAAE,CAAC,CAYrB;AAED,qBAAa,QAAQ;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,IAAI,CAAC;IACZ,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,IAAI;;MAAgC;gBAEjC,EACX,IAAI,EACJ,GAAG,EACH,SAAS,EACT,IAAI,EACJ,IAAI,EACJ,SAAS,EACT,SAAS,EACT,QAAQ,EACR,GAAG,EACH,EAAE;QACF,IAAI,EAAE,MAAM,CAAC;QACb,GAAG,CAAC,EAAE,MAAM,CAAC;QACb,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,IAAI,CAAC,EAAE,IAAI,CAAC;QACZ,SAAS,CAAC,EAAE,OAAO,CAAC;QACpB,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,GAAG,CAAC,EAAE,MAAM,CAAC;KACb;CAWD"} \ No newline at end of file diff --git a/node_modules/@gradio/client/dist/utils/duplicate.d.ts b/node_modules/@gradio/client/dist/utils/duplicate.d.ts new file mode 100644 index 0000000000000000000000000000000000000000..2db4e1f6aed77c8ef0ac705cf467fd8d0c3a1083 --- /dev/null +++ b/node_modules/@gradio/client/dist/utils/duplicate.d.ts @@ -0,0 +1,4 @@ +import type { DuplicateOptions } from "../types"; +import { Client } from "../client"; +export declare function duplicate(app_reference: string, options: DuplicateOptions): Promise; +//# sourceMappingURL=duplicate.d.ts.map \ No newline at end of file diff --git a/node_modules/@gradio/client/dist/utils/duplicate.d.ts.map b/node_modules/@gradio/client/dist/utils/duplicate.d.ts.map new file mode 100644 index 0000000000000000000000000000000000000000..d13451ab2c1d2b1adddcb79165b1d936e3e384d6 --- /dev/null +++ b/node_modules/@gradio/client/dist/utils/duplicate.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"duplicate.d.ts","sourceRoot":"","sources":["../../src/utils/duplicate.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAC;AACjD,OAAO,EAAE,MAAM,EAAE,MAAM,WAAW,CAAC;AAQnC,wBAAsB,SAAS,CAC9B,aAAa,EAAE,MAAM,EACrB,OAAO,EAAE,gBAAgB,GACvB,OAAO,CAAC,MAAM,CAAC,CAuGjB"} \ No newline at end of file diff --git a/node_modules/@gradio/client/dist/utils/handle_blob.d.ts b/node_modules/@gradio/client/dist/utils/handle_blob.d.ts new file mode 100644 index 0000000000000000000000000000000000000000..42fb43d0da8c8506c52ec47bd0196163f7f359a9 --- /dev/null +++ b/node_modules/@gradio/client/dist/utils/handle_blob.d.ts @@ -0,0 +1,5 @@ +import { type ApiData, type EndpointInfo, type JsApiData } from "../types"; +import type { Client } from ".."; +export declare function handle_blob(this: Client, endpoint: string, data: unknown[], api_info: EndpointInfo): Promise; +export declare function process_local_file_commands(client: Client, data: unknown[]): Promise; +//# sourceMappingURL=handle_blob.d.ts.map \ No newline at end of file diff --git a/node_modules/@gradio/client/dist/utils/handle_blob.d.ts.map b/node_modules/@gradio/client/dist/utils/handle_blob.d.ts.map new file mode 100644 index 0000000000000000000000000000000000000000..29557a50daf7e5f663c0a2a42bfa02f7dc98513e --- /dev/null +++ b/node_modules/@gradio/client/dist/utils/handle_blob.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"handle_blob.d.ts","sourceRoot":"","sources":["../../src/utils/handle_blob.ts"],"names":[],"mappings":"AACA,OAAO,EAEN,KAAK,OAAO,EACZ,KAAK,YAAY,EACjB,KAAK,SAAS,EACd,MAAM,UAAU,CAAC;AAElB,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,IAAI,CAAC;AAOjC,wBAAsB,WAAW,CAChC,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,OAAO,EAAE,EACf,QAAQ,EAAE,YAAY,CAAC,SAAS,GAAG,OAAO,CAAC,GACzC,OAAO,CAAC,OAAO,EAAE,CAAC,CAyCpB;AAED,wBAAsB,2BAA2B,CAChD,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,OAAO,EAAE,GACb,OAAO,CAAC,IAAI,CAAC,CAQf"} \ No newline at end of file diff --git a/node_modules/@gradio/client/dist/utils/post_data.d.ts b/node_modules/@gradio/client/dist/utils/post_data.d.ts new file mode 100644 index 0000000000000000000000000000000000000000..b08b61ae99d1c05d29b14f7413bc36358379e271 --- /dev/null +++ b/node_modules/@gradio/client/dist/utils/post_data.d.ts @@ -0,0 +1,4 @@ +import type { PostResponse } from "../types"; +import { Client } from ".."; +export declare function post_data(this: Client, url: string, body: unknown, additional_headers?: any): Promise<[PostResponse, number]>; +//# sourceMappingURL=post_data.d.ts.map \ No newline at end of file diff --git a/node_modules/@gradio/client/dist/utils/post_data.d.ts.map b/node_modules/@gradio/client/dist/utils/post_data.d.ts.map new file mode 100644 index 0000000000000000000000000000000000000000..1803a88c5bbdaeb717922e5e1d82d7b4d623a0c5 --- /dev/null +++ b/node_modules/@gradio/client/dist/utils/post_data.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"post_data.d.ts","sourceRoot":"","sources":["../../src/utils/post_data.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AAC7C,OAAO,EAAE,MAAM,EAAE,MAAM,IAAI,CAAC;AAE5B,wBAAsB,SAAS,CAC9B,IAAI,EAAE,MAAM,EACZ,GAAG,EAAE,MAAM,EACX,IAAI,EAAE,OAAO,EACb,kBAAkB,CAAC,EAAE,GAAG,GACtB,OAAO,CAAC,CAAC,YAAY,EAAE,MAAM,CAAC,CAAC,CA4BjC"} \ No newline at end of file diff --git a/node_modules/@gradio/client/dist/utils/predict.d.ts b/node_modules/@gradio/client/dist/utils/predict.d.ts new file mode 100644 index 0000000000000000000000000000000000000000..02027a2f5f9088a9a30616001693e22b448c8fd5 --- /dev/null +++ b/node_modules/@gradio/client/dist/utils/predict.d.ts @@ -0,0 +1,4 @@ +import { Client } from "../client"; +import type { PredictReturn } from "../types"; +export declare function predict(this: Client, endpoint: string | number, data?: unknown[] | Record): Promise; +//# sourceMappingURL=predict.d.ts.map \ No newline at end of file diff --git a/node_modules/@gradio/client/dist/utils/predict.d.ts.map b/node_modules/@gradio/client/dist/utils/predict.d.ts.map new file mode 100644 index 0000000000000000000000000000000000000000..a5d1bc408794e8d881b1ea1cf3cc70dbbac77597 --- /dev/null +++ b/node_modules/@gradio/client/dist/utils/predict.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"predict.d.ts","sourceRoot":"","sources":["../../src/utils/predict.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,WAAW,CAAC;AACnC,OAAO,KAAK,EAAc,aAAa,EAAE,MAAM,UAAU,CAAC;AAE1D,wBAAsB,OAAO,CAC5B,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,MAAM,GAAG,MAAM,EACzB,IAAI,GAAE,OAAO,EAAE,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM,GAC5C,OAAO,CAAC,aAAa,CAAC,CA2CxB"} \ No newline at end of file diff --git a/node_modules/@gradio/client/dist/utils/stream.d.ts b/node_modules/@gradio/client/dist/utils/stream.d.ts new file mode 100644 index 0000000000000000000000000000000000000000..de5337bc3cba1b86bb38f2d0be720bd68b150d9d --- /dev/null +++ b/node_modules/@gradio/client/dist/utils/stream.d.ts @@ -0,0 +1,9 @@ +import type { Client } from "../client"; +export declare function open_stream(this: Client): Promise; +export declare function close_stream(stream_status: { + open: boolean; +}, abort_controller: AbortController | null): void; +export declare function apply_diff_stream(pending_diff_streams: Record, event_id: string, data: any): void; +export declare function apply_diff(obj: any, diff: [string, (number | string)[], any][]): any; +export declare function readable_stream(input: RequestInfo | URL, init?: RequestInit): EventSource; +//# sourceMappingURL=stream.d.ts.map \ No newline at end of file diff --git a/node_modules/@gradio/client/dist/utils/stream.d.ts.map b/node_modules/@gradio/client/dist/utils/stream.d.ts.map new file mode 100644 index 0000000000000000000000000000000000000000..2b4217b1d8efc3f614e1d95749ad9ec19ba89f80 --- /dev/null +++ b/node_modules/@gradio/client/dist/utils/stream.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"stream.d.ts","sourceRoot":"","sources":["../../src/utils/stream.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,WAAW,CAAC;AAGxC,wBAAsB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAmF7D;AAED,wBAAgB,YAAY,CAC3B,aAAa,EAAE;IAAE,IAAI,EAAE,OAAO,CAAA;CAAE,EAChC,gBAAgB,EAAE,eAAe,GAAG,IAAI,GACtC,IAAI,CAKN;AAED,wBAAgB,iBAAiB,CAChC,oBAAoB,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,EAAE,EAAE,CAAC,EAC7C,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,GAAG,GACP,IAAI,CAcN;AAED,wBAAgB,UAAU,CACzB,GAAG,EAAE,GAAG,EACR,IAAI,EAAE,CAAC,MAAM,EAAE,CAAC,MAAM,GAAG,MAAM,CAAC,EAAE,EAAE,GAAG,CAAC,EAAE,GACxC,GAAG,CAML;AAkDD,wBAAgB,eAAe,CAC9B,KAAK,EAAE,WAAW,GAAG,GAAG,EACxB,IAAI,GAAE,WAAgB,GACpB,WAAW,CA8Cb"} \ No newline at end of file diff --git a/node_modules/@gradio/client/dist/utils/submit.d.ts b/node_modules/@gradio/client/dist/utils/submit.d.ts new file mode 100644 index 0000000000000000000000000000000000000000..b62e7191c6a27f6c8bc1543ba58f78ebd4270fed --- /dev/null +++ b/node_modules/@gradio/client/dist/utils/submit.d.ts @@ -0,0 +1,4 @@ +import type { GradioEvent, SubmitIterable } from "../types"; +import { Client } from "../client"; +export declare function submit(this: Client, endpoint: string | number, data?: unknown[] | Record, event_data?: unknown, trigger_id?: number | null, all_events?: boolean): SubmitIterable; +//# sourceMappingURL=submit.d.ts.map \ No newline at end of file diff --git a/node_modules/@gradio/client/dist/utils/submit.d.ts.map b/node_modules/@gradio/client/dist/utils/submit.d.ts.map new file mode 100644 index 0000000000000000000000000000000000000000..8ea6467cd05aaf04ca44311876a8b067855c5fb4 --- /dev/null +++ b/node_modules/@gradio/client/dist/utils/submit.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"submit.d.ts","sourceRoot":"","sources":["../../src/utils/submit.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAGX,WAAW,EAMX,cAAc,EACd,MAAM,UAAU,CAAC;AAmBlB,OAAO,EAAE,MAAM,EAAE,MAAM,WAAW,CAAC;AAEnC,wBAAgB,MAAM,CACrB,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,MAAM,GAAG,MAAM,EACzB,IAAI,GAAE,OAAO,EAAE,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM,EAC9C,UAAU,CAAC,EAAE,OAAO,EACpB,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,EAC1B,UAAU,CAAC,EAAE,OAAO,GAClB,cAAc,CAAC,WAAW,CAAC,CA2wB7B"} \ No newline at end of file diff --git a/node_modules/@gradio/client/dist/utils/upload_files.d.ts b/node_modules/@gradio/client/dist/utils/upload_files.d.ts new file mode 100644 index 0000000000000000000000000000000000000000..9696aae9fd3e8cd1d7e4eb0fe2927430d37a692f --- /dev/null +++ b/node_modules/@gradio/client/dist/utils/upload_files.d.ts @@ -0,0 +1,4 @@ +import type { Client } from ".."; +import type { UploadResponse } from "../types"; +export declare function upload_files(this: Client, root_url: string, files: (Blob | File)[], upload_id?: string): Promise; +//# sourceMappingURL=upload_files.d.ts.map \ No newline at end of file diff --git a/node_modules/@gradio/client/dist/utils/upload_files.d.ts.map b/node_modules/@gradio/client/dist/utils/upload_files.d.ts.map new file mode 100644 index 0000000000000000000000000000000000000000..a73856c66c15eb074dba1d2b737104dcd40aae62 --- /dev/null +++ b/node_modules/@gradio/client/dist/utils/upload_files.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"upload_files.d.ts","sourceRoot":"","sources":["../../src/utils/upload_files.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,IAAI,CAAC;AAEjC,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AAE/C,wBAAsB,YAAY,CACjC,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,CAAC,IAAI,GAAG,IAAI,CAAC,EAAE,EACtB,SAAS,CAAC,EAAE,MAAM,GAChB,OAAO,CAAC,cAAc,CAAC,CA0CzB"} \ No newline at end of file diff --git a/node_modules/@gradio/client/dist/utils/view_api.d.ts b/node_modules/@gradio/client/dist/utils/view_api.d.ts new file mode 100644 index 0000000000000000000000000000000000000000..0110c2bf57fa9f618868c490c5df71d8e2906ee7 --- /dev/null +++ b/node_modules/@gradio/client/dist/utils/view_api.d.ts @@ -0,0 +1,3 @@ +import { Client } from "../client"; +export declare function view_api(this: Client): Promise; +//# sourceMappingURL=view_api.d.ts.map \ No newline at end of file diff --git a/node_modules/@gradio/client/dist/utils/view_api.d.ts.map b/node_modules/@gradio/client/dist/utils/view_api.d.ts.map new file mode 100644 index 0000000000000000000000000000000000000000..0af83277d0ebedd5c1cd05e71c0ca807be4b929a --- /dev/null +++ b/node_modules/@gradio/client/dist/utils/view_api.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"view_api.d.ts","sourceRoot":"","sources":["../../src/utils/view_api.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,MAAM,EAAE,MAAM,WAAW,CAAC;AAInC,wBAAsB,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,CA+DzD"} \ No newline at end of file diff --git a/node_modules/@gradio/client/dist/wrapper-CviSselG.js b/node_modules/@gradio/client/dist/wrapper-CviSselG.js new file mode 100644 index 0000000000000000000000000000000000000000..f8f357ba505fbfd749fa757bd944f3d02b654031 --- /dev/null +++ b/node_modules/@gradio/client/dist/wrapper-CviSselG.js @@ -0,0 +1,3699 @@ +import require$$0 from "stream"; +import require$$0$2 from "zlib"; +import require$$0$1 from "fs"; +import require$$1$1 from "path"; +import require$$2 from "os"; +import require$$0$3 from "buffer"; +import require$$3 from "net"; +import require$$4 from "tls"; +import require$$5 from "crypto"; +import require$$0$4 from "events"; +import require$$1$2 from "https"; +import require$$2$1 from "http"; +import require$$7 from "url"; +function getDefaultExportFromCjs(x) { + return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, "default") ? x["default"] : x; +} +function getAugmentedNamespace(n) { + if (n.__esModule) + return n; + var f = n.default; + if (typeof f == "function") { + var a = function a2() { + if (this instanceof a2) { + 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; +} +const { Duplex } = require$$0; +function emitClose$1(stream2) { + stream2.emit("close"); +} +function duplexOnEnd() { + if (!this.destroyed && this._writableState.finished) { + this.destroy(); + } +} +function duplexOnError(err) { + this.removeListener("error", duplexOnError); + this.destroy(); + if (this.listenerCount("error") === 0) { + this.emit("error", err); + } +} +function createWebSocketStream(ws, options) { + let terminateOnDestroy = true; + const duplex = new Duplex({ + ...options, + autoDestroy: false, + emitClose: false, + objectMode: false, + writableObjectMode: false + }); + ws.on("message", function message(msg, isBinary) { + const data = !isBinary && duplex._readableState.objectMode ? msg.toString() : msg; + if (!duplex.push(data)) + ws.pause(); + }); + ws.once("error", function error2(err) { + if (duplex.destroyed) + return; + terminateOnDestroy = false; + duplex.destroy(err); + }); + ws.once("close", function close() { + if (duplex.destroyed) + return; + duplex.push(null); + }); + duplex._destroy = function(err, callback) { + if (ws.readyState === ws.CLOSED) { + callback(err); + process.nextTick(emitClose$1, duplex); + return; + } + let called = false; + ws.once("error", function error2(err2) { + called = true; + callback(err2); + }); + ws.once("close", function close() { + if (!called) + callback(err); + process.nextTick(emitClose$1, duplex); + }); + if (terminateOnDestroy) + ws.terminate(); + }; + duplex._final = function(callback) { + if (ws.readyState === ws.CONNECTING) { + ws.once("open", function open() { + duplex._final(callback); + }); + return; + } + if (ws._socket === null) + return; + if (ws._socket._writableState.finished) { + callback(); + if (duplex._readableState.endEmitted) + duplex.destroy(); + } else { + ws._socket.once("finish", function finish() { + callback(); + }); + ws.close(); + } + }; + duplex._read = function() { + if (ws.isPaused) + ws.resume(); + }; + duplex._write = function(chunk, encoding, callback) { + if (ws.readyState === ws.CONNECTING) { + ws.once("open", function open() { + duplex._write(chunk, encoding, callback); + }); + return; + } + ws.send(chunk, callback); + }; + duplex.on("end", duplexOnEnd); + duplex.on("error", duplexOnError); + return duplex; +} +var stream = createWebSocketStream; +const stream$1 = /* @__PURE__ */ getDefaultExportFromCjs(stream); +var bufferUtil$1 = { exports: {} }; +var constants = { + BINARY_TYPES: ["nodebuffer", "arraybuffer", "fragments"], + EMPTY_BUFFER: Buffer.alloc(0), + GUID: "258EAFA5-E914-47DA-95CA-C5AB0DC85B11", + kForOnEventAttribute: Symbol("kIsForOnEventAttribute"), + kListener: Symbol("kListener"), + kStatusCode: Symbol("status-code"), + kWebSocket: Symbol("websocket"), + NOOP: () => { + } +}; +var bufferutil = { exports: {} }; +var nodeGypBuild$1 = { exports: {} }; +function commonjsRequire(path) { + throw new Error('Could not dynamically require "' + path + '". Please configure the dynamicRequireTargets or/and ignoreDynamicRequires option of @rollup/plugin-commonjs appropriately for this require call to work.'); +} +var nodeGypBuild; +var hasRequiredNodeGypBuild$1; +function requireNodeGypBuild$1() { + if (hasRequiredNodeGypBuild$1) + return nodeGypBuild; + hasRequiredNodeGypBuild$1 = 1; + var fs = require$$0$1; + var path = require$$1$1; + var os = require$$2; + var runtimeRequire = typeof __webpack_require__ === "function" ? __non_webpack_require__ : commonjsRequire; + var vars = process.config && process.config.variables || {}; + var prebuildsOnly = !!process.env.PREBUILDS_ONLY; + var abi = process.versions.modules; + var runtime = isElectron() ? "electron" : isNwjs() ? "node-webkit" : "node"; + var arch = process.env.npm_config_arch || os.arch(); + var platform = process.env.npm_config_platform || os.platform(); + var libc = process.env.LIBC || (isAlpine(platform) ? "musl" : "glibc"); + var armv = process.env.ARM_VERSION || (arch === "arm64" ? "8" : vars.arm_version) || ""; + var uv = (process.versions.uv || "").split(".")[0]; + nodeGypBuild = load; + function load(dir) { + return runtimeRequire(load.resolve(dir)); + } + load.resolve = load.path = function(dir) { + dir = path.resolve(dir || "."); + try { + var name = runtimeRequire(path.join(dir, "package.json")).name.toUpperCase().replace(/-/g, "_"); + if (process.env[name + "_PREBUILD"]) + dir = process.env[name + "_PREBUILD"]; + } catch (err) { + } + if (!prebuildsOnly) { + var release = getFirst(path.join(dir, "build/Release"), matchBuild); + if (release) + return release; + var debug = getFirst(path.join(dir, "build/Debug"), matchBuild); + if (debug) + return debug; + } + var prebuild = resolve(dir); + if (prebuild) + return prebuild; + var nearby = resolve(path.dirname(process.execPath)); + if (nearby) + return nearby; + var target = [ + "platform=" + platform, + "arch=" + arch, + "runtime=" + runtime, + "abi=" + abi, + "uv=" + uv, + armv ? "armv=" + armv : "", + "libc=" + libc, + "node=" + process.versions.node, + process.versions.electron ? "electron=" + process.versions.electron : "", + typeof __webpack_require__ === "function" ? "webpack=true" : "" + // eslint-disable-line + ].filter(Boolean).join(" "); + throw new Error("No native build was found for " + target + "\n loaded from: " + dir + "\n"); + function resolve(dir2) { + var tuples = readdirSync(path.join(dir2, "prebuilds")).map(parseTuple); + var tuple = tuples.filter(matchTuple(platform, arch)).sort(compareTuples)[0]; + if (!tuple) + return; + var prebuilds = path.join(dir2, "prebuilds", tuple.name); + var parsed = readdirSync(prebuilds).map(parseTags); + var candidates = parsed.filter(matchTags(runtime, abi)); + var winner = candidates.sort(compareTags(runtime))[0]; + if (winner) + return path.join(prebuilds, winner.file); + } + }; + function readdirSync(dir) { + try { + return fs.readdirSync(dir); + } catch (err) { + return []; + } + } + function getFirst(dir, filter) { + var files = readdirSync(dir).filter(filter); + return files[0] && path.join(dir, files[0]); + } + function matchBuild(name) { + return /\.node$/.test(name); + } + function parseTuple(name) { + var arr = name.split("-"); + if (arr.length !== 2) + return; + var platform2 = arr[0]; + var architectures = arr[1].split("+"); + if (!platform2) + return; + if (!architectures.length) + return; + if (!architectures.every(Boolean)) + return; + return { name, platform: platform2, architectures }; + } + function matchTuple(platform2, arch2) { + return function(tuple) { + if (tuple == null) + return false; + if (tuple.platform !== platform2) + return false; + return tuple.architectures.includes(arch2); + }; + } + function compareTuples(a, b) { + return a.architectures.length - b.architectures.length; + } + function parseTags(file) { + var arr = file.split("."); + var extension2 = arr.pop(); + var tags = { file, specificity: 0 }; + if (extension2 !== "node") + return; + for (var i = 0; i < arr.length; i++) { + var tag = arr[i]; + if (tag === "node" || tag === "electron" || tag === "node-webkit") { + tags.runtime = tag; + } else if (tag === "napi") { + tags.napi = true; + } else if (tag.slice(0, 3) === "abi") { + tags.abi = tag.slice(3); + } else if (tag.slice(0, 2) === "uv") { + tags.uv = tag.slice(2); + } else if (tag.slice(0, 4) === "armv") { + tags.armv = tag.slice(4); + } else if (tag === "glibc" || tag === "musl") { + tags.libc = tag; + } else { + continue; + } + tags.specificity++; + } + return tags; + } + function matchTags(runtime2, abi2) { + return function(tags) { + if (tags == null) + return false; + if (tags.runtime !== runtime2 && !runtimeAgnostic(tags)) + return false; + if (tags.abi !== abi2 && !tags.napi) + return false; + if (tags.uv && tags.uv !== uv) + return false; + if (tags.armv && tags.armv !== armv) + return false; + if (tags.libc && tags.libc !== libc) + return false; + return true; + }; + } + function runtimeAgnostic(tags) { + return tags.runtime === "node" && tags.napi; + } + function compareTags(runtime2) { + return function(a, b) { + if (a.runtime !== b.runtime) { + return a.runtime === runtime2 ? -1 : 1; + } else if (a.abi !== b.abi) { + return a.abi ? -1 : 1; + } else if (a.specificity !== b.specificity) { + return a.specificity > b.specificity ? -1 : 1; + } else { + return 0; + } + }; + } + function isNwjs() { + return !!(process.versions && process.versions.nw); + } + function isElectron() { + if (process.versions && process.versions.electron) + return true; + if (process.env.ELECTRON_RUN_AS_NODE) + return true; + return typeof window !== "undefined" && window.process && window.process.type === "renderer"; + } + function isAlpine(platform2) { + return platform2 === "linux" && fs.existsSync("/etc/alpine-release"); + } + load.parseTags = parseTags; + load.matchTags = matchTags; + load.compareTags = compareTags; + load.parseTuple = parseTuple; + load.matchTuple = matchTuple; + load.compareTuples = compareTuples; + return nodeGypBuild; +} +var hasRequiredNodeGypBuild; +function requireNodeGypBuild() { + if (hasRequiredNodeGypBuild) + return nodeGypBuild$1.exports; + hasRequiredNodeGypBuild = 1; + if (typeof process.addon === "function") { + nodeGypBuild$1.exports = process.addon.bind(process); + } else { + nodeGypBuild$1.exports = requireNodeGypBuild$1(); + } + return nodeGypBuild$1.exports; +} +var fallback; +var hasRequiredFallback; +function requireFallback() { + if (hasRequiredFallback) + return fallback; + hasRequiredFallback = 1; + const mask2 = (source, mask3, output, offset, length) => { + for (var i = 0; i < length; i++) { + output[offset + i] = source[i] ^ mask3[i & 3]; + } + }; + const unmask2 = (buffer, mask3) => { + const length = buffer.length; + for (var i = 0; i < length; i++) { + buffer[i] ^= mask3[i & 3]; + } + }; + fallback = { mask: mask2, unmask: unmask2 }; + return fallback; +} +var hasRequiredBufferutil; +function requireBufferutil() { + if (hasRequiredBufferutil) + return bufferutil.exports; + hasRequiredBufferutil = 1; + try { + bufferutil.exports = requireNodeGypBuild()(__dirname); + } catch (e) { + bufferutil.exports = requireFallback(); + } + return bufferutil.exports; +} +var unmask$1; +var mask; +const { EMPTY_BUFFER: EMPTY_BUFFER$3 } = constants; +const FastBuffer$2 = Buffer[Symbol.species]; +function concat$1(list, totalLength) { + if (list.length === 0) + return EMPTY_BUFFER$3; + if (list.length === 1) + return list[0]; + const target = Buffer.allocUnsafe(totalLength); + let offset = 0; + for (let i = 0; i < list.length; i++) { + const buf = list[i]; + target.set(buf, offset); + offset += buf.length; + } + if (offset < totalLength) { + return new FastBuffer$2(target.buffer, target.byteOffset, offset); + } + return target; +} +function _mask(source, mask2, output, offset, length) { + for (let i = 0; i < length; i++) { + output[offset + i] = source[i] ^ mask2[i & 3]; + } +} +function _unmask(buffer, mask2) { + for (let i = 0; i < buffer.length; i++) { + buffer[i] ^= mask2[i & 3]; + } +} +function toArrayBuffer$1(buf) { + if (buf.length === buf.buffer.byteLength) { + return buf.buffer; + } + return buf.buffer.slice(buf.byteOffset, buf.byteOffset + buf.length); +} +function toBuffer$2(data) { + toBuffer$2.readOnly = true; + if (Buffer.isBuffer(data)) + return data; + let buf; + if (data instanceof ArrayBuffer) { + buf = new FastBuffer$2(data); + } else if (ArrayBuffer.isView(data)) { + buf = new FastBuffer$2(data.buffer, data.byteOffset, data.byteLength); + } else { + buf = Buffer.from(data); + toBuffer$2.readOnly = false; + } + return buf; +} +bufferUtil$1.exports = { + concat: concat$1, + mask: _mask, + toArrayBuffer: toArrayBuffer$1, + toBuffer: toBuffer$2, + unmask: _unmask +}; +if (!process.env.WS_NO_BUFFER_UTIL) { + try { + const bufferUtil2 = requireBufferutil(); + mask = bufferUtil$1.exports.mask = function(source, mask2, output, offset, length) { + if (length < 48) + _mask(source, mask2, output, offset, length); + else + bufferUtil2.mask(source, mask2, output, offset, length); + }; + unmask$1 = bufferUtil$1.exports.unmask = function(buffer, mask2) { + if (buffer.length < 32) + _unmask(buffer, mask2); + else + bufferUtil2.unmask(buffer, mask2); + }; + } catch (e) { + } +} +var bufferUtilExports = bufferUtil$1.exports; +const kDone = Symbol("kDone"); +const kRun = Symbol("kRun"); +let Limiter$1 = class Limiter { + /** + * Creates a new `Limiter`. + * + * @param {Number} [concurrency=Infinity] The maximum number of jobs allowed + * to run concurrently + */ + constructor(concurrency) { + this[kDone] = () => { + this.pending--; + this[kRun](); + }; + this.concurrency = concurrency || Infinity; + this.jobs = []; + this.pending = 0; + } + /** + * Adds a job to the queue. + * + * @param {Function} job The job to run + * @public + */ + add(job) { + this.jobs.push(job); + this[kRun](); + } + /** + * Removes a job from the queue and runs it if possible. + * + * @private + */ + [kRun]() { + if (this.pending === this.concurrency) + return; + if (this.jobs.length) { + const job = this.jobs.shift(); + this.pending++; + job(this[kDone]); + } + } +}; +var limiter = Limiter$1; +const zlib = require$$0$2; +const bufferUtil = bufferUtilExports; +const Limiter2 = limiter; +const { kStatusCode: kStatusCode$2 } = constants; +const FastBuffer$1 = Buffer[Symbol.species]; +const TRAILER = Buffer.from([0, 0, 255, 255]); +const kPerMessageDeflate = Symbol("permessage-deflate"); +const kTotalLength = Symbol("total-length"); +const kCallback = Symbol("callback"); +const kBuffers = Symbol("buffers"); +const kError$1 = Symbol("error"); +let zlibLimiter; +let PerMessageDeflate$4 = class PerMessageDeflate { + /** + * Creates a PerMessageDeflate instance. + * + * @param {Object} [options] Configuration options + * @param {(Boolean|Number)} [options.clientMaxWindowBits] Advertise support + * for, or request, a custom client window size + * @param {Boolean} [options.clientNoContextTakeover=false] Advertise/ + * acknowledge disabling of client context takeover + * @param {Number} [options.concurrencyLimit=10] The number of concurrent + * calls to zlib + * @param {(Boolean|Number)} [options.serverMaxWindowBits] Request/confirm the + * use of a custom server window size + * @param {Boolean} [options.serverNoContextTakeover=false] Request/accept + * disabling of server context takeover + * @param {Number} [options.threshold=1024] Size (in bytes) below which + * messages should not be compressed if context takeover is disabled + * @param {Object} [options.zlibDeflateOptions] Options to pass to zlib on + * deflate + * @param {Object} [options.zlibInflateOptions] Options to pass to zlib on + * inflate + * @param {Boolean} [isServer=false] Create the instance in either server or + * client mode + * @param {Number} [maxPayload=0] The maximum allowed message length + */ + constructor(options, isServer, maxPayload) { + this._maxPayload = maxPayload | 0; + this._options = options || {}; + this._threshold = this._options.threshold !== void 0 ? this._options.threshold : 1024; + this._isServer = !!isServer; + this._deflate = null; + this._inflate = null; + this.params = null; + if (!zlibLimiter) { + const concurrency = this._options.concurrencyLimit !== void 0 ? this._options.concurrencyLimit : 10; + zlibLimiter = new Limiter2(concurrency); + } + } + /** + * @type {String} + */ + static get extensionName() { + return "permessage-deflate"; + } + /** + * Create an extension negotiation offer. + * + * @return {Object} Extension parameters + * @public + */ + offer() { + const params = {}; + if (this._options.serverNoContextTakeover) { + params.server_no_context_takeover = true; + } + if (this._options.clientNoContextTakeover) { + params.client_no_context_takeover = true; + } + if (this._options.serverMaxWindowBits) { + params.server_max_window_bits = this._options.serverMaxWindowBits; + } + if (this._options.clientMaxWindowBits) { + params.client_max_window_bits = this._options.clientMaxWindowBits; + } else if (this._options.clientMaxWindowBits == null) { + params.client_max_window_bits = true; + } + return params; + } + /** + * Accept an extension negotiation offer/response. + * + * @param {Array} configurations The extension negotiation offers/reponse + * @return {Object} Accepted configuration + * @public + */ + accept(configurations) { + configurations = this.normalizeParams(configurations); + this.params = this._isServer ? this.acceptAsServer(configurations) : this.acceptAsClient(configurations); + return this.params; + } + /** + * Releases all resources used by the extension. + * + * @public + */ + cleanup() { + if (this._inflate) { + this._inflate.close(); + this._inflate = null; + } + if (this._deflate) { + const callback = this._deflate[kCallback]; + this._deflate.close(); + this._deflate = null; + if (callback) { + callback( + new Error( + "The deflate stream was closed while data was being processed" + ) + ); + } + } + } + /** + * Accept an extension negotiation offer. + * + * @param {Array} offers The extension negotiation offers + * @return {Object} Accepted configuration + * @private + */ + acceptAsServer(offers) { + const opts = this._options; + const accepted = offers.find((params) => { + if (opts.serverNoContextTakeover === false && params.server_no_context_takeover || params.server_max_window_bits && (opts.serverMaxWindowBits === false || typeof opts.serverMaxWindowBits === "number" && opts.serverMaxWindowBits > params.server_max_window_bits) || typeof opts.clientMaxWindowBits === "number" && !params.client_max_window_bits) { + return false; + } + return true; + }); + if (!accepted) { + throw new Error("None of the extension offers can be accepted"); + } + if (opts.serverNoContextTakeover) { + accepted.server_no_context_takeover = true; + } + if (opts.clientNoContextTakeover) { + accepted.client_no_context_takeover = true; + } + if (typeof opts.serverMaxWindowBits === "number") { + accepted.server_max_window_bits = opts.serverMaxWindowBits; + } + if (typeof opts.clientMaxWindowBits === "number") { + accepted.client_max_window_bits = opts.clientMaxWindowBits; + } else if (accepted.client_max_window_bits === true || opts.clientMaxWindowBits === false) { + delete accepted.client_max_window_bits; + } + return accepted; + } + /** + * Accept the extension negotiation response. + * + * @param {Array} response The extension negotiation response + * @return {Object} Accepted configuration + * @private + */ + acceptAsClient(response) { + const params = response[0]; + if (this._options.clientNoContextTakeover === false && params.client_no_context_takeover) { + throw new Error('Unexpected parameter "client_no_context_takeover"'); + } + if (!params.client_max_window_bits) { + if (typeof this._options.clientMaxWindowBits === "number") { + params.client_max_window_bits = this._options.clientMaxWindowBits; + } + } else if (this._options.clientMaxWindowBits === false || typeof this._options.clientMaxWindowBits === "number" && params.client_max_window_bits > this._options.clientMaxWindowBits) { + throw new Error( + 'Unexpected or invalid parameter "client_max_window_bits"' + ); + } + return params; + } + /** + * Normalize parameters. + * + * @param {Array} configurations The extension negotiation offers/reponse + * @return {Array} The offers/response with normalized parameters + * @private + */ + normalizeParams(configurations) { + configurations.forEach((params) => { + Object.keys(params).forEach((key) => { + let value = params[key]; + if (value.length > 1) { + throw new Error(`Parameter "${key}" must have only a single value`); + } + value = value[0]; + if (key === "client_max_window_bits") { + if (value !== true) { + const num = +value; + if (!Number.isInteger(num) || num < 8 || num > 15) { + throw new TypeError( + `Invalid value for parameter "${key}": ${value}` + ); + } + value = num; + } else if (!this._isServer) { + throw new TypeError( + `Invalid value for parameter "${key}": ${value}` + ); + } + } else if (key === "server_max_window_bits") { + const num = +value; + if (!Number.isInteger(num) || num < 8 || num > 15) { + throw new TypeError( + `Invalid value for parameter "${key}": ${value}` + ); + } + value = num; + } else if (key === "client_no_context_takeover" || key === "server_no_context_takeover") { + if (value !== true) { + throw new TypeError( + `Invalid value for parameter "${key}": ${value}` + ); + } + } else { + throw new Error(`Unknown parameter "${key}"`); + } + params[key] = value; + }); + }); + return configurations; + } + /** + * Decompress data. Concurrency limited. + * + * @param {Buffer} data Compressed data + * @param {Boolean} fin Specifies whether or not this is the last fragment + * @param {Function} callback Callback + * @public + */ + decompress(data, fin, callback) { + zlibLimiter.add((done) => { + this._decompress(data, fin, (err, result) => { + done(); + callback(err, result); + }); + }); + } + /** + * Compress data. Concurrency limited. + * + * @param {(Buffer|String)} data Data to compress + * @param {Boolean} fin Specifies whether or not this is the last fragment + * @param {Function} callback Callback + * @public + */ + compress(data, fin, callback) { + zlibLimiter.add((done) => { + this._compress(data, fin, (err, result) => { + done(); + callback(err, result); + }); + }); + } + /** + * Decompress data. + * + * @param {Buffer} data Compressed data + * @param {Boolean} fin Specifies whether or not this is the last fragment + * @param {Function} callback Callback + * @private + */ + _decompress(data, fin, callback) { + const endpoint = this._isServer ? "client" : "server"; + if (!this._inflate) { + const key = `${endpoint}_max_window_bits`; + const windowBits = typeof this.params[key] !== "number" ? zlib.Z_DEFAULT_WINDOWBITS : this.params[key]; + this._inflate = zlib.createInflateRaw({ + ...this._options.zlibInflateOptions, + windowBits + }); + this._inflate[kPerMessageDeflate] = this; + this._inflate[kTotalLength] = 0; + this._inflate[kBuffers] = []; + this._inflate.on("error", inflateOnError); + this._inflate.on("data", inflateOnData); + } + this._inflate[kCallback] = callback; + this._inflate.write(data); + if (fin) + this._inflate.write(TRAILER); + this._inflate.flush(() => { + const err = this._inflate[kError$1]; + if (err) { + this._inflate.close(); + this._inflate = null; + callback(err); + return; + } + const data2 = bufferUtil.concat( + this._inflate[kBuffers], + this._inflate[kTotalLength] + ); + if (this._inflate._readableState.endEmitted) { + this._inflate.close(); + this._inflate = null; + } else { + this._inflate[kTotalLength] = 0; + this._inflate[kBuffers] = []; + if (fin && this.params[`${endpoint}_no_context_takeover`]) { + this._inflate.reset(); + } + } + callback(null, data2); + }); + } + /** + * Compress data. + * + * @param {(Buffer|String)} data Data to compress + * @param {Boolean} fin Specifies whether or not this is the last fragment + * @param {Function} callback Callback + * @private + */ + _compress(data, fin, callback) { + const endpoint = this._isServer ? "server" : "client"; + if (!this._deflate) { + const key = `${endpoint}_max_window_bits`; + const windowBits = typeof this.params[key] !== "number" ? zlib.Z_DEFAULT_WINDOWBITS : this.params[key]; + this._deflate = zlib.createDeflateRaw({ + ...this._options.zlibDeflateOptions, + windowBits + }); + this._deflate[kTotalLength] = 0; + this._deflate[kBuffers] = []; + this._deflate.on("data", deflateOnData); + } + this._deflate[kCallback] = callback; + this._deflate.write(data); + this._deflate.flush(zlib.Z_SYNC_FLUSH, () => { + if (!this._deflate) { + return; + } + let data2 = bufferUtil.concat( + this._deflate[kBuffers], + this._deflate[kTotalLength] + ); + if (fin) { + data2 = new FastBuffer$1(data2.buffer, data2.byteOffset, data2.length - 4); + } + this._deflate[kCallback] = null; + this._deflate[kTotalLength] = 0; + this._deflate[kBuffers] = []; + if (fin && this.params[`${endpoint}_no_context_takeover`]) { + this._deflate.reset(); + } + callback(null, data2); + }); + } +}; +var permessageDeflate = PerMessageDeflate$4; +function deflateOnData(chunk) { + this[kBuffers].push(chunk); + this[kTotalLength] += chunk.length; +} +function inflateOnData(chunk) { + this[kTotalLength] += chunk.length; + if (this[kPerMessageDeflate]._maxPayload < 1 || this[kTotalLength] <= this[kPerMessageDeflate]._maxPayload) { + this[kBuffers].push(chunk); + return; + } + this[kError$1] = new RangeError("Max payload size exceeded"); + this[kError$1].code = "WS_ERR_UNSUPPORTED_MESSAGE_LENGTH"; + this[kError$1][kStatusCode$2] = 1009; + this.removeListener("data", inflateOnData); + this.reset(); +} +function inflateOnError(err) { + this[kPerMessageDeflate]._inflate = null; + err[kStatusCode$2] = 1007; + this[kCallback](err); +} +var validation = { exports: {} }; +const __viteOptionalPeerDep_utf8Validate_ws = {}; +const __viteOptionalPeerDep_utf8Validate_ws$1 = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({ + __proto__: null, + default: __viteOptionalPeerDep_utf8Validate_ws +}, Symbol.toStringTag, { value: "Module" })); +const require$$1 = /* @__PURE__ */ getAugmentedNamespace(__viteOptionalPeerDep_utf8Validate_ws$1); +var isValidUTF8_1; +const { isUtf8 } = require$$0$3; +const tokenChars$2 = [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + // 0 - 15 + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + // 16 - 31 + 0, + 1, + 0, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 1, + 1, + 0, + 1, + 1, + 0, + // 32 - 47 + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + // 48 - 63 + 0, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + // 64 - 79 + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 1, + 1, + // 80 - 95 + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + // 96 - 111 + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 0, + 1, + 0, + 1, + 0 + // 112 - 127 +]; +function isValidStatusCode$2(code) { + return code >= 1e3 && code <= 1014 && code !== 1004 && code !== 1005 && code !== 1006 || code >= 3e3 && code <= 4999; +} +function _isValidUTF8(buf) { + const len = buf.length; + let i = 0; + while (i < len) { + if ((buf[i] & 128) === 0) { + i++; + } else if ((buf[i] & 224) === 192) { + if (i + 1 === len || (buf[i + 1] & 192) !== 128 || (buf[i] & 254) === 192) { + return false; + } + i += 2; + } else if ((buf[i] & 240) === 224) { + if (i + 2 >= len || (buf[i + 1] & 192) !== 128 || (buf[i + 2] & 192) !== 128 || buf[i] === 224 && (buf[i + 1] & 224) === 128 || // Overlong + buf[i] === 237 && (buf[i + 1] & 224) === 160) { + return false; + } + i += 3; + } else if ((buf[i] & 248) === 240) { + if (i + 3 >= len || (buf[i + 1] & 192) !== 128 || (buf[i + 2] & 192) !== 128 || (buf[i + 3] & 192) !== 128 || buf[i] === 240 && (buf[i + 1] & 240) === 128 || // Overlong + buf[i] === 244 && buf[i + 1] > 143 || buf[i] > 244) { + return false; + } + i += 4; + } else { + return false; + } + } + return true; +} +validation.exports = { + isValidStatusCode: isValidStatusCode$2, + isValidUTF8: _isValidUTF8, + tokenChars: tokenChars$2 +}; +if (isUtf8) { + isValidUTF8_1 = validation.exports.isValidUTF8 = function(buf) { + return buf.length < 24 ? _isValidUTF8(buf) : isUtf8(buf); + }; +} else if (!process.env.WS_NO_UTF_8_VALIDATE) { + try { + const isValidUTF82 = require$$1; + isValidUTF8_1 = validation.exports.isValidUTF8 = function(buf) { + return buf.length < 32 ? _isValidUTF8(buf) : isValidUTF82(buf); + }; + } catch (e) { + } +} +var validationExports = validation.exports; +const { Writable } = require$$0; +const PerMessageDeflate$3 = permessageDeflate; +const { + BINARY_TYPES: BINARY_TYPES$1, + EMPTY_BUFFER: EMPTY_BUFFER$2, + kStatusCode: kStatusCode$1, + kWebSocket: kWebSocket$2 +} = constants; +const { concat, toArrayBuffer, unmask } = bufferUtilExports; +const { isValidStatusCode: isValidStatusCode$1, isValidUTF8 } = validationExports; +const FastBuffer = Buffer[Symbol.species]; +const GET_INFO = 0; +const GET_PAYLOAD_LENGTH_16 = 1; +const GET_PAYLOAD_LENGTH_64 = 2; +const GET_MASK = 3; +const GET_DATA = 4; +const INFLATING = 5; +let Receiver$1 = class Receiver extends Writable { + /** + * Creates a Receiver instance. + * + * @param {Object} [options] Options object + * @param {String} [options.binaryType=nodebuffer] The type for binary data + * @param {Object} [options.extensions] An object containing the negotiated + * extensions + * @param {Boolean} [options.isServer=false] Specifies whether to operate in + * client or server mode + * @param {Number} [options.maxPayload=0] The maximum allowed message length + * @param {Boolean} [options.skipUTF8Validation=false] Specifies whether or + * not to skip UTF-8 validation for text and close messages + */ + constructor(options = {}) { + super(); + this._binaryType = options.binaryType || BINARY_TYPES$1[0]; + this._extensions = options.extensions || {}; + this._isServer = !!options.isServer; + this._maxPayload = options.maxPayload | 0; + this._skipUTF8Validation = !!options.skipUTF8Validation; + this[kWebSocket$2] = void 0; + this._bufferedBytes = 0; + this._buffers = []; + this._compressed = false; + this._payloadLength = 0; + this._mask = void 0; + this._fragmented = 0; + this._masked = false; + this._fin = false; + this._opcode = 0; + this._totalPayloadLength = 0; + this._messageLength = 0; + this._fragments = []; + this._state = GET_INFO; + this._loop = false; + } + /** + * Implements `Writable.prototype._write()`. + * + * @param {Buffer} chunk The chunk of data to write + * @param {String} encoding The character encoding of `chunk` + * @param {Function} cb Callback + * @private + */ + _write(chunk, encoding, cb) { + if (this._opcode === 8 && this._state == GET_INFO) + return cb(); + this._bufferedBytes += chunk.length; + this._buffers.push(chunk); + this.startLoop(cb); + } + /** + * Consumes `n` bytes from the buffered data. + * + * @param {Number} n The number of bytes to consume + * @return {Buffer} The consumed bytes + * @private + */ + consume(n) { + this._bufferedBytes -= n; + if (n === this._buffers[0].length) + return this._buffers.shift(); + if (n < this._buffers[0].length) { + const buf = this._buffers[0]; + this._buffers[0] = new FastBuffer( + buf.buffer, + buf.byteOffset + n, + buf.length - n + ); + return new FastBuffer(buf.buffer, buf.byteOffset, n); + } + const dst = Buffer.allocUnsafe(n); + do { + const buf = this._buffers[0]; + const offset = dst.length - n; + if (n >= buf.length) { + dst.set(this._buffers.shift(), offset); + } else { + dst.set(new Uint8Array(buf.buffer, buf.byteOffset, n), offset); + this._buffers[0] = new FastBuffer( + buf.buffer, + buf.byteOffset + n, + buf.length - n + ); + } + n -= buf.length; + } while (n > 0); + return dst; + } + /** + * Starts the parsing loop. + * + * @param {Function} cb Callback + * @private + */ + startLoop(cb) { + let err; + this._loop = true; + do { + switch (this._state) { + case GET_INFO: + err = this.getInfo(); + break; + case GET_PAYLOAD_LENGTH_16: + err = this.getPayloadLength16(); + break; + case GET_PAYLOAD_LENGTH_64: + err = this.getPayloadLength64(); + break; + case GET_MASK: + this.getMask(); + break; + case GET_DATA: + err = this.getData(cb); + break; + default: + this._loop = false; + return; + } + } while (this._loop); + cb(err); + } + /** + * Reads the first two bytes of a frame. + * + * @return {(RangeError|undefined)} A possible error + * @private + */ + getInfo() { + if (this._bufferedBytes < 2) { + this._loop = false; + return; + } + const buf = this.consume(2); + if ((buf[0] & 48) !== 0) { + this._loop = false; + return error( + RangeError, + "RSV2 and RSV3 must be clear", + true, + 1002, + "WS_ERR_UNEXPECTED_RSV_2_3" + ); + } + const compressed = (buf[0] & 64) === 64; + if (compressed && !this._extensions[PerMessageDeflate$3.extensionName]) { + this._loop = false; + return error( + RangeError, + "RSV1 must be clear", + true, + 1002, + "WS_ERR_UNEXPECTED_RSV_1" + ); + } + this._fin = (buf[0] & 128) === 128; + this._opcode = buf[0] & 15; + this._payloadLength = buf[1] & 127; + if (this._opcode === 0) { + if (compressed) { + this._loop = false; + return error( + RangeError, + "RSV1 must be clear", + true, + 1002, + "WS_ERR_UNEXPECTED_RSV_1" + ); + } + if (!this._fragmented) { + this._loop = false; + return error( + RangeError, + "invalid opcode 0", + true, + 1002, + "WS_ERR_INVALID_OPCODE" + ); + } + this._opcode = this._fragmented; + } else if (this._opcode === 1 || this._opcode === 2) { + if (this._fragmented) { + this._loop = false; + return error( + RangeError, + `invalid opcode ${this._opcode}`, + true, + 1002, + "WS_ERR_INVALID_OPCODE" + ); + } + this._compressed = compressed; + } else if (this._opcode > 7 && this._opcode < 11) { + if (!this._fin) { + this._loop = false; + return error( + RangeError, + "FIN must be set", + true, + 1002, + "WS_ERR_EXPECTED_FIN" + ); + } + if (compressed) { + this._loop = false; + return error( + RangeError, + "RSV1 must be clear", + true, + 1002, + "WS_ERR_UNEXPECTED_RSV_1" + ); + } + if (this._payloadLength > 125 || this._opcode === 8 && this._payloadLength === 1) { + this._loop = false; + return error( + RangeError, + `invalid payload length ${this._payloadLength}`, + true, + 1002, + "WS_ERR_INVALID_CONTROL_PAYLOAD_LENGTH" + ); + } + } else { + this._loop = false; + return error( + RangeError, + `invalid opcode ${this._opcode}`, + true, + 1002, + "WS_ERR_INVALID_OPCODE" + ); + } + if (!this._fin && !this._fragmented) + this._fragmented = this._opcode; + this._masked = (buf[1] & 128) === 128; + if (this._isServer) { + if (!this._masked) { + this._loop = false; + return error( + RangeError, + "MASK must be set", + true, + 1002, + "WS_ERR_EXPECTED_MASK" + ); + } + } else if (this._masked) { + this._loop = false; + return error( + RangeError, + "MASK must be clear", + true, + 1002, + "WS_ERR_UNEXPECTED_MASK" + ); + } + if (this._payloadLength === 126) + this._state = GET_PAYLOAD_LENGTH_16; + else if (this._payloadLength === 127) + this._state = GET_PAYLOAD_LENGTH_64; + else + return this.haveLength(); + } + /** + * Gets extended payload length (7+16). + * + * @return {(RangeError|undefined)} A possible error + * @private + */ + getPayloadLength16() { + if (this._bufferedBytes < 2) { + this._loop = false; + return; + } + this._payloadLength = this.consume(2).readUInt16BE(0); + return this.haveLength(); + } + /** + * Gets extended payload length (7+64). + * + * @return {(RangeError|undefined)} A possible error + * @private + */ + getPayloadLength64() { + if (this._bufferedBytes < 8) { + this._loop = false; + return; + } + const buf = this.consume(8); + const num = buf.readUInt32BE(0); + if (num > Math.pow(2, 53 - 32) - 1) { + this._loop = false; + return error( + RangeError, + "Unsupported WebSocket frame: payload length > 2^53 - 1", + false, + 1009, + "WS_ERR_UNSUPPORTED_DATA_PAYLOAD_LENGTH" + ); + } + this._payloadLength = num * Math.pow(2, 32) + buf.readUInt32BE(4); + return this.haveLength(); + } + /** + * Payload length has been read. + * + * @return {(RangeError|undefined)} A possible error + * @private + */ + haveLength() { + if (this._payloadLength && this._opcode < 8) { + this._totalPayloadLength += this._payloadLength; + if (this._totalPayloadLength > this._maxPayload && this._maxPayload > 0) { + this._loop = false; + return error( + RangeError, + "Max payload size exceeded", + false, + 1009, + "WS_ERR_UNSUPPORTED_MESSAGE_LENGTH" + ); + } + } + if (this._masked) + this._state = GET_MASK; + else + this._state = GET_DATA; + } + /** + * Reads mask bytes. + * + * @private + */ + getMask() { + if (this._bufferedBytes < 4) { + this._loop = false; + return; + } + this._mask = this.consume(4); + this._state = GET_DATA; + } + /** + * Reads data bytes. + * + * @param {Function} cb Callback + * @return {(Error|RangeError|undefined)} A possible error + * @private + */ + getData(cb) { + let data = EMPTY_BUFFER$2; + if (this._payloadLength) { + if (this._bufferedBytes < this._payloadLength) { + this._loop = false; + return; + } + data = this.consume(this._payloadLength); + if (this._masked && (this._mask[0] | this._mask[1] | this._mask[2] | this._mask[3]) !== 0) { + unmask(data, this._mask); + } + } + if (this._opcode > 7) + return this.controlMessage(data); + if (this._compressed) { + this._state = INFLATING; + this.decompress(data, cb); + return; + } + if (data.length) { + this._messageLength = this._totalPayloadLength; + this._fragments.push(data); + } + return this.dataMessage(); + } + /** + * Decompresses data. + * + * @param {Buffer} data Compressed data + * @param {Function} cb Callback + * @private + */ + decompress(data, cb) { + const perMessageDeflate = this._extensions[PerMessageDeflate$3.extensionName]; + perMessageDeflate.decompress(data, this._fin, (err, buf) => { + if (err) + return cb(err); + if (buf.length) { + this._messageLength += buf.length; + if (this._messageLength > this._maxPayload && this._maxPayload > 0) { + return cb( + error( + RangeError, + "Max payload size exceeded", + false, + 1009, + "WS_ERR_UNSUPPORTED_MESSAGE_LENGTH" + ) + ); + } + this._fragments.push(buf); + } + const er = this.dataMessage(); + if (er) + return cb(er); + this.startLoop(cb); + }); + } + /** + * Handles a data message. + * + * @return {(Error|undefined)} A possible error + * @private + */ + dataMessage() { + if (this._fin) { + const messageLength = this._messageLength; + const fragments = this._fragments; + this._totalPayloadLength = 0; + this._messageLength = 0; + this._fragmented = 0; + this._fragments = []; + if (this._opcode === 2) { + let data; + if (this._binaryType === "nodebuffer") { + data = concat(fragments, messageLength); + } else if (this._binaryType === "arraybuffer") { + data = toArrayBuffer(concat(fragments, messageLength)); + } else { + data = fragments; + } + this.emit("message", data, true); + } else { + const buf = concat(fragments, messageLength); + if (!this._skipUTF8Validation && !isValidUTF8(buf)) { + this._loop = false; + return error( + Error, + "invalid UTF-8 sequence", + true, + 1007, + "WS_ERR_INVALID_UTF8" + ); + } + this.emit("message", buf, false); + } + } + this._state = GET_INFO; + } + /** + * Handles a control message. + * + * @param {Buffer} data Data to handle + * @return {(Error|RangeError|undefined)} A possible error + * @private + */ + controlMessage(data) { + if (this._opcode === 8) { + this._loop = false; + if (data.length === 0) { + this.emit("conclude", 1005, EMPTY_BUFFER$2); + this.end(); + } else { + const code = data.readUInt16BE(0); + if (!isValidStatusCode$1(code)) { + return error( + RangeError, + `invalid status code ${code}`, + true, + 1002, + "WS_ERR_INVALID_CLOSE_CODE" + ); + } + const buf = new FastBuffer( + data.buffer, + data.byteOffset + 2, + data.length - 2 + ); + if (!this._skipUTF8Validation && !isValidUTF8(buf)) { + return error( + Error, + "invalid UTF-8 sequence", + true, + 1007, + "WS_ERR_INVALID_UTF8" + ); + } + this.emit("conclude", code, buf); + this.end(); + } + } else if (this._opcode === 9) { + this.emit("ping", data); + } else { + this.emit("pong", data); + } + this._state = GET_INFO; + } +}; +var receiver = Receiver$1; +function error(ErrorCtor, message, prefix, statusCode, errorCode) { + const err = new ErrorCtor( + prefix ? `Invalid WebSocket frame: ${message}` : message + ); + Error.captureStackTrace(err, error); + err.code = errorCode; + err[kStatusCode$1] = statusCode; + return err; +} +const receiver$1 = /* @__PURE__ */ getDefaultExportFromCjs(receiver); +const { randomFillSync } = require$$5; +const PerMessageDeflate$2 = permessageDeflate; +const { EMPTY_BUFFER: EMPTY_BUFFER$1 } = constants; +const { isValidStatusCode } = validationExports; +const { mask: applyMask, toBuffer: toBuffer$1 } = bufferUtilExports; +const kByteLength = Symbol("kByteLength"); +const maskBuffer = Buffer.alloc(4); +let Sender$1 = class Sender { + /** + * Creates a Sender instance. + * + * @param {(net.Socket|tls.Socket)} socket The connection socket + * @param {Object} [extensions] An object containing the negotiated extensions + * @param {Function} [generateMask] The function used to generate the masking + * key + */ + constructor(socket, extensions, generateMask) { + this._extensions = extensions || {}; + if (generateMask) { + this._generateMask = generateMask; + this._maskBuffer = Buffer.alloc(4); + } + this._socket = socket; + this._firstFragment = true; + this._compress = false; + this._bufferedBytes = 0; + this._deflating = false; + this._queue = []; + } + /** + * Frames a piece of data according to the HyBi WebSocket protocol. + * + * @param {(Buffer|String)} data The data to frame + * @param {Object} options Options object + * @param {Boolean} [options.fin=false] Specifies whether or not to set the + * FIN bit + * @param {Function} [options.generateMask] The function used to generate the + * masking key + * @param {Boolean} [options.mask=false] Specifies whether or not to mask + * `data` + * @param {Buffer} [options.maskBuffer] The buffer used to store the masking + * key + * @param {Number} options.opcode The opcode + * @param {Boolean} [options.readOnly=false] Specifies whether `data` can be + * modified + * @param {Boolean} [options.rsv1=false] Specifies whether or not to set the + * RSV1 bit + * @return {(Buffer|String)[]} The framed data + * @public + */ + static frame(data, options) { + let mask2; + let merge = false; + let offset = 2; + let skipMasking = false; + if (options.mask) { + mask2 = options.maskBuffer || maskBuffer; + if (options.generateMask) { + options.generateMask(mask2); + } else { + randomFillSync(mask2, 0, 4); + } + skipMasking = (mask2[0] | mask2[1] | mask2[2] | mask2[3]) === 0; + offset = 6; + } + let dataLength; + if (typeof data === "string") { + if ((!options.mask || skipMasking) && options[kByteLength] !== void 0) { + dataLength = options[kByteLength]; + } else { + data = Buffer.from(data); + dataLength = data.length; + } + } else { + dataLength = data.length; + merge = options.mask && options.readOnly && !skipMasking; + } + let payloadLength = dataLength; + if (dataLength >= 65536) { + offset += 8; + payloadLength = 127; + } else if (dataLength > 125) { + offset += 2; + payloadLength = 126; + } + const target = Buffer.allocUnsafe(merge ? dataLength + offset : offset); + target[0] = options.fin ? options.opcode | 128 : options.opcode; + if (options.rsv1) + target[0] |= 64; + target[1] = payloadLength; + if (payloadLength === 126) { + target.writeUInt16BE(dataLength, 2); + } else if (payloadLength === 127) { + target[2] = target[3] = 0; + target.writeUIntBE(dataLength, 4, 6); + } + if (!options.mask) + return [target, data]; + target[1] |= 128; + target[offset - 4] = mask2[0]; + target[offset - 3] = mask2[1]; + target[offset - 2] = mask2[2]; + target[offset - 1] = mask2[3]; + if (skipMasking) + return [target, data]; + if (merge) { + applyMask(data, mask2, target, offset, dataLength); + return [target]; + } + applyMask(data, mask2, data, 0, dataLength); + return [target, data]; + } + /** + * Sends a close message to the other peer. + * + * @param {Number} [code] The status code component of the body + * @param {(String|Buffer)} [data] The message component of the body + * @param {Boolean} [mask=false] Specifies whether or not to mask the message + * @param {Function} [cb] Callback + * @public + */ + close(code, data, mask2, cb) { + let buf; + if (code === void 0) { + buf = EMPTY_BUFFER$1; + } else if (typeof code !== "number" || !isValidStatusCode(code)) { + throw new TypeError("First argument must be a valid error code number"); + } else if (data === void 0 || !data.length) { + buf = Buffer.allocUnsafe(2); + buf.writeUInt16BE(code, 0); + } else { + const length = Buffer.byteLength(data); + if (length > 123) { + throw new RangeError("The message must not be greater than 123 bytes"); + } + buf = Buffer.allocUnsafe(2 + length); + buf.writeUInt16BE(code, 0); + if (typeof data === "string") { + buf.write(data, 2); + } else { + buf.set(data, 2); + } + } + const options = { + [kByteLength]: buf.length, + fin: true, + generateMask: this._generateMask, + mask: mask2, + maskBuffer: this._maskBuffer, + opcode: 8, + readOnly: false, + rsv1: false + }; + if (this._deflating) { + this.enqueue([this.dispatch, buf, false, options, cb]); + } else { + this.sendFrame(Sender.frame(buf, options), cb); + } + } + /** + * Sends a ping message to the other peer. + * + * @param {*} data The message to send + * @param {Boolean} [mask=false] Specifies whether or not to mask `data` + * @param {Function} [cb] Callback + * @public + */ + ping(data, mask2, cb) { + let byteLength; + let readOnly; + if (typeof data === "string") { + byteLength = Buffer.byteLength(data); + readOnly = false; + } else { + data = toBuffer$1(data); + byteLength = data.length; + readOnly = toBuffer$1.readOnly; + } + if (byteLength > 125) { + throw new RangeError("The data size must not be greater than 125 bytes"); + } + const options = { + [kByteLength]: byteLength, + fin: true, + generateMask: this._generateMask, + mask: mask2, + maskBuffer: this._maskBuffer, + opcode: 9, + readOnly, + rsv1: false + }; + if (this._deflating) { + this.enqueue([this.dispatch, data, false, options, cb]); + } else { + this.sendFrame(Sender.frame(data, options), cb); + } + } + /** + * Sends a pong message to the other peer. + * + * @param {*} data The message to send + * @param {Boolean} [mask=false] Specifies whether or not to mask `data` + * @param {Function} [cb] Callback + * @public + */ + pong(data, mask2, cb) { + let byteLength; + let readOnly; + if (typeof data === "string") { + byteLength = Buffer.byteLength(data); + readOnly = false; + } else { + data = toBuffer$1(data); + byteLength = data.length; + readOnly = toBuffer$1.readOnly; + } + if (byteLength > 125) { + throw new RangeError("The data size must not be greater than 125 bytes"); + } + const options = { + [kByteLength]: byteLength, + fin: true, + generateMask: this._generateMask, + mask: mask2, + maskBuffer: this._maskBuffer, + opcode: 10, + readOnly, + rsv1: false + }; + if (this._deflating) { + this.enqueue([this.dispatch, data, false, options, cb]); + } else { + this.sendFrame(Sender.frame(data, options), cb); + } + } + /** + * Sends a data message to the other peer. + * + * @param {*} data The message to send + * @param {Object} options Options object + * @param {Boolean} [options.binary=false] Specifies whether `data` is binary + * or text + * @param {Boolean} [options.compress=false] Specifies whether or not to + * compress `data` + * @param {Boolean} [options.fin=false] Specifies whether the fragment is the + * last one + * @param {Boolean} [options.mask=false] Specifies whether or not to mask + * `data` + * @param {Function} [cb] Callback + * @public + */ + send(data, options, cb) { + const perMessageDeflate = this._extensions[PerMessageDeflate$2.extensionName]; + let opcode = options.binary ? 2 : 1; + let rsv1 = options.compress; + let byteLength; + let readOnly; + if (typeof data === "string") { + byteLength = Buffer.byteLength(data); + readOnly = false; + } else { + data = toBuffer$1(data); + byteLength = data.length; + readOnly = toBuffer$1.readOnly; + } + if (this._firstFragment) { + this._firstFragment = false; + if (rsv1 && perMessageDeflate && perMessageDeflate.params[perMessageDeflate._isServer ? "server_no_context_takeover" : "client_no_context_takeover"]) { + rsv1 = byteLength >= perMessageDeflate._threshold; + } + this._compress = rsv1; + } else { + rsv1 = false; + opcode = 0; + } + if (options.fin) + this._firstFragment = true; + if (perMessageDeflate) { + const opts = { + [kByteLength]: byteLength, + fin: options.fin, + generateMask: this._generateMask, + mask: options.mask, + maskBuffer: this._maskBuffer, + opcode, + readOnly, + rsv1 + }; + if (this._deflating) { + this.enqueue([this.dispatch, data, this._compress, opts, cb]); + } else { + this.dispatch(data, this._compress, opts, cb); + } + } else { + this.sendFrame( + Sender.frame(data, { + [kByteLength]: byteLength, + fin: options.fin, + generateMask: this._generateMask, + mask: options.mask, + maskBuffer: this._maskBuffer, + opcode, + readOnly, + rsv1: false + }), + cb + ); + } + } + /** + * Dispatches a message. + * + * @param {(Buffer|String)} data The message to send + * @param {Boolean} [compress=false] Specifies whether or not to compress + * `data` + * @param {Object} options Options object + * @param {Boolean} [options.fin=false] Specifies whether or not to set the + * FIN bit + * @param {Function} [options.generateMask] The function used to generate the + * masking key + * @param {Boolean} [options.mask=false] Specifies whether or not to mask + * `data` + * @param {Buffer} [options.maskBuffer] The buffer used to store the masking + * key + * @param {Number} options.opcode The opcode + * @param {Boolean} [options.readOnly=false] Specifies whether `data` can be + * modified + * @param {Boolean} [options.rsv1=false] Specifies whether or not to set the + * RSV1 bit + * @param {Function} [cb] Callback + * @private + */ + dispatch(data, compress, options, cb) { + if (!compress) { + this.sendFrame(Sender.frame(data, options), cb); + return; + } + const perMessageDeflate = this._extensions[PerMessageDeflate$2.extensionName]; + this._bufferedBytes += options[kByteLength]; + this._deflating = true; + perMessageDeflate.compress(data, options.fin, (_, buf) => { + if (this._socket.destroyed) { + const err = new Error( + "The socket was closed while data was being compressed" + ); + if (typeof cb === "function") + cb(err); + for (let i = 0; i < this._queue.length; i++) { + const params = this._queue[i]; + const callback = params[params.length - 1]; + if (typeof callback === "function") + callback(err); + } + return; + } + this._bufferedBytes -= options[kByteLength]; + this._deflating = false; + options.readOnly = false; + this.sendFrame(Sender.frame(buf, options), cb); + this.dequeue(); + }); + } + /** + * Executes queued send operations. + * + * @private + */ + dequeue() { + while (!this._deflating && this._queue.length) { + const params = this._queue.shift(); + this._bufferedBytes -= params[3][kByteLength]; + Reflect.apply(params[0], this, params.slice(1)); + } + } + /** + * Enqueues a send operation. + * + * @param {Array} params Send operation parameters. + * @private + */ + enqueue(params) { + this._bufferedBytes += params[3][kByteLength]; + this._queue.push(params); + } + /** + * Sends a frame. + * + * @param {Buffer[]} list The frame to send + * @param {Function} [cb] Callback + * @private + */ + sendFrame(list, cb) { + if (list.length === 2) { + this._socket.cork(); + this._socket.write(list[0]); + this._socket.write(list[1], cb); + this._socket.uncork(); + } else { + this._socket.write(list[0], cb); + } + } +}; +var sender = Sender$1; +const sender$1 = /* @__PURE__ */ getDefaultExportFromCjs(sender); +const { kForOnEventAttribute: kForOnEventAttribute$1, kListener: kListener$1 } = constants; +const kCode = Symbol("kCode"); +const kData = Symbol("kData"); +const kError = Symbol("kError"); +const kMessage = Symbol("kMessage"); +const kReason = Symbol("kReason"); +const kTarget = Symbol("kTarget"); +const kType = Symbol("kType"); +const kWasClean = Symbol("kWasClean"); +class Event { + /** + * Create a new `Event`. + * + * @param {String} type The name of the event + * @throws {TypeError} If the `type` argument is not specified + */ + constructor(type) { + this[kTarget] = null; + this[kType] = type; + } + /** + * @type {*} + */ + get target() { + return this[kTarget]; + } + /** + * @type {String} + */ + get type() { + return this[kType]; + } +} +Object.defineProperty(Event.prototype, "target", { enumerable: true }); +Object.defineProperty(Event.prototype, "type", { enumerable: true }); +class CloseEvent extends Event { + /** + * Create a new `CloseEvent`. + * + * @param {String} type The name of the event + * @param {Object} [options] A dictionary object that allows for setting + * attributes via object members of the same name + * @param {Number} [options.code=0] The status code explaining why the + * connection was closed + * @param {String} [options.reason=''] A human-readable string explaining why + * the connection was closed + * @param {Boolean} [options.wasClean=false] Indicates whether or not the + * connection was cleanly closed + */ + constructor(type, options = {}) { + super(type); + this[kCode] = options.code === void 0 ? 0 : options.code; + this[kReason] = options.reason === void 0 ? "" : options.reason; + this[kWasClean] = options.wasClean === void 0 ? false : options.wasClean; + } + /** + * @type {Number} + */ + get code() { + return this[kCode]; + } + /** + * @type {String} + */ + get reason() { + return this[kReason]; + } + /** + * @type {Boolean} + */ + get wasClean() { + return this[kWasClean]; + } +} +Object.defineProperty(CloseEvent.prototype, "code", { enumerable: true }); +Object.defineProperty(CloseEvent.prototype, "reason", { enumerable: true }); +Object.defineProperty(CloseEvent.prototype, "wasClean", { enumerable: true }); +class ErrorEvent extends Event { + /** + * Create a new `ErrorEvent`. + * + * @param {String} type The name of the event + * @param {Object} [options] A dictionary object that allows for setting + * attributes via object members of the same name + * @param {*} [options.error=null] The error that generated this event + * @param {String} [options.message=''] The error message + */ + constructor(type, options = {}) { + super(type); + this[kError] = options.error === void 0 ? null : options.error; + this[kMessage] = options.message === void 0 ? "" : options.message; + } + /** + * @type {*} + */ + get error() { + return this[kError]; + } + /** + * @type {String} + */ + get message() { + return this[kMessage]; + } +} +Object.defineProperty(ErrorEvent.prototype, "error", { enumerable: true }); +Object.defineProperty(ErrorEvent.prototype, "message", { enumerable: true }); +class MessageEvent extends Event { + /** + * Create a new `MessageEvent`. + * + * @param {String} type The name of the event + * @param {Object} [options] A dictionary object that allows for setting + * attributes via object members of the same name + * @param {*} [options.data=null] The message content + */ + constructor(type, options = {}) { + super(type); + this[kData] = options.data === void 0 ? null : options.data; + } + /** + * @type {*} + */ + get data() { + return this[kData]; + } +} +Object.defineProperty(MessageEvent.prototype, "data", { enumerable: true }); +const EventTarget = { + /** + * Register an event listener. + * + * @param {String} type A string representing the event type to listen for + * @param {(Function|Object)} handler The listener to add + * @param {Object} [options] An options object specifies characteristics about + * the event listener + * @param {Boolean} [options.once=false] A `Boolean` indicating that the + * listener should be invoked at most once after being added. If `true`, + * the listener would be automatically removed when invoked. + * @public + */ + addEventListener(type, handler, options = {}) { + for (const listener of this.listeners(type)) { + if (!options[kForOnEventAttribute$1] && listener[kListener$1] === handler && !listener[kForOnEventAttribute$1]) { + return; + } + } + let wrapper; + if (type === "message") { + wrapper = function onMessage(data, isBinary) { + const event = new MessageEvent("message", { + data: isBinary ? data : data.toString() + }); + event[kTarget] = this; + callListener(handler, this, event); + }; + } else if (type === "close") { + wrapper = function onClose(code, message) { + const event = new CloseEvent("close", { + code, + reason: message.toString(), + wasClean: this._closeFrameReceived && this._closeFrameSent + }); + event[kTarget] = this; + callListener(handler, this, event); + }; + } else if (type === "error") { + wrapper = function onError(error2) { + const event = new ErrorEvent("error", { + error: error2, + message: error2.message + }); + event[kTarget] = this; + callListener(handler, this, event); + }; + } else if (type === "open") { + wrapper = function onOpen() { + const event = new Event("open"); + event[kTarget] = this; + callListener(handler, this, event); + }; + } else { + return; + } + wrapper[kForOnEventAttribute$1] = !!options[kForOnEventAttribute$1]; + wrapper[kListener$1] = handler; + if (options.once) { + this.once(type, wrapper); + } else { + this.on(type, wrapper); + } + }, + /** + * Remove an event listener. + * + * @param {String} type A string representing the event type to remove + * @param {(Function|Object)} handler The listener to remove + * @public + */ + removeEventListener(type, handler) { + for (const listener of this.listeners(type)) { + if (listener[kListener$1] === handler && !listener[kForOnEventAttribute$1]) { + this.removeListener(type, listener); + break; + } + } + } +}; +var eventTarget = { + CloseEvent, + ErrorEvent, + Event, + EventTarget, + MessageEvent +}; +function callListener(listener, thisArg, event) { + if (typeof listener === "object" && listener.handleEvent) { + listener.handleEvent.call(listener, event); + } else { + listener.call(thisArg, event); + } +} +const { tokenChars: tokenChars$1 } = validationExports; +function push(dest, name, elem) { + if (dest[name] === void 0) + dest[name] = [elem]; + else + dest[name].push(elem); +} +function parse$2(header) { + const offers = /* @__PURE__ */ Object.create(null); + let params = /* @__PURE__ */ Object.create(null); + let mustUnescape = false; + let isEscaping = false; + let inQuotes = false; + let extensionName; + let paramName; + let start = -1; + let code = -1; + let end = -1; + let i = 0; + for (; i < header.length; i++) { + code = header.charCodeAt(i); + if (extensionName === void 0) { + if (end === -1 && tokenChars$1[code] === 1) { + if (start === -1) + start = i; + } else if (i !== 0 && (code === 32 || code === 9)) { + if (end === -1 && start !== -1) + end = i; + } else if (code === 59 || code === 44) { + if (start === -1) { + throw new SyntaxError(`Unexpected character at index ${i}`); + } + if (end === -1) + end = i; + const name = header.slice(start, end); + if (code === 44) { + push(offers, name, params); + params = /* @__PURE__ */ Object.create(null); + } else { + extensionName = name; + } + start = end = -1; + } else { + throw new SyntaxError(`Unexpected character at index ${i}`); + } + } else if (paramName === void 0) { + if (end === -1 && tokenChars$1[code] === 1) { + if (start === -1) + start = i; + } else if (code === 32 || code === 9) { + if (end === -1 && start !== -1) + end = i; + } else if (code === 59 || code === 44) { + if (start === -1) { + throw new SyntaxError(`Unexpected character at index ${i}`); + } + if (end === -1) + end = i; + push(params, header.slice(start, end), true); + if (code === 44) { + push(offers, extensionName, params); + params = /* @__PURE__ */ Object.create(null); + extensionName = void 0; + } + start = end = -1; + } else if (code === 61 && start !== -1 && end === -1) { + paramName = header.slice(start, i); + start = end = -1; + } else { + throw new SyntaxError(`Unexpected character at index ${i}`); + } + } else { + if (isEscaping) { + if (tokenChars$1[code] !== 1) { + throw new SyntaxError(`Unexpected character at index ${i}`); + } + if (start === -1) + start = i; + else if (!mustUnescape) + mustUnescape = true; + isEscaping = false; + } else if (inQuotes) { + if (tokenChars$1[code] === 1) { + if (start === -1) + start = i; + } else if (code === 34 && start !== -1) { + inQuotes = false; + end = i; + } else if (code === 92) { + isEscaping = true; + } else { + throw new SyntaxError(`Unexpected character at index ${i}`); + } + } else if (code === 34 && header.charCodeAt(i - 1) === 61) { + inQuotes = true; + } else if (end === -1 && tokenChars$1[code] === 1) { + if (start === -1) + start = i; + } else if (start !== -1 && (code === 32 || code === 9)) { + if (end === -1) + end = i; + } else if (code === 59 || code === 44) { + if (start === -1) { + throw new SyntaxError(`Unexpected character at index ${i}`); + } + if (end === -1) + end = i; + let value = header.slice(start, end); + if (mustUnescape) { + value = value.replace(/\\/g, ""); + mustUnescape = false; + } + push(params, paramName, value); + if (code === 44) { + push(offers, extensionName, params); + params = /* @__PURE__ */ Object.create(null); + extensionName = void 0; + } + paramName = void 0; + start = end = -1; + } else { + throw new SyntaxError(`Unexpected character at index ${i}`); + } + } + } + if (start === -1 || inQuotes || code === 32 || code === 9) { + throw new SyntaxError("Unexpected end of input"); + } + if (end === -1) + end = i; + const token = header.slice(start, end); + if (extensionName === void 0) { + push(offers, token, params); + } else { + if (paramName === void 0) { + push(params, token, true); + } else if (mustUnescape) { + push(params, paramName, token.replace(/\\/g, "")); + } else { + push(params, paramName, token); + } + push(offers, extensionName, params); + } + return offers; +} +function format$1(extensions) { + return Object.keys(extensions).map((extension2) => { + let configurations = extensions[extension2]; + if (!Array.isArray(configurations)) + configurations = [configurations]; + return configurations.map((params) => { + return [extension2].concat( + Object.keys(params).map((k) => { + let values = params[k]; + if (!Array.isArray(values)) + values = [values]; + return values.map((v) => v === true ? k : `${k}=${v}`).join("; "); + }) + ).join("; "); + }).join(", "); + }).join(", "); +} +var extension$1 = { format: format$1, parse: parse$2 }; +const EventEmitter$1 = require$$0$4; +const https = require$$1$2; +const http$1 = require$$2$1; +const net = require$$3; +const tls = require$$4; +const { randomBytes, createHash: createHash$1 } = require$$5; +const { URL } = require$$7; +const PerMessageDeflate$1 = permessageDeflate; +const Receiver2 = receiver; +const Sender2 = sender; +const { + BINARY_TYPES, + EMPTY_BUFFER, + GUID: GUID$1, + kForOnEventAttribute, + kListener, + kStatusCode, + kWebSocket: kWebSocket$1, + NOOP +} = constants; +const { + EventTarget: { addEventListener, removeEventListener } +} = eventTarget; +const { format, parse: parse$1 } = extension$1; +const { toBuffer } = bufferUtilExports; +const closeTimeout = 30 * 1e3; +const kAborted = Symbol("kAborted"); +const protocolVersions = [8, 13]; +const readyStates = ["CONNECTING", "OPEN", "CLOSING", "CLOSED"]; +const subprotocolRegex = /^[!#$%&'*+\-.0-9A-Z^_`|a-z~]+$/; +let WebSocket$1 = class WebSocket extends EventEmitter$1 { + /** + * Create a new `WebSocket`. + * + * @param {(String|URL)} address The URL to which to connect + * @param {(String|String[])} [protocols] The subprotocols + * @param {Object} [options] Connection options + */ + constructor(address, protocols, options) { + super(); + this._binaryType = BINARY_TYPES[0]; + this._closeCode = 1006; + this._closeFrameReceived = false; + this._closeFrameSent = false; + this._closeMessage = EMPTY_BUFFER; + this._closeTimer = null; + this._extensions = {}; + this._paused = false; + this._protocol = ""; + this._readyState = WebSocket.CONNECTING; + this._receiver = null; + this._sender = null; + this._socket = null; + if (address !== null) { + this._bufferedAmount = 0; + this._isServer = false; + this._redirects = 0; + if (protocols === void 0) { + protocols = []; + } else if (!Array.isArray(protocols)) { + if (typeof protocols === "object" && protocols !== null) { + options = protocols; + protocols = []; + } else { + protocols = [protocols]; + } + } + initAsClient(this, address, protocols, options); + } else { + this._isServer = true; + } + } + /** + * This deviates from the WHATWG interface since ws doesn't support the + * required default "blob" type (instead we define a custom "nodebuffer" + * type). + * + * @type {String} + */ + get binaryType() { + return this._binaryType; + } + set binaryType(type) { + if (!BINARY_TYPES.includes(type)) + return; + this._binaryType = type; + if (this._receiver) + this._receiver._binaryType = type; + } + /** + * @type {Number} + */ + get bufferedAmount() { + if (!this._socket) + return this._bufferedAmount; + return this._socket._writableState.length + this._sender._bufferedBytes; + } + /** + * @type {String} + */ + get extensions() { + return Object.keys(this._extensions).join(); + } + /** + * @type {Boolean} + */ + get isPaused() { + return this._paused; + } + /** + * @type {Function} + */ + /* istanbul ignore next */ + get onclose() { + return null; + } + /** + * @type {Function} + */ + /* istanbul ignore next */ + get onerror() { + return null; + } + /** + * @type {Function} + */ + /* istanbul ignore next */ + get onopen() { + return null; + } + /** + * @type {Function} + */ + /* istanbul ignore next */ + get onmessage() { + return null; + } + /** + * @type {String} + */ + get protocol() { + return this._protocol; + } + /** + * @type {Number} + */ + get readyState() { + return this._readyState; + } + /** + * @type {String} + */ + get url() { + return this._url; + } + /** + * Set up the socket and the internal resources. + * + * @param {(net.Socket|tls.Socket)} socket The network socket between the + * server and client + * @param {Buffer} head The first packet of the upgraded stream + * @param {Object} options Options object + * @param {Function} [options.generateMask] The function used to generate the + * masking key + * @param {Number} [options.maxPayload=0] The maximum allowed message size + * @param {Boolean} [options.skipUTF8Validation=false] Specifies whether or + * not to skip UTF-8 validation for text and close messages + * @private + */ + setSocket(socket, head, options) { + const receiver2 = new Receiver2({ + binaryType: this.binaryType, + extensions: this._extensions, + isServer: this._isServer, + maxPayload: options.maxPayload, + skipUTF8Validation: options.skipUTF8Validation + }); + this._sender = new Sender2(socket, this._extensions, options.generateMask); + this._receiver = receiver2; + this._socket = socket; + receiver2[kWebSocket$1] = this; + socket[kWebSocket$1] = this; + receiver2.on("conclude", receiverOnConclude); + receiver2.on("drain", receiverOnDrain); + receiver2.on("error", receiverOnError); + receiver2.on("message", receiverOnMessage); + receiver2.on("ping", receiverOnPing); + receiver2.on("pong", receiverOnPong); + socket.setTimeout(0); + socket.setNoDelay(); + if (head.length > 0) + socket.unshift(head); + socket.on("close", socketOnClose); + socket.on("data", socketOnData); + socket.on("end", socketOnEnd); + socket.on("error", socketOnError$1); + this._readyState = WebSocket.OPEN; + this.emit("open"); + } + /** + * Emit the `'close'` event. + * + * @private + */ + emitClose() { + if (!this._socket) { + this._readyState = WebSocket.CLOSED; + this.emit("close", this._closeCode, this._closeMessage); + return; + } + if (this._extensions[PerMessageDeflate$1.extensionName]) { + this._extensions[PerMessageDeflate$1.extensionName].cleanup(); + } + this._receiver.removeAllListeners(); + this._readyState = WebSocket.CLOSED; + this.emit("close", this._closeCode, this._closeMessage); + } + /** + * Start a closing handshake. + * + * +----------+ +-----------+ +----------+ + * - - -|ws.close()|-->|close frame|-->|ws.close()|- - - + * | +----------+ +-----------+ +----------+ | + * +----------+ +-----------+ | + * CLOSING |ws.close()|<--|close frame|<--+-----+ CLOSING + * +----------+ +-----------+ | + * | | | +---+ | + * +------------------------+-->|fin| - - - - + * | +---+ | +---+ + * - - - - -|fin|<---------------------+ + * +---+ + * + * @param {Number} [code] Status code explaining why the connection is closing + * @param {(String|Buffer)} [data] The reason why the connection is + * closing + * @public + */ + close(code, data) { + if (this.readyState === WebSocket.CLOSED) + return; + if (this.readyState === WebSocket.CONNECTING) { + const msg = "WebSocket was closed before the connection was established"; + abortHandshake$1(this, this._req, msg); + return; + } + if (this.readyState === WebSocket.CLOSING) { + if (this._closeFrameSent && (this._closeFrameReceived || this._receiver._writableState.errorEmitted)) { + this._socket.end(); + } + return; + } + this._readyState = WebSocket.CLOSING; + this._sender.close(code, data, !this._isServer, (err) => { + if (err) + return; + this._closeFrameSent = true; + if (this._closeFrameReceived || this._receiver._writableState.errorEmitted) { + this._socket.end(); + } + }); + this._closeTimer = setTimeout( + this._socket.destroy.bind(this._socket), + closeTimeout + ); + } + /** + * Pause the socket. + * + * @public + */ + pause() { + if (this.readyState === WebSocket.CONNECTING || this.readyState === WebSocket.CLOSED) { + return; + } + this._paused = true; + this._socket.pause(); + } + /** + * Send a ping. + * + * @param {*} [data] The data to send + * @param {Boolean} [mask] Indicates whether or not to mask `data` + * @param {Function} [cb] Callback which is executed when the ping is sent + * @public + */ + ping(data, mask2, cb) { + if (this.readyState === WebSocket.CONNECTING) { + throw new Error("WebSocket is not open: readyState 0 (CONNECTING)"); + } + if (typeof data === "function") { + cb = data; + data = mask2 = void 0; + } else if (typeof mask2 === "function") { + cb = mask2; + mask2 = void 0; + } + if (typeof data === "number") + data = data.toString(); + if (this.readyState !== WebSocket.OPEN) { + sendAfterClose(this, data, cb); + return; + } + if (mask2 === void 0) + mask2 = !this._isServer; + this._sender.ping(data || EMPTY_BUFFER, mask2, cb); + } + /** + * Send a pong. + * + * @param {*} [data] The data to send + * @param {Boolean} [mask] Indicates whether or not to mask `data` + * @param {Function} [cb] Callback which is executed when the pong is sent + * @public + */ + pong(data, mask2, cb) { + if (this.readyState === WebSocket.CONNECTING) { + throw new Error("WebSocket is not open: readyState 0 (CONNECTING)"); + } + if (typeof data === "function") { + cb = data; + data = mask2 = void 0; + } else if (typeof mask2 === "function") { + cb = mask2; + mask2 = void 0; + } + if (typeof data === "number") + data = data.toString(); + if (this.readyState !== WebSocket.OPEN) { + sendAfterClose(this, data, cb); + return; + } + if (mask2 === void 0) + mask2 = !this._isServer; + this._sender.pong(data || EMPTY_BUFFER, mask2, cb); + } + /** + * Resume the socket. + * + * @public + */ + resume() { + if (this.readyState === WebSocket.CONNECTING || this.readyState === WebSocket.CLOSED) { + return; + } + this._paused = false; + if (!this._receiver._writableState.needDrain) + this._socket.resume(); + } + /** + * Send a data message. + * + * @param {*} data The message to send + * @param {Object} [options] Options object + * @param {Boolean} [options.binary] Specifies whether `data` is binary or + * text + * @param {Boolean} [options.compress] Specifies whether or not to compress + * `data` + * @param {Boolean} [options.fin=true] Specifies whether the fragment is the + * last one + * @param {Boolean} [options.mask] Specifies whether or not to mask `data` + * @param {Function} [cb] Callback which is executed when data is written out + * @public + */ + send(data, options, cb) { + if (this.readyState === WebSocket.CONNECTING) { + throw new Error("WebSocket is not open: readyState 0 (CONNECTING)"); + } + if (typeof options === "function") { + cb = options; + options = {}; + } + if (typeof data === "number") + data = data.toString(); + if (this.readyState !== WebSocket.OPEN) { + sendAfterClose(this, data, cb); + return; + } + const opts = { + binary: typeof data !== "string", + mask: !this._isServer, + compress: true, + fin: true, + ...options + }; + if (!this._extensions[PerMessageDeflate$1.extensionName]) { + opts.compress = false; + } + this._sender.send(data || EMPTY_BUFFER, opts, cb); + } + /** + * Forcibly close the connection. + * + * @public + */ + terminate() { + if (this.readyState === WebSocket.CLOSED) + return; + if (this.readyState === WebSocket.CONNECTING) { + const msg = "WebSocket was closed before the connection was established"; + abortHandshake$1(this, this._req, msg); + return; + } + if (this._socket) { + this._readyState = WebSocket.CLOSING; + this._socket.destroy(); + } + } +}; +Object.defineProperty(WebSocket$1, "CONNECTING", { + enumerable: true, + value: readyStates.indexOf("CONNECTING") +}); +Object.defineProperty(WebSocket$1.prototype, "CONNECTING", { + enumerable: true, + value: readyStates.indexOf("CONNECTING") +}); +Object.defineProperty(WebSocket$1, "OPEN", { + enumerable: true, + value: readyStates.indexOf("OPEN") +}); +Object.defineProperty(WebSocket$1.prototype, "OPEN", { + enumerable: true, + value: readyStates.indexOf("OPEN") +}); +Object.defineProperty(WebSocket$1, "CLOSING", { + enumerable: true, + value: readyStates.indexOf("CLOSING") +}); +Object.defineProperty(WebSocket$1.prototype, "CLOSING", { + enumerable: true, + value: readyStates.indexOf("CLOSING") +}); +Object.defineProperty(WebSocket$1, "CLOSED", { + enumerable: true, + value: readyStates.indexOf("CLOSED") +}); +Object.defineProperty(WebSocket$1.prototype, "CLOSED", { + enumerable: true, + value: readyStates.indexOf("CLOSED") +}); +[ + "binaryType", + "bufferedAmount", + "extensions", + "isPaused", + "protocol", + "readyState", + "url" +].forEach((property) => { + Object.defineProperty(WebSocket$1.prototype, property, { enumerable: true }); +}); +["open", "error", "close", "message"].forEach((method) => { + Object.defineProperty(WebSocket$1.prototype, `on${method}`, { + enumerable: true, + get() { + for (const listener of this.listeners(method)) { + if (listener[kForOnEventAttribute]) + return listener[kListener]; + } + return null; + }, + set(handler) { + for (const listener of this.listeners(method)) { + if (listener[kForOnEventAttribute]) { + this.removeListener(method, listener); + break; + } + } + if (typeof handler !== "function") + return; + this.addEventListener(method, handler, { + [kForOnEventAttribute]: true + }); + } + }); +}); +WebSocket$1.prototype.addEventListener = addEventListener; +WebSocket$1.prototype.removeEventListener = removeEventListener; +var websocket = WebSocket$1; +function initAsClient(websocket2, address, protocols, options) { + const opts = { + protocolVersion: protocolVersions[1], + maxPayload: 100 * 1024 * 1024, + skipUTF8Validation: false, + perMessageDeflate: true, + followRedirects: false, + maxRedirects: 10, + ...options, + createConnection: void 0, + socketPath: void 0, + hostname: void 0, + protocol: void 0, + timeout: void 0, + method: "GET", + host: void 0, + path: void 0, + port: void 0 + }; + if (!protocolVersions.includes(opts.protocolVersion)) { + throw new RangeError( + `Unsupported protocol version: ${opts.protocolVersion} (supported versions: ${protocolVersions.join(", ")})` + ); + } + let parsedUrl; + if (address instanceof URL) { + parsedUrl = address; + websocket2._url = address.href; + } else { + try { + parsedUrl = new URL(address); + } catch (e) { + throw new SyntaxError(`Invalid URL: ${address}`); + } + websocket2._url = address; + } + const isSecure = parsedUrl.protocol === "wss:"; + const isIpcUrl = parsedUrl.protocol === "ws+unix:"; + let invalidUrlMessage; + if (parsedUrl.protocol !== "ws:" && !isSecure && !isIpcUrl) { + invalidUrlMessage = `The URL's protocol must be one of "ws:", "wss:", or "ws+unix:"`; + } else if (isIpcUrl && !parsedUrl.pathname) { + invalidUrlMessage = "The URL's pathname is empty"; + } else if (parsedUrl.hash) { + invalidUrlMessage = "The URL contains a fragment identifier"; + } + if (invalidUrlMessage) { + const err = new SyntaxError(invalidUrlMessage); + if (websocket2._redirects === 0) { + throw err; + } else { + emitErrorAndClose(websocket2, err); + return; + } + } + const defaultPort = isSecure ? 443 : 80; + const key = randomBytes(16).toString("base64"); + const request = isSecure ? https.request : http$1.request; + const protocolSet = /* @__PURE__ */ new Set(); + let perMessageDeflate; + opts.createConnection = isSecure ? tlsConnect : netConnect; + opts.defaultPort = opts.defaultPort || defaultPort; + opts.port = parsedUrl.port || defaultPort; + opts.host = parsedUrl.hostname.startsWith("[") ? parsedUrl.hostname.slice(1, -1) : parsedUrl.hostname; + opts.headers = { + ...opts.headers, + "Sec-WebSocket-Version": opts.protocolVersion, + "Sec-WebSocket-Key": key, + Connection: "Upgrade", + Upgrade: "websocket" + }; + opts.path = parsedUrl.pathname + parsedUrl.search; + opts.timeout = opts.handshakeTimeout; + if (opts.perMessageDeflate) { + perMessageDeflate = new PerMessageDeflate$1( + opts.perMessageDeflate !== true ? opts.perMessageDeflate : {}, + false, + opts.maxPayload + ); + opts.headers["Sec-WebSocket-Extensions"] = format({ + [PerMessageDeflate$1.extensionName]: perMessageDeflate.offer() + }); + } + if (protocols.length) { + for (const protocol of protocols) { + if (typeof protocol !== "string" || !subprotocolRegex.test(protocol) || protocolSet.has(protocol)) { + throw new SyntaxError( + "An invalid or duplicated subprotocol was specified" + ); + } + protocolSet.add(protocol); + } + opts.headers["Sec-WebSocket-Protocol"] = protocols.join(","); + } + if (opts.origin) { + if (opts.protocolVersion < 13) { + opts.headers["Sec-WebSocket-Origin"] = opts.origin; + } else { + opts.headers.Origin = opts.origin; + } + } + if (parsedUrl.username || parsedUrl.password) { + opts.auth = `${parsedUrl.username}:${parsedUrl.password}`; + } + if (isIpcUrl) { + const parts = opts.path.split(":"); + opts.socketPath = parts[0]; + opts.path = parts[1]; + } + let req; + if (opts.followRedirects) { + if (websocket2._redirects === 0) { + websocket2._originalIpc = isIpcUrl; + websocket2._originalSecure = isSecure; + websocket2._originalHostOrSocketPath = isIpcUrl ? opts.socketPath : parsedUrl.host; + const headers = options && options.headers; + options = { ...options, headers: {} }; + if (headers) { + for (const [key2, value] of Object.entries(headers)) { + options.headers[key2.toLowerCase()] = value; + } + } + } else if (websocket2.listenerCount("redirect") === 0) { + const isSameHost = isIpcUrl ? websocket2._originalIpc ? opts.socketPath === websocket2._originalHostOrSocketPath : false : websocket2._originalIpc ? false : parsedUrl.host === websocket2._originalHostOrSocketPath; + if (!isSameHost || websocket2._originalSecure && !isSecure) { + delete opts.headers.authorization; + delete opts.headers.cookie; + if (!isSameHost) + delete opts.headers.host; + opts.auth = void 0; + } + } + if (opts.auth && !options.headers.authorization) { + options.headers.authorization = "Basic " + Buffer.from(opts.auth).toString("base64"); + } + req = websocket2._req = request(opts); + if (websocket2._redirects) { + websocket2.emit("redirect", websocket2.url, req); + } + } else { + req = websocket2._req = request(opts); + } + if (opts.timeout) { + req.on("timeout", () => { + abortHandshake$1(websocket2, req, "Opening handshake has timed out"); + }); + } + req.on("error", (err) => { + if (req === null || req[kAborted]) + return; + req = websocket2._req = null; + emitErrorAndClose(websocket2, err); + }); + req.on("response", (res) => { + const location = res.headers.location; + const statusCode = res.statusCode; + if (location && opts.followRedirects && statusCode >= 300 && statusCode < 400) { + if (++websocket2._redirects > opts.maxRedirects) { + abortHandshake$1(websocket2, req, "Maximum redirects exceeded"); + return; + } + req.abort(); + let addr; + try { + addr = new URL(location, address); + } catch (e) { + const err = new SyntaxError(`Invalid URL: ${location}`); + emitErrorAndClose(websocket2, err); + return; + } + initAsClient(websocket2, addr, protocols, options); + } else if (!websocket2.emit("unexpected-response", req, res)) { + abortHandshake$1( + websocket2, + req, + `Unexpected server response: ${res.statusCode}` + ); + } + }); + req.on("upgrade", (res, socket, head) => { + websocket2.emit("upgrade", res); + if (websocket2.readyState !== WebSocket$1.CONNECTING) + return; + req = websocket2._req = null; + if (res.headers.upgrade.toLowerCase() !== "websocket") { + abortHandshake$1(websocket2, socket, "Invalid Upgrade header"); + return; + } + const digest = createHash$1("sha1").update(key + GUID$1).digest("base64"); + if (res.headers["sec-websocket-accept"] !== digest) { + abortHandshake$1(websocket2, socket, "Invalid Sec-WebSocket-Accept header"); + return; + } + const serverProt = res.headers["sec-websocket-protocol"]; + let protError; + if (serverProt !== void 0) { + if (!protocolSet.size) { + protError = "Server sent a subprotocol but none was requested"; + } else if (!protocolSet.has(serverProt)) { + protError = "Server sent an invalid subprotocol"; + } + } else if (protocolSet.size) { + protError = "Server sent no subprotocol"; + } + if (protError) { + abortHandshake$1(websocket2, socket, protError); + return; + } + if (serverProt) + websocket2._protocol = serverProt; + const secWebSocketExtensions = res.headers["sec-websocket-extensions"]; + if (secWebSocketExtensions !== void 0) { + if (!perMessageDeflate) { + const message = "Server sent a Sec-WebSocket-Extensions header but no extension was requested"; + abortHandshake$1(websocket2, socket, message); + return; + } + let extensions; + try { + extensions = parse$1(secWebSocketExtensions); + } catch (err) { + const message = "Invalid Sec-WebSocket-Extensions header"; + abortHandshake$1(websocket2, socket, message); + return; + } + const extensionNames = Object.keys(extensions); + if (extensionNames.length !== 1 || extensionNames[0] !== PerMessageDeflate$1.extensionName) { + const message = "Server indicated an extension that was not requested"; + abortHandshake$1(websocket2, socket, message); + return; + } + try { + perMessageDeflate.accept(extensions[PerMessageDeflate$1.extensionName]); + } catch (err) { + const message = "Invalid Sec-WebSocket-Extensions header"; + abortHandshake$1(websocket2, socket, message); + return; + } + websocket2._extensions[PerMessageDeflate$1.extensionName] = perMessageDeflate; + } + websocket2.setSocket(socket, head, { + generateMask: opts.generateMask, + maxPayload: opts.maxPayload, + skipUTF8Validation: opts.skipUTF8Validation + }); + }); + if (opts.finishRequest) { + opts.finishRequest(req, websocket2); + } else { + req.end(); + } +} +function emitErrorAndClose(websocket2, err) { + websocket2._readyState = WebSocket$1.CLOSING; + websocket2.emit("error", err); + websocket2.emitClose(); +} +function netConnect(options) { + options.path = options.socketPath; + return net.connect(options); +} +function tlsConnect(options) { + options.path = void 0; + if (!options.servername && options.servername !== "") { + options.servername = net.isIP(options.host) ? "" : options.host; + } + return tls.connect(options); +} +function abortHandshake$1(websocket2, stream2, message) { + websocket2._readyState = WebSocket$1.CLOSING; + const err = new Error(message); + Error.captureStackTrace(err, abortHandshake$1); + if (stream2.setHeader) { + stream2[kAborted] = true; + stream2.abort(); + if (stream2.socket && !stream2.socket.destroyed) { + stream2.socket.destroy(); + } + process.nextTick(emitErrorAndClose, websocket2, err); + } else { + stream2.destroy(err); + stream2.once("error", websocket2.emit.bind(websocket2, "error")); + stream2.once("close", websocket2.emitClose.bind(websocket2)); + } +} +function sendAfterClose(websocket2, data, cb) { + if (data) { + const length = toBuffer(data).length; + if (websocket2._socket) + websocket2._sender._bufferedBytes += length; + else + websocket2._bufferedAmount += length; + } + if (cb) { + const err = new Error( + `WebSocket is not open: readyState ${websocket2.readyState} (${readyStates[websocket2.readyState]})` + ); + process.nextTick(cb, err); + } +} +function receiverOnConclude(code, reason) { + const websocket2 = this[kWebSocket$1]; + websocket2._closeFrameReceived = true; + websocket2._closeMessage = reason; + websocket2._closeCode = code; + if (websocket2._socket[kWebSocket$1] === void 0) + return; + websocket2._socket.removeListener("data", socketOnData); + process.nextTick(resume, websocket2._socket); + if (code === 1005) + websocket2.close(); + else + websocket2.close(code, reason); +} +function receiverOnDrain() { + const websocket2 = this[kWebSocket$1]; + if (!websocket2.isPaused) + websocket2._socket.resume(); +} +function receiverOnError(err) { + const websocket2 = this[kWebSocket$1]; + if (websocket2._socket[kWebSocket$1] !== void 0) { + websocket2._socket.removeListener("data", socketOnData); + process.nextTick(resume, websocket2._socket); + websocket2.close(err[kStatusCode]); + } + websocket2.emit("error", err); +} +function receiverOnFinish() { + this[kWebSocket$1].emitClose(); +} +function receiverOnMessage(data, isBinary) { + this[kWebSocket$1].emit("message", data, isBinary); +} +function receiverOnPing(data) { + const websocket2 = this[kWebSocket$1]; + websocket2.pong(data, !websocket2._isServer, NOOP); + websocket2.emit("ping", data); +} +function receiverOnPong(data) { + this[kWebSocket$1].emit("pong", data); +} +function resume(stream2) { + stream2.resume(); +} +function socketOnClose() { + const websocket2 = this[kWebSocket$1]; + this.removeListener("close", socketOnClose); + this.removeListener("data", socketOnData); + this.removeListener("end", socketOnEnd); + websocket2._readyState = WebSocket$1.CLOSING; + let chunk; + if (!this._readableState.endEmitted && !websocket2._closeFrameReceived && !websocket2._receiver._writableState.errorEmitted && (chunk = websocket2._socket.read()) !== null) { + websocket2._receiver.write(chunk); + } + websocket2._receiver.end(); + this[kWebSocket$1] = void 0; + clearTimeout(websocket2._closeTimer); + if (websocket2._receiver._writableState.finished || websocket2._receiver._writableState.errorEmitted) { + websocket2.emitClose(); + } else { + websocket2._receiver.on("error", receiverOnFinish); + websocket2._receiver.on("finish", receiverOnFinish); + } +} +function socketOnData(chunk) { + if (!this[kWebSocket$1]._receiver.write(chunk)) { + this.pause(); + } +} +function socketOnEnd() { + const websocket2 = this[kWebSocket$1]; + websocket2._readyState = WebSocket$1.CLOSING; + websocket2._receiver.end(); + this.end(); +} +function socketOnError$1() { + const websocket2 = this[kWebSocket$1]; + this.removeListener("error", socketOnError$1); + this.on("error", NOOP); + if (websocket2) { + websocket2._readyState = WebSocket$1.CLOSING; + this.destroy(); + } +} +const WebSocket$2 = /* @__PURE__ */ getDefaultExportFromCjs(websocket); +const { tokenChars } = validationExports; +function parse(header) { + const protocols = /* @__PURE__ */ new Set(); + let start = -1; + let end = -1; + let i = 0; + for (i; i < header.length; i++) { + const code = header.charCodeAt(i); + if (end === -1 && tokenChars[code] === 1) { + if (start === -1) + start = i; + } else if (i !== 0 && (code === 32 || code === 9)) { + if (end === -1 && start !== -1) + end = i; + } else if (code === 44) { + if (start === -1) { + throw new SyntaxError(`Unexpected character at index ${i}`); + } + if (end === -1) + end = i; + const protocol2 = header.slice(start, end); + if (protocols.has(protocol2)) { + throw new SyntaxError(`The "${protocol2}" subprotocol is duplicated`); + } + protocols.add(protocol2); + start = end = -1; + } else { + throw new SyntaxError(`Unexpected character at index ${i}`); + } + } + if (start === -1 || end !== -1) { + throw new SyntaxError("Unexpected end of input"); + } + const protocol = header.slice(start, i); + if (protocols.has(protocol)) { + throw new SyntaxError(`The "${protocol}" subprotocol is duplicated`); + } + protocols.add(protocol); + return protocols; +} +var subprotocol$1 = { parse }; +const EventEmitter = require$$0$4; +const http = require$$2$1; +const { createHash } = require$$5; +const extension = extension$1; +const PerMessageDeflate2 = permessageDeflate; +const subprotocol = subprotocol$1; +const WebSocket2 = websocket; +const { GUID, kWebSocket } = constants; +const keyRegex = /^[+/0-9A-Za-z]{22}==$/; +const RUNNING = 0; +const CLOSING = 1; +const CLOSED = 2; +class WebSocketServer extends EventEmitter { + /** + * Create a `WebSocketServer` instance. + * + * @param {Object} options Configuration options + * @param {Number} [options.backlog=511] The maximum length of the queue of + * pending connections + * @param {Boolean} [options.clientTracking=true] Specifies whether or not to + * track clients + * @param {Function} [options.handleProtocols] A hook to handle protocols + * @param {String} [options.host] The hostname where to bind the server + * @param {Number} [options.maxPayload=104857600] The maximum allowed message + * size + * @param {Boolean} [options.noServer=false] Enable no server mode + * @param {String} [options.path] Accept only connections matching this path + * @param {(Boolean|Object)} [options.perMessageDeflate=false] Enable/disable + * permessage-deflate + * @param {Number} [options.port] The port where to bind the server + * @param {(http.Server|https.Server)} [options.server] A pre-created HTTP/S + * server to use + * @param {Boolean} [options.skipUTF8Validation=false] Specifies whether or + * not to skip UTF-8 validation for text and close messages + * @param {Function} [options.verifyClient] A hook to reject connections + * @param {Function} [options.WebSocket=WebSocket] Specifies the `WebSocket` + * class to use. It must be the `WebSocket` class or class that extends it + * @param {Function} [callback] A listener for the `listening` event + */ + constructor(options, callback) { + super(); + options = { + maxPayload: 100 * 1024 * 1024, + skipUTF8Validation: false, + perMessageDeflate: false, + handleProtocols: null, + clientTracking: true, + verifyClient: null, + noServer: false, + backlog: null, + // use default (511 as implemented in net.js) + server: null, + host: null, + path: null, + port: null, + WebSocket: WebSocket2, + ...options + }; + if (options.port == null && !options.server && !options.noServer || options.port != null && (options.server || options.noServer) || options.server && options.noServer) { + throw new TypeError( + 'One and only one of the "port", "server", or "noServer" options must be specified' + ); + } + if (options.port != null) { + this._server = http.createServer((req, res) => { + const body = http.STATUS_CODES[426]; + res.writeHead(426, { + "Content-Length": body.length, + "Content-Type": "text/plain" + }); + res.end(body); + }); + this._server.listen( + options.port, + options.host, + options.backlog, + callback + ); + } else if (options.server) { + this._server = options.server; + } + if (this._server) { + const emitConnection = this.emit.bind(this, "connection"); + this._removeListeners = addListeners(this._server, { + listening: this.emit.bind(this, "listening"), + error: this.emit.bind(this, "error"), + upgrade: (req, socket, head) => { + this.handleUpgrade(req, socket, head, emitConnection); + } + }); + } + if (options.perMessageDeflate === true) + options.perMessageDeflate = {}; + if (options.clientTracking) { + this.clients = /* @__PURE__ */ new Set(); + this._shouldEmitClose = false; + } + this.options = options; + this._state = RUNNING; + } + /** + * Returns the bound address, the address family name, and port of the server + * as reported by the operating system if listening on an IP socket. + * If the server is listening on a pipe or UNIX domain socket, the name is + * returned as a string. + * + * @return {(Object|String|null)} The address of the server + * @public + */ + address() { + if (this.options.noServer) { + throw new Error('The server is operating in "noServer" mode'); + } + if (!this._server) + return null; + return this._server.address(); + } + /** + * Stop the server from accepting new connections and emit the `'close'` event + * when all existing connections are closed. + * + * @param {Function} [cb] A one-time listener for the `'close'` event + * @public + */ + close(cb) { + if (this._state === CLOSED) { + if (cb) { + this.once("close", () => { + cb(new Error("The server is not running")); + }); + } + process.nextTick(emitClose, this); + return; + } + if (cb) + this.once("close", cb); + if (this._state === CLOSING) + return; + this._state = CLOSING; + if (this.options.noServer || this.options.server) { + if (this._server) { + this._removeListeners(); + this._removeListeners = this._server = null; + } + if (this.clients) { + if (!this.clients.size) { + process.nextTick(emitClose, this); + } else { + this._shouldEmitClose = true; + } + } else { + process.nextTick(emitClose, this); + } + } else { + const server = this._server; + this._removeListeners(); + this._removeListeners = this._server = null; + server.close(() => { + emitClose(this); + }); + } + } + /** + * See if a given request should be handled by this server instance. + * + * @param {http.IncomingMessage} req Request object to inspect + * @return {Boolean} `true` if the request is valid, else `false` + * @public + */ + shouldHandle(req) { + if (this.options.path) { + const index = req.url.indexOf("?"); + const pathname = index !== -1 ? req.url.slice(0, index) : req.url; + if (pathname !== this.options.path) + return false; + } + return true; + } + /** + * Handle a HTTP Upgrade request. + * + * @param {http.IncomingMessage} req The request object + * @param {(net.Socket|tls.Socket)} socket The network socket between the + * server and client + * @param {Buffer} head The first packet of the upgraded stream + * @param {Function} cb Callback + * @public + */ + handleUpgrade(req, socket, head, cb) { + socket.on("error", socketOnError); + const key = req.headers["sec-websocket-key"]; + const version = +req.headers["sec-websocket-version"]; + if (req.method !== "GET") { + const message = "Invalid HTTP method"; + abortHandshakeOrEmitwsClientError(this, req, socket, 405, message); + return; + } + if (req.headers.upgrade.toLowerCase() !== "websocket") { + const message = "Invalid Upgrade header"; + abortHandshakeOrEmitwsClientError(this, req, socket, 400, message); + return; + } + if (!key || !keyRegex.test(key)) { + const message = "Missing or invalid Sec-WebSocket-Key header"; + abortHandshakeOrEmitwsClientError(this, req, socket, 400, message); + return; + } + if (version !== 8 && version !== 13) { + const message = "Missing or invalid Sec-WebSocket-Version header"; + abortHandshakeOrEmitwsClientError(this, req, socket, 400, message); + return; + } + if (!this.shouldHandle(req)) { + abortHandshake(socket, 400); + return; + } + const secWebSocketProtocol = req.headers["sec-websocket-protocol"]; + let protocols = /* @__PURE__ */ new Set(); + if (secWebSocketProtocol !== void 0) { + try { + protocols = subprotocol.parse(secWebSocketProtocol); + } catch (err) { + const message = "Invalid Sec-WebSocket-Protocol header"; + abortHandshakeOrEmitwsClientError(this, req, socket, 400, message); + return; + } + } + const secWebSocketExtensions = req.headers["sec-websocket-extensions"]; + const extensions = {}; + if (this.options.perMessageDeflate && secWebSocketExtensions !== void 0) { + const perMessageDeflate = new PerMessageDeflate2( + this.options.perMessageDeflate, + true, + this.options.maxPayload + ); + try { + const offers = extension.parse(secWebSocketExtensions); + if (offers[PerMessageDeflate2.extensionName]) { + perMessageDeflate.accept(offers[PerMessageDeflate2.extensionName]); + extensions[PerMessageDeflate2.extensionName] = perMessageDeflate; + } + } catch (err) { + const message = "Invalid or unacceptable Sec-WebSocket-Extensions header"; + abortHandshakeOrEmitwsClientError(this, req, socket, 400, message); + return; + } + } + if (this.options.verifyClient) { + const info = { + origin: req.headers[`${version === 8 ? "sec-websocket-origin" : "origin"}`], + secure: !!(req.socket.authorized || req.socket.encrypted), + req + }; + if (this.options.verifyClient.length === 2) { + this.options.verifyClient(info, (verified, code, message, headers) => { + if (!verified) { + return abortHandshake(socket, code || 401, message, headers); + } + this.completeUpgrade( + extensions, + key, + protocols, + req, + socket, + head, + cb + ); + }); + return; + } + if (!this.options.verifyClient(info)) + return abortHandshake(socket, 401); + } + this.completeUpgrade(extensions, key, protocols, req, socket, head, cb); + } + /** + * Upgrade the connection to WebSocket. + * + * @param {Object} extensions The accepted extensions + * @param {String} key The value of the `Sec-WebSocket-Key` header + * @param {Set} protocols The subprotocols + * @param {http.IncomingMessage} req The request object + * @param {(net.Socket|tls.Socket)} socket The network socket between the + * server and client + * @param {Buffer} head The first packet of the upgraded stream + * @param {Function} cb Callback + * @throws {Error} If called more than once with the same socket + * @private + */ + completeUpgrade(extensions, key, protocols, req, socket, head, cb) { + if (!socket.readable || !socket.writable) + return socket.destroy(); + if (socket[kWebSocket]) { + throw new Error( + "server.handleUpgrade() was called more than once with the same socket, possibly due to a misconfiguration" + ); + } + if (this._state > RUNNING) + return abortHandshake(socket, 503); + const digest = createHash("sha1").update(key + GUID).digest("base64"); + const headers = [ + "HTTP/1.1 101 Switching Protocols", + "Upgrade: websocket", + "Connection: Upgrade", + `Sec-WebSocket-Accept: ${digest}` + ]; + const ws = new this.options.WebSocket(null); + if (protocols.size) { + const protocol = this.options.handleProtocols ? this.options.handleProtocols(protocols, req) : protocols.values().next().value; + if (protocol) { + headers.push(`Sec-WebSocket-Protocol: ${protocol}`); + ws._protocol = protocol; + } + } + if (extensions[PerMessageDeflate2.extensionName]) { + const params = extensions[PerMessageDeflate2.extensionName].params; + const value = extension.format({ + [PerMessageDeflate2.extensionName]: [params] + }); + headers.push(`Sec-WebSocket-Extensions: ${value}`); + ws._extensions = extensions; + } + this.emit("headers", headers, req); + socket.write(headers.concat("\r\n").join("\r\n")); + socket.removeListener("error", socketOnError); + ws.setSocket(socket, head, { + maxPayload: this.options.maxPayload, + skipUTF8Validation: this.options.skipUTF8Validation + }); + if (this.clients) { + this.clients.add(ws); + ws.on("close", () => { + this.clients.delete(ws); + if (this._shouldEmitClose && !this.clients.size) { + process.nextTick(emitClose, this); + } + }); + } + cb(ws, req); + } +} +var websocketServer = WebSocketServer; +function addListeners(server, map) { + for (const event of Object.keys(map)) + server.on(event, map[event]); + return function removeListeners() { + for (const event of Object.keys(map)) { + server.removeListener(event, map[event]); + } + }; +} +function emitClose(server) { + server._state = CLOSED; + server.emit("close"); +} +function socketOnError() { + this.destroy(); +} +function abortHandshake(socket, code, message, headers) { + message = message || http.STATUS_CODES[code]; + headers = { + Connection: "close", + "Content-Type": "text/html", + "Content-Length": Buffer.byteLength(message), + ...headers + }; + socket.once("finish", socket.destroy); + socket.end( + `HTTP/1.1 ${code} ${http.STATUS_CODES[code]}\r +` + Object.keys(headers).map((h) => `${h}: ${headers[h]}`).join("\r\n") + "\r\n\r\n" + message + ); +} +function abortHandshakeOrEmitwsClientError(server, req, socket, code, message) { + if (server.listenerCount("wsClientError")) { + const err = new Error(message); + Error.captureStackTrace(err, abortHandshakeOrEmitwsClientError); + server.emit("wsClientError", err, socket, req); + } else { + abortHandshake(socket, code, message); + } +} +const websocketServer$1 = /* @__PURE__ */ getDefaultExportFromCjs(websocketServer); +export { + receiver$1 as Receiver, + sender$1 as Sender, + WebSocket$2 as WebSocket, + websocketServer$1 as WebSocketServer, + stream$1 as createWebSocketStream, + WebSocket$2 as default +}; diff --git a/node_modules/@gradio/client/gradio-client-1.4.0.tgz b/node_modules/@gradio/client/gradio-client-1.4.0.tgz new file mode 100644 index 0000000000000000000000000000000000000000..ec75cdb6718a719b946a31afe20d15eb96c00241 --- /dev/null +++ b/node_modules/@gradio/client/gradio-client-1.4.0.tgz @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:5d3e9c3aace85743e2d5a3f6997415ade0cb41407ee538fc220f684714488506 +size 104374 diff --git a/node_modules/@gradio/client/index.html b/node_modules/@gradio/client/index.html new file mode 100644 index 0000000000000000000000000000000000000000..1afd437873ac0e0ad160a577a5fb325dcb07142b --- /dev/null +++ b/node_modules/@gradio/client/index.html @@ -0,0 +1,39 @@ + + + + + + + Client + + + +
+ + diff --git a/node_modules/@gradio/client/package.json b/node_modules/@gradio/client/package.json new file mode 100644 index 0000000000000000000000000000000000000000..63e2aca590d7a514d56ca08319707be8952956a0 --- /dev/null +++ b/node_modules/@gradio/client/package.json @@ -0,0 +1,49 @@ +{ + "name": "@gradio/client", + "version": "1.14.1", + "description": "Gradio API client", + "type": "module", + "main": "dist/index.js", + "author": "", + "license": "ISC", + "exports": { + ".": { + "gradio": "./src/index.ts", + "import": "./dist/index.js" + }, + "./package.json": "./package.json" + }, + "dependencies": { + "@types/eventsource": "^1.1.15", + "bufferutil": "^4.0.7", + "eventsource": "^2.0.2", + "fetch-event-stream": "^0.1.5", + "msw": "^2.2.1", + "semiver": "^1.1.0", + "textlinestream": "^1.1.1", + "typescript": "^5.0.0", + "ws": "^8.13.0" + }, + "devDependencies": { + "@types/ws": "^8.5.10", + "esbuild": "^0.21.0" + }, + "engines": { + "node": ">=18.0.0" + }, + "main_changeset": true, + "repository": { + "type": "git", + "url": "git+https://github.com/gradio-app/gradio.git", + "directory": "client/js" + }, + "scripts": { + "bundle": "vite build --ssr", + "generate_types": "tsc", + "build": "pnpm bundle && pnpm generate_types", + "test": "pnpm test:client && pnpm test:client:node", + "test:client": "vitest run -c vite.config.js", + "test:client:node": "TEST_MODE=node vitest run -c vite.config.js", + "preview:browser": "vite dev --mode=preview" + } +} \ No newline at end of file diff --git a/node_modules/@gradio/client/src/client.ts b/node_modules/@gradio/client/src/client.ts new file mode 100644 index 0000000000000000000000000000000000000000..a790eb4b5a3d751bf00bdf224e180aefb95ffee6 --- /dev/null +++ b/node_modules/@gradio/client/src/client.ts @@ -0,0 +1,580 @@ +import type { + ApiData, + ApiInfo, + ClientOptions, + Config, + DuplicateOptions, + EndpointInfo, + JsApiData, + PredictReturn, + SpaceStatus, + Status, + UploadResponse, + client_return, + SubmitIterable, + GradioEvent +} from "./types"; +import { view_api } from "./utils/view_api"; +import { upload_files } from "./utils/upload_files"; +import { upload, FileData } from "./upload"; +import { handle_blob } from "./utils/handle_blob"; +import { post_data } from "./utils/post_data"; +import { predict } from "./utils/predict"; +import { duplicate } from "./utils/duplicate"; +import { submit } from "./utils/submit"; +import { RE_SPACE_NAME, process_endpoint } from "./helpers/api_info"; +import { + map_names_to_ids, + resolve_cookies, + resolve_config, + get_jwt, + parse_and_set_cookies +} from "./helpers/init_helpers"; +import { check_and_wake_space, check_space_status } from "./helpers/spaces"; +import { open_stream, readable_stream, close_stream } from "./utils/stream"; +import { + API_INFO_ERROR_MSG, + CONFIG_ERROR_MSG, + HEARTBEAT_URL, + COMPONENT_SERVER_URL +} from "./constants"; + +export class Client { + app_reference: string; + options: ClientOptions; + deep_link: string | null = null; + + config: Config | undefined; + api_prefix = ""; + api_info: ApiInfo | undefined; + api_map: Record = {}; + session_hash: string = Math.random().toString(36).substring(2); + jwt: string | false = false; + last_status: Record = {}; + + private cookies: string | null = null; + + // streaming + stream_status = { open: false }; + closed = false; + pending_stream_messages: Record = {}; + pending_diff_streams: Record = {}; + event_callbacks: Record Promise> = {}; + unclosed_events: Set = new Set(); + heartbeat_event: EventSource | null = null; + abort_controller: AbortController | null = null; + stream_instance: EventSource | null = null; + current_payload: any; + ws_map: Record = {}; + + get_url_config(url: string | null = null): Config { + if (!this.config) { + throw new Error(CONFIG_ERROR_MSG); + } + if (url === null) { + url = window.location.href; + } + const stripSlashes = (str: string): string => str.replace(/^\/+|\/+$/g, ""); + let root_path = stripSlashes(new URL(this.config.root).pathname); + let url_path = stripSlashes(new URL(url).pathname); + let page: string; + if (!url_path.startsWith(root_path)) { + page = ""; + } else { + page = stripSlashes(url_path.substring(root_path.length)); + } + return this.get_page_config(page); + } + get_page_config(page: string): Config { + if (!this.config) { + throw new Error(CONFIG_ERROR_MSG); + } + let config = this.config; + if (!(page in config.page)) { + page = ""; + } + return { + ...config, + current_page: page, + layout: config.page[page].layout, + components: config.components.filter((c) => + config.page[page].components.includes(c.id) + ), + dependencies: this.config.dependencies.filter((d) => + config.page[page].dependencies.includes(d.id) + ) + }; + } + + fetch(input: RequestInfo | URL, init?: RequestInit): Promise { + const headers = new Headers(init?.headers || {}); + if (this && this.cookies) { + headers.append("Cookie", this.cookies); + } + if (this && this.options.headers) { + for (const name in this.options.headers) { + headers.append(name, this.options.headers[name]); + } + } + + return fetch(input, { ...init, headers }); + } + + stream(url: URL): EventSource { + const headers = new Headers(); + if (this && this.cookies) { + headers.append("Cookie", this.cookies); + } + if (this && this.options.headers) { + for (const name in this.options.headers) { + headers.append(name, this.options.headers[name]); + } + } + + this.abort_controller = new AbortController(); + + this.stream_instance = readable_stream(url.toString(), { + credentials: "include", + headers: headers, + signal: this.abort_controller.signal + }); + + return this.stream_instance; + } + + view_api: () => Promise>; + upload_files: ( + root_url: string, + files: (Blob | File)[], + upload_id?: string + ) => Promise; + upload: ( + file_data: FileData[], + root_url: string, + upload_id?: string, + max_file_size?: number + ) => Promise<(FileData | null)[] | null>; + handle_blob: ( + endpoint: string, + data: unknown[], + endpoint_info: EndpointInfo + ) => Promise; + post_data: ( + url: string, + body: unknown, + additional_headers?: any + ) => Promise; + submit: ( + endpoint: string | number, + data: unknown[] | Record | undefined, + event_data?: unknown, + trigger_id?: number | null, + all_events?: boolean + ) => SubmitIterable; + predict: ( + endpoint: string | number, + data: unknown[] | Record | undefined, + event_data?: unknown + ) => Promise; + open_stream: () => Promise; + private resolve_config: (endpoint: string) => Promise; + private resolve_cookies: () => Promise; + constructor( + app_reference: string, + options: ClientOptions = { events: ["data"] } + ) { + this.app_reference = app_reference; + this.deep_link = options.query_params?.deep_link || null; + if (!options.events) { + options.events = ["data"]; + } + + this.options = options; + this.current_payload = {}; + this.view_api = view_api.bind(this); + this.upload_files = upload_files.bind(this); + this.handle_blob = handle_blob.bind(this); + this.post_data = post_data.bind(this); + this.submit = submit.bind(this); + this.predict = predict.bind(this); + this.open_stream = open_stream.bind(this); + this.resolve_config = resolve_config.bind(this); + this.resolve_cookies = resolve_cookies.bind(this); + this.upload = upload.bind(this); + this.fetch = this.fetch.bind(this); + this.handle_space_success = this.handle_space_success.bind(this); + this.stream = this.stream.bind(this); + } + + private async init(): Promise { + if ( + (typeof window === "undefined" || !("WebSocket" in window)) && + !global.WebSocket + ) { + const ws = await import("ws"); + global.WebSocket = ws.WebSocket as unknown as typeof WebSocket; + } + + if (this.options.auth) { + await this.resolve_cookies(); + } + + await this._resolve_config().then(({ config }) => + this._resolve_hearbeat(config) + ); + + this.api_info = await this.view_api(); + this.api_map = map_names_to_ids(this.config?.dependencies || []); + } + + async _resolve_hearbeat(_config: Config): Promise { + if (_config) { + this.config = _config; + this.api_prefix = _config.api_prefix || ""; + + if (this.config && this.config.connect_heartbeat) { + if (this.config.space_id && this.options.hf_token) { + this.jwt = await get_jwt( + this.config.space_id, + this.options.hf_token, + this.cookies + ); + } + } + } + + if (_config.space_id && this.options.hf_token) { + this.jwt = await get_jwt(_config.space_id, this.options.hf_token); + } + + if (this.config && this.config.connect_heartbeat) { + // connect to the heartbeat endpoint via GET request + const heartbeat_url = new URL( + `${this.config.root}${this.api_prefix}/${HEARTBEAT_URL}/${this.session_hash}` + ); + + // if the jwt is available, add it to the query params + if (this.jwt) { + heartbeat_url.searchParams.set("__sign", this.jwt); + } + + // Just connect to the endpoint without parsing the response. Ref: https://github.com/gradio-app/gradio/pull/7974#discussion_r1557717540 + if (!this.heartbeat_event) { + this.heartbeat_event = this.stream(heartbeat_url); + } + } + } + + static async connect( + app_reference: string, + options: ClientOptions = { + events: ["data"] + } + ): Promise { + const client = new this(app_reference, options); // this refers to the class itself, not the instance + await client.init(); + return client; + } + + close(): void { + this.closed = true; + close_stream(this.stream_status, this.abort_controller); + } + + set_current_payload(payload: any): void { + this.current_payload = payload; + } + + static async duplicate( + app_reference: string, + options: DuplicateOptions = { + events: ["data"] + } + ): Promise { + return duplicate(app_reference, options); + } + + private async _resolve_config(): Promise { + const { http_protocol, host, space_id } = await process_endpoint( + this.app_reference, + this.options.hf_token + ); + + const { status_callback } = this.options; + + if (space_id && status_callback) { + await check_and_wake_space(space_id, status_callback); + } + + let config: Config | undefined; + + try { + // Create base URL + let configUrl = `${http_protocol}//${host}`; + config = await this.resolve_config(configUrl); + + if (!config) { + throw new Error(CONFIG_ERROR_MSG); + } + + return this.config_success(config); + } catch (e: any) { + if (space_id && status_callback) { + check_space_status( + space_id, + RE_SPACE_NAME.test(space_id) ? "space_name" : "subdomain", + this.handle_space_success + ); + } else { + if (status_callback) + status_callback({ + status: "error", + message: "Could not load this space.", + load_status: "error", + detail: "NOT_FOUND" + }); + throw Error(e); + } + } + } + + private async config_success( + _config: Config + ): Promise { + this.config = _config; + this.api_prefix = _config.api_prefix || ""; + + if (typeof window !== "undefined" && typeof document !== "undefined") { + if (window.location.protocol === "https:") { + this.config.root = this.config.root.replace("http://", "https://"); + } + } + + if (this.config.auth_required) { + return this.prepare_return_obj(); + } + + try { + this.api_info = await this.view_api(); + } catch (e) { + console.error(API_INFO_ERROR_MSG + (e as Error).message); + } + + return this.prepare_return_obj(); + } + + async handle_space_success(status: SpaceStatus): Promise { + if (!this) { + throw new Error(CONFIG_ERROR_MSG); + } + const { status_callback } = this.options; + if (status_callback) status_callback(status); + if (status.status === "running") { + try { + this.config = await this._resolve_config(); + this.api_prefix = this?.config?.api_prefix || ""; + + if (!this.config) { + throw new Error(CONFIG_ERROR_MSG); + } + + const _config = await this.config_success(this.config); + + return _config as Config; + } catch (e) { + if (status_callback) { + status_callback({ + status: "error", + message: "Could not load this space.", + load_status: "error", + detail: "NOT_FOUND" + }); + } + throw e; + } + } + } + + public async component_server( + component_id: number, + fn_name: string, + data: unknown[] | { binary: boolean; data: Record } + ): Promise { + if (!this.config) { + throw new Error(CONFIG_ERROR_MSG); + } + + const headers: { + Authorization?: string; + "Content-Type"?: "application/json"; + } = {}; + + const { hf_token } = this.options; + const { session_hash } = this; + + if (hf_token) { + headers.Authorization = `Bearer ${this.options.hf_token}`; + } + + let root_url: string; + let component = this.config.components.find( + (comp) => comp.id === component_id + ); + if (component?.props?.root_url) { + root_url = component.props.root_url; + } else { + root_url = this.config.root; + } + + let body: FormData | string; + + if ("binary" in data) { + body = new FormData(); + for (const key in data.data) { + if (key === "binary") continue; + body.append(key, data.data[key]); + } + body.set("component_id", component_id.toString()); + body.set("fn_name", fn_name); + body.set("session_hash", session_hash); + } else { + body = JSON.stringify({ + data: data, + component_id, + fn_name, + session_hash + }); + + headers["Content-Type"] = "application/json"; + } + + if (hf_token) { + headers.Authorization = `Bearer ${hf_token}`; + } + + try { + const response = await this.fetch( + `${root_url}${this.api_prefix}/${COMPONENT_SERVER_URL}/`, + { + method: "POST", + body: body, + headers, + credentials: "include" + } + ); + + if (!response.ok) { + throw new Error( + "Could not connect to component server: " + response.statusText + ); + } + + const output = await response.json(); + return output; + } catch (e) { + console.warn(e); + } + } + + public set_cookies(raw_cookies: string): void { + this.cookies = parse_and_set_cookies(raw_cookies).join("; "); + } + + private prepare_return_obj(): client_return { + return { + config: this.config, + predict: this.predict, + submit: this.submit, + view_api: this.view_api, + component_server: this.component_server + }; + } + + private async connect_ws(url: string): Promise { + return new Promise((resolve, reject) => { + let ws; + try { + ws = new WebSocket(url); + } catch (e) { + this.ws_map[url] = "failed"; + return; + } + + ws.onopen = () => { + resolve(); + }; + + ws.onerror = (error) => { + console.error("WebSocket error:", error); + this.close_ws(url); + this.ws_map[url] = "failed"; + resolve(); + }; + + ws.onclose = () => { + delete this.ws_map[url]; + this.ws_map[url] = "failed"; + }; + + ws.onmessage = (event) => {}; + this.ws_map[url] = ws; + }); + } + + async send_ws_message(url: string, data: any): Promise { + // connect if not connected + if (!(url in this.ws_map)) { + await this.connect_ws(url); + } + const ws = this.ws_map[url]; + if (ws instanceof WebSocket) { + ws.send(JSON.stringify(data)); + } else { + this.post_data(url, data); + } + } + + async close_ws(url: string): Promise { + if (url in this.ws_map) { + const ws = this.ws_map[url]; + if (ws instanceof WebSocket) { + ws.close(); + delete this.ws_map[url]; + } + } + } +} + +/** + * @deprecated This method will be removed in v1.0. Use `Client.connect()` instead. + * Creates a client instance for interacting with Gradio apps. + * + * @param {string} app_reference - The reference or URL to a Gradio space or app. + * @param {ClientOptions} options - Configuration options for the client. + * @returns {Promise} A promise that resolves to a `Client` instance. + */ +export async function client( + app_reference: string, + options: ClientOptions = { + events: ["data"] + } +): Promise { + return await Client.connect(app_reference, options); +} + +/** + * @deprecated This method will be removed in v1.0. Use `Client.duplicate()` instead. + * Creates a duplicate of a space and returns a client instance for the duplicated space. + * + * @param {string} app_reference - The reference or URL to a Gradio space or app to duplicate. + * @param {DuplicateOptions} options - Configuration options for the client. + * @returns {Promise} A promise that resolves to a `Client` instance. + */ +export async function duplicate_space( + app_reference: string, + options: DuplicateOptions +): Promise { + return await Client.duplicate(app_reference, options); +} + +export type ClientInstance = Client; diff --git a/node_modules/@gradio/client/src/constants.ts b/node_modules/@gradio/client/src/constants.ts new file mode 100644 index 0000000000000000000000000000000000000000..1dbce9880c3142b5e2ed5bf1a775311ada85025f --- /dev/null +++ b/node_modules/@gradio/client/src/constants.ts @@ -0,0 +1,40 @@ +// endpoints +export const HOST_URL = `host`; +export const API_URL = `predict/`; +export const SSE_URL_V0 = `queue/join`; +export const SSE_DATA_URL_V0 = `queue/data`; +export const SSE_URL = `queue/data`; +export const SSE_DATA_URL = `queue/join`; +export const UPLOAD_URL = `upload`; +export const LOGIN_URL = `login`; +export const CONFIG_URL = `config`; +export const API_INFO_URL = `info`; +export const RUNTIME_URL = `runtime`; +export const SLEEPTIME_URL = `sleeptime`; +export const HEARTBEAT_URL = `heartbeat`; +export const COMPONENT_SERVER_URL = `component_server`; +export const RESET_URL = `reset`; +export const CANCEL_URL = `cancel`; + +export const RAW_API_INFO_URL = `info?serialize=False`; +export const SPACE_FETCHER_URL = + "https://gradio-space-api-fetcher-v2.hf.space/api"; +export const SPACE_URL = "https://hf.space/{}"; + +// messages +export const QUEUE_FULL_MSG = + "This application is currently busy. Please try again. "; +export const BROKEN_CONNECTION_MSG = "Connection errored out. "; +export const CONFIG_ERROR_MSG = "Could not resolve app config. "; +export const SPACE_STATUS_ERROR_MSG = "Could not get space status. "; +export const API_INFO_ERROR_MSG = "Could not get API info. "; +export const SPACE_METADATA_ERROR_MSG = "Space metadata could not be loaded. "; +export const INVALID_URL_MSG = "Invalid URL. A full URL path is required."; +export const UNAUTHORIZED_MSG = "Not authorized to access this space. "; +export const INVALID_CREDENTIALS_MSG = "Invalid credentials. Could not login. "; +export const MISSING_CREDENTIALS_MSG = + "Login credentials are required to access this space."; +export const NODEJS_FS_ERROR_MSG = + "File system access is only available in Node.js environments"; +export const ROOT_URL_ERROR_MSG = "Root URL not found in client config"; +export const FILE_PROCESSING_ERROR_MSG = "Error uploading file"; diff --git a/node_modules/@gradio/client/src/globals.d.ts b/node_modules/@gradio/client/src/globals.d.ts new file mode 100644 index 0000000000000000000000000000000000000000..e0e63a07dbfbf91c29259c4e5834f51d64493d61 --- /dev/null +++ b/node_modules/@gradio/client/src/globals.d.ts @@ -0,0 +1,12 @@ +import { ApiData, ApiInfo, Config } from "./types"; + +declare global { + interface Window { + __gradio_mode__: "app" | "website"; + gradio_config: Config; + gradio_api_info: ApiInfo | { api: ApiInfo }; + __is_colab__: boolean; + __gradio_space__: string | null; + supports_zerogpu_headers?: boolean; + } +} diff --git a/node_modules/@gradio/client/src/helpers/api_info.ts b/node_modules/@gradio/client/src/helpers/api_info.ts new file mode 100644 index 0000000000000000000000000000000000000000..ba68bc4b8fac7bdc9bbc92d9fb92eab1358f229a --- /dev/null +++ b/node_modules/@gradio/client/src/helpers/api_info.ts @@ -0,0 +1,460 @@ +import { + HOST_URL, + INVALID_URL_MSG, + QUEUE_FULL_MSG, + SPACE_METADATA_ERROR_MSG +} from "../constants"; +import type { + ApiData, + ApiInfo, + Config, + JsApiData, + EndpointInfo, + Status +} from "../types"; +import { determine_protocol } from "./init_helpers"; + +export const RE_SPACE_NAME = /^[a-zA-Z0-9_\-\.]+\/[a-zA-Z0-9_\-\.]+$/; +export const RE_SPACE_DOMAIN = /.*hf\.space\/{0,1}.*$/; + +export async function process_endpoint( + app_reference: string, + hf_token?: `hf_${string}` +): Promise<{ + space_id: string | false; + host: string; + ws_protocol: "ws" | "wss"; + http_protocol: "http:" | "https:"; +}> { + const headers: { Authorization?: string } = {}; + if (hf_token) { + headers.Authorization = `Bearer ${hf_token}`; + } + + const _app_reference = app_reference.trim().replace(/\/$/, ""); + + if (RE_SPACE_NAME.test(_app_reference)) { + // app_reference is a HF space name + try { + const res = await fetch( + `https://huggingface.co/api/spaces/${_app_reference}/${HOST_URL}`, + { headers } + ); + + const _host = (await res.json()).host; + + return { + space_id: app_reference, + ...determine_protocol(_host) + }; + } catch (e) { + throw new Error(SPACE_METADATA_ERROR_MSG); + } + } + + if (RE_SPACE_DOMAIN.test(_app_reference)) { + // app_reference is a direct HF space domain + const { ws_protocol, http_protocol, host } = + determine_protocol(_app_reference); + + return { + space_id: host.split("/")[0].replace(".hf.space", ""), + ws_protocol, + http_protocol, + host + }; + } + + return { + space_id: false, + ...determine_protocol(_app_reference) + }; +} + +export const join_urls = (...urls: string[]): string => { + try { + return urls.reduce((base_url: string, part: string) => { + base_url = base_url.replace(/\/+$/, ""); + part = part.replace(/^\/+/, ""); + return new URL(part, base_url + "/").toString(); + }); + } catch (e) { + throw new Error(INVALID_URL_MSG); + } +}; + +export function transform_api_info( + api_info: ApiInfo, + config: Config, + api_map: Record +): ApiInfo { + const transformed_info: ApiInfo = { + named_endpoints: {}, + unnamed_endpoints: {} + }; + + Object.keys(api_info).forEach((category) => { + if (category === "named_endpoints" || category === "unnamed_endpoints") { + transformed_info[category] = {}; + + Object.entries(api_info[category]).forEach( + ([endpoint, { parameters, returns }]) => { + const dependencyIndex = + config.dependencies.find( + (dep) => + dep.api_name === endpoint || + dep.api_name === endpoint.replace("/", "") + )?.id || + api_map[endpoint.replace("/", "")] || + -1; + + const dependencyTypes = + dependencyIndex !== -1 + ? config.dependencies.find((dep) => dep.id == dependencyIndex) + ?.types + : { generator: false, cancel: false }; + + if ( + dependencyIndex !== -1 && + config.dependencies.find((dep) => dep.id == dependencyIndex)?.inputs + ?.length !== parameters.length + ) { + const components = config.dependencies + .find((dep) => dep.id == dependencyIndex)! + .inputs.map( + (input) => config.components.find((c) => c.id === input)?.type + ); + + try { + components.forEach((comp, idx) => { + if (comp === "state") { + const new_param = { + component: "state", + example: null, + parameter_default: null, + parameter_has_default: true, + parameter_name: null, + hidden: true + }; + + // @ts-ignore + parameters.splice(idx, 0, new_param); + } + }); + } catch (e) { + console.error(e); + } + } + + const transform_type = ( + data: ApiData, + component: string, + serializer: string, + signature_type: "return" | "parameter" + ): JsApiData => ({ + ...data, + description: get_description(data?.type, serializer), + type: + get_type(data?.type, component, serializer, signature_type) || "" + }); + + transformed_info[category][endpoint] = { + parameters: parameters.map((p: ApiData) => + transform_type(p, p?.component, p?.serializer, "parameter") + ), + returns: returns.map((r: ApiData) => + transform_type(r, r?.component, r?.serializer, "return") + ), + type: dependencyTypes + }; + } + ); + } + }); + + return transformed_info; +} + +export function get_type( + type: { type: any; description: string }, + component: string, + serializer: string, + signature_type: "return" | "parameter" +): string | undefined { + if (component === "Api") return type.type; + switch (type?.type) { + case "string": + return "string"; + case "boolean": + return "boolean"; + case "number": + return "number"; + } + + if ( + serializer === "JSONSerializable" || + serializer === "StringSerializable" + ) { + return "any"; + } else if (serializer === "ListStringSerializable") { + return "string[]"; + } else if (component === "Image") { + return signature_type === "parameter" ? "Blob | File | Buffer" : "string"; + } else if (serializer === "FileSerializable") { + if (type?.type === "array") { + return signature_type === "parameter" + ? "(Blob | File | Buffer)[]" + : `{ name: string; data: string; size?: number; is_file?: boolean; orig_name?: string}[]`; + } + return signature_type === "parameter" + ? "Blob | File | Buffer" + : `{ name: string; data: string; size?: number; is_file?: boolean; orig_name?: string}`; + } else if (serializer === "GallerySerializable") { + return signature_type === "parameter" + ? "[(Blob | File | Buffer), (string | null)][]" + : `[{ name: string; data: string; size?: number; is_file?: boolean; orig_name?: string}, (string | null))][]`; + } +} + +export function get_description( + type: { type: any; description: string }, + serializer: string +): string { + if (serializer === "GallerySerializable") { + return "array of [file, label] tuples"; + } else if (serializer === "ListStringSerializable") { + return "array of strings"; + } else if (serializer === "FileSerializable") { + return "array of files or single file"; + } + return type?.description; +} + +/* eslint-disable complexity */ +export function handle_message( + data: any, + last_status: Status["stage"] +): { + type: + | "hash" + | "data" + | "update" + | "complete" + | "generating" + | "log" + | "none" + | "heartbeat" + | "streaming" + | "unexpected_error"; + data?: any; + status?: Status; + original_msg?: string; +} { + const queue = true; + switch (data.msg) { + case "send_data": + return { type: "data" }; + case "send_hash": + return { type: "hash" }; + case "queue_full": + return { + type: "update", + status: { + queue, + message: QUEUE_FULL_MSG, + stage: "error", + code: data.code, + success: data.success + } + }; + case "heartbeat": + return { + type: "heartbeat" + }; + case "unexpected_error": + return { + type: "unexpected_error", + status: { + queue, + message: data.message, + stage: "error", + success: false + } + }; + case "estimation": + return { + type: "update", + status: { + queue, + stage: last_status || "pending", + code: data.code, + size: data.queue_size, + position: data.rank, + eta: data.rank_eta, + success: data.success + } + }; + case "progress": + return { + type: "update", + status: { + queue, + stage: "pending", + code: data.code, + progress_data: data.progress_data, + success: data.success + } + }; + case "log": + return { type: "log", data: data }; + case "process_generating": + return { + type: "generating", + status: { + queue, + message: !data.success ? data.output.error : null, + stage: data.success ? "generating" : "error", + code: data.code, + progress_data: data.progress_data, + eta: data.average_duration, + changed_state_ids: data.success + ? data.output.changed_state_ids + : undefined + }, + data: data.success ? data.output : null + }; + case "process_streaming": + return { + type: "streaming", + status: { + queue, + message: data.output.error, + stage: "streaming", + time_limit: data.time_limit, + code: data.code, + progress_data: data.progress_data, + eta: data.eta + }, + data: data.output + }; + case "process_completed": + if ("error" in data.output) { + return { + type: "update", + status: { + queue, + title: data.output.title as string, + message: data.output.error as string, + visible: data.output.visible as boolean, + duration: data.output.duration as number, + stage: "error", + code: data.code, + success: data.success + } + }; + } + return { + type: "complete", + status: { + queue, + message: !data.success ? data.output.error : undefined, + stage: data.success ? "complete" : "error", + code: data.code, + progress_data: data.progress_data, + changed_state_ids: data.success + ? data.output.changed_state_ids + : undefined + }, + data: data.success ? data.output : null + }; + + case "process_starts": + return { + type: "update", + status: { + queue, + stage: "pending", + code: data.code, + size: data.rank, + position: 0, + success: data.success, + eta: data.eta + }, + original_msg: "process_starts" + }; + } + + return { type: "none", status: { stage: "error", queue } }; +} +/* eslint-enable complexity */ + +/** + * Maps the provided `data` to the parameters defined by the `/info` endpoint response. + * This allows us to support both positional and keyword arguments passed to the client + * and ensures that all parameters are either directly provided or have default values assigned. + * + * @param {unknown[] | Record} data - The input data for the function, + * which can be either an array of values for positional arguments or an object + * with key-value pairs for keyword arguments. + * @param {JsApiData[]} parameters - Array of parameter descriptions retrieved from the + * `/info` endpoint. + * + * @returns {unknown[]} - Returns an array of resolved data where each element corresponds + * to the expected parameter from the API. The `parameter_default` value is used where + * a value is not provided for a parameter, and optional parameters without defaults are + * set to `undefined`. + * + * @throws {Error} - Throws an error: + * - If more arguments are provided than are defined in the parameters. + * * - If no parameter value is provided for a required parameter and no default value is defined. + * - If an argument is provided that does not match any defined parameter. + */ + +export const map_data_to_params = ( + data: unknown[] | Record = [], + endpoint_info: EndpointInfo +): unknown[] => { + // Workaround for the case where the endpoint_info is undefined + // See https://github.com/gradio-app/gradio/pull/8820#issuecomment-2237381761 + const parameters = endpoint_info ? endpoint_info.parameters : []; + + if (Array.isArray(data)) { + if (data.length > parameters.length) { + console.warn("Too many arguments provided for the endpoint."); + } + return data; + } + + const resolved_data: unknown[] = []; + const provided_keys = Object.keys(data); + + parameters.forEach((param, index) => { + if (data.hasOwnProperty(param.parameter_name)) { + resolved_data[index] = data[param.parameter_name]; + } else if (param.parameter_has_default) { + resolved_data[index] = param.parameter_default; + } else { + throw new Error( + `No value provided for required parameter: ${param.parameter_name}` + ); + } + }); + + provided_keys.forEach((key) => { + if (!parameters.some((param) => param.parameter_name === key)) { + throw new Error( + `Parameter \`${key}\` is not a valid keyword argument. Please refer to the API for usage.` + ); + } + }); + + resolved_data.forEach((value, idx) => { + if (value === undefined && !parameters[idx].parameter_has_default) { + throw new Error( + `No value provided for required parameter: ${parameters[idx].parameter_name}` + ); + } + }); + + return resolved_data; +}; diff --git a/node_modules/@gradio/client/src/helpers/data.ts b/node_modules/@gradio/client/src/helpers/data.ts new file mode 100644 index 0000000000000000000000000000000000000000..a79cd2eb4d0ae659e4c283ca147cfcd32d3e91a2 --- /dev/null +++ b/node_modules/@gradio/client/src/helpers/data.ts @@ -0,0 +1,221 @@ +import { + type ApiData, + type BlobRef, + type Config, + type EndpointInfo, + type JsApiData, + type DataType, + Command, + type Dependency, + type ComponentMeta +} from "../types"; +import { FileData } from "../upload"; + +const is_node = + typeof process !== "undefined" && process.versions && process.versions.node; + +export function update_object( + object: { [x: string]: any }, + newValue: any, + stack: (string | number)[] +): void { + while (stack.length > 1) { + const key = stack.shift(); + if (typeof key === "string" || typeof key === "number") { + object = object[key]; + } else { + throw new Error("Invalid key type"); + } + } + + const key = stack.shift(); + if (typeof key === "string" || typeof key === "number") { + object[key] = newValue; + } else { + throw new Error("Invalid key type"); + } +} + +export async function walk_and_store_blobs( + data: DataType, + type: string | undefined = undefined, + path: string[] = [], + root = false, + endpoint_info: EndpointInfo | undefined = undefined +): Promise { + if (Array.isArray(data)) { + let blob_refs: BlobRef[] = []; + + await Promise.all( + data.map(async (_, index) => { + let new_path = path.slice(); + new_path.push(String(index)); + + const array_refs = await walk_and_store_blobs( + data[index], + root + ? endpoint_info?.parameters[index]?.component || undefined + : type, + new_path, + false, + endpoint_info + ); + + blob_refs = blob_refs.concat(array_refs); + }) + ); + + return blob_refs; + } else if ( + (globalThis.Buffer && data instanceof globalThis.Buffer) || + data instanceof Blob + ) { + return [ + { + path: path, + blob: new Blob([data]), + type + } + ]; + } else if (typeof data === "object" && data !== null) { + let blob_refs: BlobRef[] = []; + for (const key of Object.keys(data) as (keyof typeof data)[]) { + const new_path = [...path, key]; + const value = data[key]; + + blob_refs = blob_refs.concat( + await walk_and_store_blobs( + value, + undefined, + new_path, + false, + endpoint_info + ) + ); + } + + return blob_refs; + } + + return []; +} + +export function skip_queue(id: number, config: Config): boolean { + let fn_queue = config?.dependencies?.find((dep) => dep.id == id)?.queue; + if (fn_queue != null) { + return !fn_queue; + } + return !config.enable_queue; +} + +// todo: add jsdoc for this function + +export function post_message( + message: any, + origin: string +): Promise { + return new Promise((res, _rej) => { + const channel = new MessageChannel(); + channel.port1.onmessage = (({ data }) => { + channel.port1.close(); + res(data); + }) as (ev: MessageEvent) => void; + window.parent.postMessage(message, origin, [channel.port2]); + }); +} + +export function handle_file( + file_or_url: File | string | Blob | Buffer +): FileData | Blob | Command { + if (typeof file_or_url === "string") { + if ( + file_or_url.startsWith("http://") || + file_or_url.startsWith("https://") + ) { + return { + path: file_or_url, + url: file_or_url, + orig_name: file_or_url.split("/").pop() ?? "unknown", + meta: { _type: "gradio.FileData" } + }; + } + + if (is_node) { + // Handle local file paths + return new Command("upload_file", { + path: file_or_url, + name: file_or_url, + orig_path: file_or_url + }); + } + } else if (typeof File !== "undefined" && file_or_url instanceof File) { + return new Blob([file_or_url]); + } else if (file_or_url instanceof Buffer) { + return new Blob([file_or_url]); + } else if (file_or_url instanceof Blob) { + return file_or_url; + } + throw new Error( + "Invalid input: must be a URL, File, Blob, or Buffer object." + ); +} + +/** + * Handles the payload by filtering out state inputs and returning an array of resolved payload values. + * We send null values for state inputs to the server, but we don't want to include them in the resolved payload. + * + * @param resolved_payload - The resolved payload values received from the client or the server + * @param dependency - The dependency object. + * @param components - The array of component metadata. + * @param with_null_state - Optional. Specifies whether to include null values for state inputs. Default is false. + * @returns An array of resolved payload values, filtered based on the dependency and component metadata. + */ +export function handle_payload( + resolved_payload: unknown[], + dependency: Dependency, + components: ComponentMeta[], + type: "input" | "output", + with_null_state = false +): unknown[] { + if (type === "input" && !with_null_state) { + throw new Error("Invalid code path. Cannot skip state inputs for input."); + } + // data comes from the server with null state values so we skip + if (type === "output" && with_null_state) { + return resolved_payload; + } + + let updated_payload: unknown[] = []; + let payload_index = 0; + const deps = type === "input" ? dependency.inputs : dependency.outputs; + for (let i = 0; i < deps.length; i++) { + const input_id = deps[i]; + const component = components.find((c) => c.id === input_id); + + if (component?.type === "state") { + // input + with_null_state needs us to fill state with null values + if (with_null_state) { + if (resolved_payload.length === deps.length) { + const value = resolved_payload[payload_index]; + updated_payload.push(value); + payload_index++; + } else { + updated_payload.push(null); + } + } else { + // this is output & !with_null_state, we skip state inputs + // the server payload always comes with null state values so we move along the payload index + payload_index++; + continue; + } + // input & !with_null_state isn't a case we care about, server needs null + continue; + } else { + const value = resolved_payload[payload_index]; + updated_payload.push(value); + payload_index++; + } + } + + return updated_payload; +} diff --git a/node_modules/@gradio/client/src/helpers/init_helpers.ts b/node_modules/@gradio/client/src/helpers/init_helpers.ts new file mode 100644 index 0000000000000000000000000000000000000000..54c1faa44fc0f789695a3ff8cdb36089168d69e9 --- /dev/null +++ b/node_modules/@gradio/client/src/helpers/init_helpers.ts @@ -0,0 +1,222 @@ +import type { Config } from "../types"; +import { + CONFIG_ERROR_MSG, + CONFIG_URL, + INVALID_CREDENTIALS_MSG, + LOGIN_URL, + MISSING_CREDENTIALS_MSG, + SPACE_METADATA_ERROR_MSG, + UNAUTHORIZED_MSG +} from "../constants"; +import { Client } from ".."; +import { join_urls, process_endpoint } from "./api_info"; + +/** + * This function is used to resolve the URL for making requests when the app has a root path. + * The root path could be a path suffix like "/app" which is appended to the end of the base URL. Or + * it could be a full URL like "https://abidlabs-test-client-replica--gqf2x.hf.space" which is used when hosting + * Gradio apps on Hugging Face Spaces. + * @param {string} base_url The base URL at which the Gradio server is hosted + * @param {string} root_path The root path, which could be a path suffix (e.g. mounted in FastAPI app) or a full URL (e.g. hosted on Hugging Face Spaces) + * @param {boolean} prioritize_base Whether to prioritize the base URL over the root path. This is used when both the base path and root paths are full URLs. For example, for fetching files the root path should be prioritized, but for making requests, the base URL should be prioritized. + * @returns {string} the resolved URL + */ +export function resolve_root( + base_url: string, + root_path: string, + prioritize_base: boolean +): string { + if (root_path.startsWith("http://") || root_path.startsWith("https://")) { + return prioritize_base ? base_url : root_path; + } + return base_url + root_path; +} + +export async function get_jwt( + space: string, + token: `hf_${string}`, + cookies?: string | null +): Promise { + try { + const r = await fetch(`https://huggingface.co/api/spaces/${space}/jwt`, { + headers: { + Authorization: `Bearer ${token}`, + ...(cookies ? { Cookie: cookies } : {}) + } + }); + + const jwt = (await r.json()).token; + + return jwt || false; + } catch (e) { + return false; + } +} + +export function map_names_to_ids( + fns: Config["dependencies"] +): Record { + let apis: Record = {}; + + fns.forEach(({ api_name, id }) => { + if (api_name) apis[api_name] = id; + }); + return apis; +} + +export async function resolve_config( + this: Client, + endpoint: string +): Promise { + const headers: Record = this.options.hf_token + ? { Authorization: `Bearer ${this.options.hf_token}` } + : {}; + + headers["Content-Type"] = "application/json"; + + if ( + typeof window !== "undefined" && + window.gradio_config && + location.origin !== "http://localhost:9876" && + !window.gradio_config.dev_mode + ) { + const path = window.gradio_config.root; + const config = window.gradio_config; + let config_root = resolve_root(endpoint, config.root, false); + config.root = config_root; + return { ...config, path } as Config; + } else if (endpoint) { + let config_url = join_urls( + endpoint, + this.deep_link ? CONFIG_URL + "?deep_link=" + this.deep_link : CONFIG_URL + ); + + const response = await this.fetch(config_url, { + headers, + credentials: "include" + }); + + if (response?.status === 401 && !this.options.auth) { + throw new Error(MISSING_CREDENTIALS_MSG); + } else if (response?.status === 401 && this.options.auth) { + throw new Error(INVALID_CREDENTIALS_MSG); + } + if (response?.status === 200) { + let config = await response.json(); + config.path = config.path ?? ""; + config.root = endpoint; + config.dependencies?.forEach((dep: any, i: number) => { + if (dep.id === undefined) { + dep.id = i; + } + }); + return config; + } else if (response?.status === 401) { + throw new Error(UNAUTHORIZED_MSG); + } + throw new Error(CONFIG_ERROR_MSG); + } + + throw new Error(CONFIG_ERROR_MSG); +} + +export async function resolve_cookies(this: Client): Promise { + const { http_protocol, host } = await process_endpoint( + this.app_reference, + this.options.hf_token + ); + + try { + if (this.options.auth) { + const cookie_header = await get_cookie_header( + http_protocol, + host, + this.options.auth, + this.fetch, + this.options.hf_token + ); + + if (cookie_header) this.set_cookies(cookie_header); + } + } catch (e: unknown) { + throw Error((e as Error).message); + } +} + +// separating this from client-bound resolve_cookies so that it can be used in duplicate +export async function get_cookie_header( + http_protocol: string, + host: string, + auth: [string, string], + _fetch: typeof fetch, + hf_token?: `hf_${string}` +): Promise { + const formData = new FormData(); + formData.append("username", auth?.[0]); + formData.append("password", auth?.[1]); + + let headers: { Authorization?: string } = {}; + + if (hf_token) { + headers.Authorization = `Bearer ${hf_token}`; + } + + const res = await _fetch(`${http_protocol}//${host}/${LOGIN_URL}`, { + headers, + method: "POST", + body: formData, + credentials: "include" + }); + + if (res.status === 200) { + return res.headers.get("set-cookie"); + } else if (res.status === 401) { + throw new Error(INVALID_CREDENTIALS_MSG); + } else { + throw new Error(SPACE_METADATA_ERROR_MSG); + } +} + +export function determine_protocol(endpoint: string): { + ws_protocol: "ws" | "wss"; + http_protocol: "http:" | "https:"; + host: string; +} { + if (endpoint.startsWith("http")) { + const { protocol, host, pathname } = new URL(endpoint); + + return { + ws_protocol: protocol === "https:" ? "wss" : "ws", + http_protocol: protocol as "http:" | "https:", + host: host + (pathname !== "/" ? pathname : "") + }; + } else if (endpoint.startsWith("file:")) { + // This case is only expected to be used for the Wasm mode (Gradio-lite), + // where users can create a local HTML file using it and open the page in a browser directly via the `file:` protocol. + return { + ws_protocol: "ws", + http_protocol: "http:", + host: "lite.local" // Special fake hostname only used for this case. This matches the hostname allowed in `is_self_host()` in `js/wasm/network/host.ts`. + }; + } + + // default to secure if no protocol is provided + + return { + ws_protocol: "wss", + http_protocol: "https:", + host: new URL(endpoint).host + }; +} + +export const parse_and_set_cookies = (cookie_header: string): string[] => { + let cookies: string[] = []; + const parts = cookie_header.split(/,(?=\s*[^\s=;]+=[^\s=;]+)/); + parts.forEach((cookie) => { + const [cookie_name, cookie_value] = cookie.split(";")[0].split("="); + if (cookie_name && cookie_value) { + cookies.push(`${cookie_name.trim()}=${cookie_value.trim()}`); + } + }); + return cookies; +}; diff --git a/node_modules/@gradio/client/src/helpers/spaces.ts b/node_modules/@gradio/client/src/helpers/spaces.ts new file mode 100644 index 0000000000000000000000000000000000000000..c290939c52a61f23a6f98e405f19f4235c08fa40 --- /dev/null +++ b/node_modules/@gradio/client/src/helpers/spaces.ts @@ -0,0 +1,252 @@ +import { + RUNTIME_URL, + SLEEPTIME_URL, + SPACE_STATUS_ERROR_MSG +} from "../constants"; +import { RE_SPACE_NAME } from "./api_info"; +import type { SpaceStatusCallback } from "../types"; + +export async function check_space_status( + id: string, + type: "subdomain" | "space_name", + status_callback: SpaceStatusCallback +): Promise { + let endpoint = + type === "subdomain" + ? `https://huggingface.co/api/spaces/by-subdomain/${id}` + : `https://huggingface.co/api/spaces/${id}`; + let response; + let _status; + try { + response = await fetch(endpoint); + _status = response.status; + if (_status !== 200) { + throw new Error(); + } + response = await response.json(); + } catch (e) { + status_callback({ + status: "error", + load_status: "error", + message: SPACE_STATUS_ERROR_MSG, + detail: "NOT_FOUND" + }); + return; + } + + if (!response || _status !== 200) return; + const { + runtime: { stage }, + id: space_name + } = response; + + switch (stage) { + case "STOPPED": + case "SLEEPING": + status_callback({ + status: "sleeping", + load_status: "pending", + message: "Space is asleep. Waking it up...", + detail: stage + }); + + setTimeout(() => { + check_space_status(id, type, status_callback); + }, 1000); // poll for status + break; + case "PAUSED": + status_callback({ + status: "paused", + load_status: "error", + message: + "This space has been paused by the author. If you would like to try this demo, consider duplicating the space.", + detail: stage, + discussions_enabled: await discussions_enabled(space_name) + }); + break; + case "RUNNING": + case "RUNNING_BUILDING": + status_callback({ + status: "running", + load_status: "complete", + message: "Space is running.", + detail: stage + }); + break; + case "BUILDING": + status_callback({ + status: "building", + load_status: "pending", + message: "Space is building...", + detail: stage + }); + + setTimeout(() => { + check_space_status(id, type, status_callback); + }, 1000); + break; + case "APP_STARTING": + status_callback({ + status: "starting", + load_status: "pending", + message: "Space is starting...", + detail: stage + }); + + setTimeout(() => { + check_space_status(id, type, status_callback); + }, 1000); + break; + default: + status_callback({ + status: "space_error", + load_status: "error", + message: "This space is experiencing an issue.", + detail: stage, + discussions_enabled: await discussions_enabled(space_name) + }); + break; + } +} + +export const check_and_wake_space = async ( + space_id: string, + status_callback: SpaceStatusCallback +): Promise => { + let retries = 0; + const max_retries = 12; + const check_interval = 5000; + + return new Promise((resolve) => { + check_space_status( + space_id, + RE_SPACE_NAME.test(space_id) ? "space_name" : "subdomain", + (status) => { + status_callback(status); + + if (status.status === "running") { + resolve(); + } else if ( + status.status === "error" || + status.status === "paused" || + status.status === "space_error" + ) { + resolve(); + } else if ( + status.status === "sleeping" || + status.status === "building" + ) { + if (retries < max_retries) { + retries++; + setTimeout(() => { + check_and_wake_space(space_id, status_callback).then(resolve); + }, check_interval); + } else { + resolve(); + } + } + } + ); + }); +}; + +const RE_DISABLED_DISCUSSION = + /^(?=[^]*\b[dD]iscussions{0,1}\b)(?=[^]*\b[dD]isabled\b)[^]*$/; +export async function discussions_enabled(space_id: string): Promise { + try { + const r = await fetch( + `https://huggingface.co/api/spaces/${space_id}/discussions`, + { + method: "HEAD" + } + ); + + const error = r.headers.get("x-error-message"); + + if (!r.ok || (error && RE_DISABLED_DISCUSSION.test(error))) return false; + return true; + } catch (e) { + return false; + } +} + +export async function get_space_hardware( + space_id: string, + hf_token?: `hf_${string}` | undefined +): Promise<(typeof hardware_types)[number]> { + const headers: { Authorization?: string } = {}; + if (hf_token) { + headers.Authorization = `Bearer ${hf_token}`; + } + + try { + const res = await fetch( + `https://huggingface.co/api/spaces/${space_id}/${RUNTIME_URL}`, + { headers } + ); + + if (res.status !== 200) + throw new Error("Space hardware could not be obtained."); + + const { hardware } = await res.json(); + + return hardware.current; + } catch (e: any) { + throw new Error(e.message); + } +} + +export async function set_space_timeout( + space_id: string, + timeout: number, + hf_token?: `hf_${string}` +): Promise { + const headers: { Authorization?: string } = {}; + if (hf_token) { + headers.Authorization = `Bearer ${hf_token}`; + } + + const body: { + seconds?: number; + } = { + seconds: timeout + }; + + try { + const res = await fetch( + `https://huggingface.co/api/spaces/${space_id}/${SLEEPTIME_URL}`, + { + method: "POST", + headers: { "Content-Type": "application/json", ...headers }, + body: JSON.stringify(body) + } + ); + + if (res.status !== 200) { + throw new Error( + "Could not set sleep timeout on duplicated Space. Please visit *ADD HF LINK TO SETTINGS* to set a timeout manually to reduce billing charges." + ); + } + + const response = await res.json(); + return response; + } catch (e: any) { + throw new Error(e.message); + } +} + +export const hardware_types = [ + "cpu-basic", + "cpu-upgrade", + "cpu-xl", + "t4-small", + "t4-medium", + "a10g-small", + "a10g-large", + "a10g-largex2", + "a10g-largex4", + "a100-large", + "zero-a10g", + "h100", + "h100x8" +] as const; diff --git a/node_modules/@gradio/client/src/index.ts b/node_modules/@gradio/client/src/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..6ba30fc37a3e6865c6ae986e13f43364efbe568c --- /dev/null +++ b/node_modules/@gradio/client/src/index.ts @@ -0,0 +1,23 @@ +export { Client } from "./client"; + +export { predict } from "./utils/predict"; +export { submit } from "./utils/submit"; +export { upload_files } from "./utils/upload_files"; +export { FileData, upload, prepare_files } from "./upload"; +export { handle_file } from "./helpers/data"; + +export type { + SpaceStatus, + StatusMessage, + Status, + client_return, + UploadResponse, + RenderMessage, + LogMessage, + Payload, + Config +} from "./types"; + +// todo: remove in @gradio/client v1.0 +export { client } from "./client"; +export { duplicate_space as duplicate } from "./client"; diff --git a/node_modules/@gradio/client/src/test/api_info.test.ts b/node_modules/@gradio/client/src/test/api_info.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..26da19a429f8a25a28ae8f68acd167be023f73de --- /dev/null +++ b/node_modules/@gradio/client/src/test/api_info.test.ts @@ -0,0 +1,660 @@ +import { + INVALID_URL_MSG, + QUEUE_FULL_MSG, + SPACE_METADATA_ERROR_MSG +} from "../constants"; +import { beforeAll, afterEach, afterAll, it, expect, describe } from "vitest"; +import { + handle_message, + get_description, + get_type, + process_endpoint, + join_urls, + map_data_to_params +} from "../helpers/api_info"; +import { initialise_server } from "./server"; +import { transformed_api_info } from "./test_data"; + +const server = initialise_server(); + +beforeAll(() => server.listen()); +afterEach(() => server.resetHandlers()); +afterAll(() => server.close()); + +describe("handle_message", () => { + it("should return type 'data' when msg is 'send_data'", () => { + const data = { msg: "send_data" }; + const last_status = "pending"; + const result = handle_message(data, last_status); + expect(result).toEqual({ type: "data" }); + }); + + it("should return type 'hash' when msg is 'send_hash'", () => { + const data = { msg: "send_hash" }; + const last_status = "pending"; + const result = handle_message(data, last_status); + expect(result).toEqual({ type: "hash" }); + }); + + it("should return type 'update' with queue full message when msg is 'queue_full'", () => { + const data = { msg: "queue_full", code: 500, success: false }; + const last_status = "pending"; + const result = handle_message(data, last_status); + expect(result).toEqual({ + type: "update", + status: { + queue: true, + message: QUEUE_FULL_MSG, + stage: "error", + code: 500, + success: false + } + }); + }); + + it("should return type 'heartbeat' when msg is 'heartbeat'", () => { + const data = { msg: "heartbeat" }; + const last_status = "pending"; + const result = handle_message(data, last_status); + expect(result).toEqual({ type: "heartbeat" }); + }); + + it("should return type 'unexpected_error' with error message when msg is 'unexpected_error'", () => { + const data = { msg: "unexpected_error", message: "Something went wrong" }; + const last_status = "pending"; + const result = handle_message(data, last_status); + expect(result).toEqual({ + type: "unexpected_error", + status: { + queue: true, + message: "Something went wrong", + stage: "error", + success: false + } + }); + }); + + it("should return type 'update' with estimation status when msg is 'estimation'", () => { + const data = { + msg: "estimation", + code: 200, + queue_size: 10, + rank: 5, + rank_eta: 60, + success: true + }; + const last_status = "pending"; + const result = handle_message(data, last_status); + expect(result).toEqual({ + type: "update", + status: { + queue: true, + stage: "pending", + code: 200, + size: 10, + position: 5, + eta: 60, + success: true + } + }); + }); + + it("should return type 'update' with progress status when msg is 'progress'", () => { + const data = { + msg: "progress", + code: 200, + progress_data: { current: 50, total: 100 }, + success: true + }; + const last_status = "pending"; + const result = handle_message(data, last_status); + expect(result).toEqual({ + type: "update", + status: { + queue: true, + stage: "pending", + code: 200, + progress_data: { current: 50, total: 100 }, + success: true + } + }); + }); + + it("should return type 'log' with the provided data when msg is 'log'", () => { + const data = { msg: "log", log_data: "Some log message" }; + const last_status = "pending"; + const result = handle_message(data, last_status); + expect(result).toEqual({ + type: "log", + data: { msg: "log", log_data: "Some log message" } + }); + }); + + it("should return type 'generating' with generating status when msg is 'process_generating' and success is true", () => { + const data = { + msg: "process_generating", + success: true, + code: 200, + progress_data: { current: 50, total: 100 }, + average_duration: 120, + output: { result: "Some result" } + }; + const last_status = "pending"; + const result = handle_message(data, last_status); + expect(result).toEqual({ + type: "generating", + status: { + queue: true, + message: null, + stage: "generating", + code: 200, + progress_data: { current: 50, total: 100 }, + eta: 120 + }, + data: { result: "Some result" } + }); + }); + + it("should return type 'update' with error status when msg is 'process_generating' and success is false", () => { + const data = { + msg: "process_generating", + success: false, + code: 500, + progress_data: { current: 50, total: 100 }, + average_duration: 120, + output: { error: "Error" } + }; + const last_status = "pending"; + const result = handle_message(data, last_status); + + expect(result).toEqual({ + type: "generating", + data: null, + status: { + eta: 120, + queue: true, + message: "Error", + stage: "error", + code: 500, + progress_data: { current: 50, total: 100 } + } + }); + }); + + it("should return type 'complete' with success status when msg is 'process_completed' and success is true", () => { + const data = { + msg: "process_completed", + success: true, + code: 200, + progress_data: { current: 100, total: 100 }, + output: { result: "Some result" } + }; + const last_status = "pending"; + const result = handle_message(data, last_status); + expect(result).toEqual({ + type: "complete", + status: { + queue: true, + message: undefined, + stage: "complete", + code: 200, + progress_data: { current: 100, total: 100 } + }, + data: { result: "Some result" } + }); + }); + + it("should return type 'update' with error status when msg is 'process_completed' and success is false", () => { + const data = { + msg: "process_completed", + success: false, + code: 500, + progress_data: { current: 100, total: 100 }, + output: { error: "Some error message" } + }; + const last_status = "pending"; + const result = handle_message(data, last_status); + expect(result).toEqual({ + type: "update", + status: { + queue: true, + message: "Some error message", + stage: "error", + code: 500, + success: false + } + }); + }); + + it("should return type 'update' with pending status when msg is 'process_starts'", () => { + const data = { + msg: "process_starts", + code: 200, + rank: 5, + success: true, + eta: 60 + }; + const last_status = "pending"; + const result = handle_message(data, last_status); + expect(result).toEqual({ + type: "update", + original_msg: "process_starts", + status: { + queue: true, + stage: "pending", + code: 200, + size: 5, + position: 0, + success: true, + eta: 60 + } + }); + }); + + it("should return type 'none' with error status when msg is unknown", () => { + const data = { msg: "unknown" }; + const last_status = "pending"; + const result = handle_message(data, last_status); + expect(result).toEqual({ + type: "none", + status: { stage: "error", queue: true } + }); + }); +}); + +describe("get_description", () => { + it("should return 'array of [file, label] tuples' when serializer is 'GallerySerializable'", () => { + const type = { type: "string", description: "param description" }; + const serializer = "GallerySerializable"; + const result = get_description(type, serializer); + expect(result).toEqual("array of [file, label] tuples"); + }); + + it("should return 'array of strings' when serializer is 'ListStringSerializable'", () => { + const type = { type: "string", description: "param description" }; + const serializer = "ListStringSerializable"; + const result = get_description(type, serializer); + expect(result).toEqual("array of strings"); + }); + + it("should return 'array of files or single file' when serializer is 'FileSerializable'", () => { + const type = { type: "string", description: "param description" }; + const serializer = "FileSerializable"; + const result = get_description(type, serializer); + expect(result).toEqual("array of files or single file"); + }); + + it("should return the type's description when serializer is not 'GallerySerializable', 'ListStringSerializable', or 'FileSerializable'", () => { + const type = { type: "string", description: "param description" }; + const serializer = "SomeOtherSerializer"; + const result = get_description(type, serializer); + expect(result).toEqual(type.description); + }); +}); + +describe("get_type", () => { + it("should return 'string' when type is 'string'", () => { + const type = { type: "string", description: "param description" }; + const component = "Component"; + const serializer = "Serializer"; + const signature_type = "parameter"; + const result = get_type(type, component, serializer, signature_type); + expect(result).toEqual("string"); + }); + + it("should return 'boolean' when type is 'boolean'", () => { + const type = { type: "boolean", description: "param description" }; + const component = "Component"; + const serializer = "Serializer"; + const signature_type = "parameter"; + const result = get_type(type, component, serializer, signature_type); + expect(result).toEqual("boolean"); + }); + + it("should return 'number' when type is 'number'", () => { + const type = { type: "number", description: "param description" }; + const component = "Component"; + const serializer = "Serializer"; + const signature_type = "parameter"; + const result = get_type(type, component, serializer, signature_type); + expect(result).toEqual("number"); + }); + + it("should return 'any' when serializer is 'JSONSerializable'", () => { + const type = { type: "any", description: "param description" }; + const component = "Component"; + const serializer = "JSONSerializable"; + const signature_type = "parameter"; + const result = get_type(type, component, serializer, signature_type); + expect(result).toEqual("any"); + }); + + it("should return 'any' when serializer is 'StringSerializable'", () => { + const type = { type: "any", description: "param description" }; + const component = "Component"; + const serializer = "StringSerializable"; + const signature_type = "parameter"; + const result = get_type(type, component, serializer, signature_type); + expect(result).toEqual("any"); + }); + + it("should return 'string[]' when serializer is 'ListStringSerializable'", () => { + const type = { type: "any", description: "param description" }; + const component = "Component"; + const serializer = "ListStringSerializable"; + const signature_type = "parameter"; + const result = get_type(type, component, serializer, signature_type); + expect(result).toEqual("string[]"); + }); + + it("should return 'Blob | File | Buffer' when component is 'Image' and signature_type is 'parameter'", () => { + const type = { type: "any", description: "param description" }; + const component = "Image"; + const serializer = "Serializer"; + const signature_type = "parameter"; + const result = get_type(type, component, serializer, signature_type); + expect(result).toEqual("Blob | File | Buffer"); + }); + + it("should return 'string' when component is 'Image' and signature_type is 'return'", () => { + const type = { type: "string", description: "param description" }; + const component = "Image"; + const serializer = "Serializer"; + const signature_type = "return"; + const result = get_type(type, component, serializer, signature_type); + expect(result).toEqual("string"); + }); + + it("should return '(Blob | File | Buffer)[]' when serializer is 'FileSerializable' and type is an array and signature_type is 'parameter'", () => { + const type = { type: "array", description: "param description" }; + const component = "Component"; + const serializer = "FileSerializable"; + const signature_type = "parameter"; + const result = get_type(type, component, serializer, signature_type); + expect(result).toEqual("(Blob | File | Buffer)[]"); + }); + + it("should return 'Blob | File | Buffer' when serializer is 'FileSerializable' and type is not an array and signature_type is 'return'", () => { + const type = { type: "any", description: "param description" }; + const component = "Component"; + const serializer = "FileSerializable"; + const signature_type = "return"; + const result = get_type(type, component, serializer, signature_type); + expect(result).toEqual( + "{ name: string; data: string; size?: number; is_file?: boolean; orig_name?: string}" + ); + }); + + it("should return a FileData object when serializer is 'FileSerializable' and type is not an array and signature_type is 'return'", () => { + const type = { type: "any", description: "param description" }; + const component = "Component"; + const serializer = "FileSerializable"; + const signature_type = "return"; + const result = get_type(type, component, serializer, signature_type); + expect(result).toEqual( + "{ name: string; data: string; size?: number; is_file?: boolean; orig_name?: string}" + ); + }); + + it("should return '[(Blob | File | Buffer), (string | null)][]' when serializer is 'GallerySerializable' and signature_type is 'parameter'", () => { + const type = { type: "any", description: "param description" }; + const component = "Component"; + const serializer = "GallerySerializable"; + const signature_type = "parameter"; + const result = get_type(type, component, serializer, signature_type); + expect(result).toEqual("[(Blob | File | Buffer), (string | null)][]"); + }); + + it("should return a FileData object when serializer is 'GallerySerializable' and signature_type is 'return'", () => { + const type = { type: "any", description: "param description" }; + const component = "Component"; + const serializer = "GallerySerializable"; + const signature_type = "return"; + const result = get_type(type, component, serializer, signature_type); + expect(result).toEqual( + "[{ name: string; data: string; size?: number; is_file?: boolean; orig_name?: string}, (string | null))][]" + ); + }); +}); + +describe("process_endpoint", () => { + it("should return space_id, host, ws_protocol, and http_protocol when app_reference is a valid space name", async () => { + const app_reference = "hmb/hello_world"; + const host = "hmb-hello-world.hf.space"; + + const hf_token = "hf_token"; + const expected = { + space_id: app_reference, + host, + ws_protocol: "wss", + http_protocol: "https:" + }; + + const result = await process_endpoint(app_reference, hf_token); + expect(result).toEqual(expected); + }); + + it("should throw an error when fetching space metadata fails", async () => { + const app_reference = "hmb/bye_world"; + const hf_token = "hf_token"; + + try { + await process_endpoint(app_reference, hf_token); + } catch (error) { + expect(error.message).toEqual(SPACE_METADATA_ERROR_MSG); + } + }); + + it("should return the correct data when app_reference is a valid space domain", async () => { + const app_reference = "hmb/hello_world"; + const host = "hmb-hello-world.hf.space"; + + const expected = { + space_id: app_reference, + host, + ws_protocol: "wss", + http_protocol: "https:" + }; + + const result = await process_endpoint("hmb/hello_world"); + expect(result).toEqual(expected); + }); + + it("processes local server URLs correctly", async () => { + const local_url = "http://localhost:7860/gradio"; + const response_local_url = await process_endpoint(local_url); + expect(response_local_url.space_id).toBe(false); + expect(response_local_url.host).toBe("localhost:7860/gradio"); + + const local_url_2 = "http://localhost:7860/gradio/"; + const response_local_url_2 = await process_endpoint(local_url_2); + expect(response_local_url_2.space_id).toBe(false); + expect(response_local_url_2.host).toBe("localhost:7860/gradio"); + }); + + it("handles hugging face space references", async () => { + const space_id = "hmb/hello_world"; + + const response = await process_endpoint(space_id); + expect(response.space_id).toBe(space_id); + expect(response.host).toContain("hf.space"); + }); + + it("handles hugging face domain URLs", async () => { + const app_reference = "https://hmb-hello-world.hf.space/"; + const response = await process_endpoint(app_reference); + expect(response.space_id).toBe("hmb-hello-world"); + expect(response.host).toBe("hmb-hello-world.hf.space"); + }); + + it("handles huggingface subpath urls", async () => { + const app_reference = + "https://pngwn-pr-demos-test.hf.space/demo/audio_debugger/"; + const response = await process_endpoint(app_reference); + expect(response.space_id).toBe("pngwn-pr-demos-test"); + expect(response.host).toBe( + "pngwn-pr-demos-test.hf.space/demo/audio_debugger" + ); + + expect(response.http_protocol).toBe("https:"); + }); +}); + +describe("join_urls", () => { + it("joins URLs correctly", () => { + expect(join_urls("http://localhost:7860", "/gradio")).toBe( + "http://localhost:7860/gradio" + ); + expect(join_urls("http://localhost:7860/", "/gradio")).toBe( + "http://localhost:7860/gradio" + ); + expect(join_urls("http://localhost:7860", "app/", "/gradio")).toBe( + "http://localhost:7860/app/gradio" + ); + expect(join_urls("http://localhost:7860/", "/app/", "/gradio/")).toBe( + "http://localhost:7860/app/gradio/" + ); + + expect(join_urls("http://127.0.0.1:8000/app", "/config")).toBe( + "http://127.0.0.1:8000/app/config" + ); + + expect(join_urls("http://127.0.0.1:8000/app/gradio", "/config")).toBe( + "http://127.0.0.1:8000/app/gradio/config" + ); + }); + it("throws an error when the URLs are not valid", () => { + expect(() => join_urls("localhost:7860", "/gradio")).toThrowError( + INVALID_URL_MSG + ); + + expect(() => join_urls("localhost:7860", "/gradio", "app")).toThrowError( + INVALID_URL_MSG + ); + }); +}); + +describe("map_data_params", () => { + let test_data = transformed_api_info; + + test_data.named_endpoints["/predict"].parameters = [ + { + parameter_name: "param1", + parameter_has_default: false, + label: "", + component: "", + serializer: "", + python_type: { + type: "", + description: "" + }, + type: { + type: "", + description: "" + } + }, + { + parameter_name: "param2", + parameter_has_default: false, + label: "", + type: { + type: "", + description: "" + }, + component: "", + serializer: "", + python_type: { + type: "", + description: "" + } + }, + { + parameter_name: "param3", + parameter_has_default: true, + parameter_default: 3, + label: "", + type: { + type: "", + description: "" + }, + component: "", + serializer: "", + python_type: { + type: "", + description: "" + } + } + ]; + + let endpoint_info = test_data.named_endpoints["/predict"]; + + it("should return an array of data when data is an array", () => { + const data = [1, 2]; + + const result = map_data_to_params(data, endpoint_info); + expect(result).toEqual(data); + }); + + it("should return an empty array when data is an empty array", () => { + const data = []; + + const result = map_data_to_params(data, endpoint_info); + expect(result).toEqual(data); + }); + + it("should return an empty array when data is not defined", () => { + const data = undefined; + + const result = map_data_to_params(data, endpoint_info); + expect(result).toEqual([]); + }); + + it("should return the data when too many arguments are provided for the endpoint", () => { + const data = [1, 2, 3, 4]; + + const result = map_data_to_params(data, endpoint_info); + expect(result).toEqual(data); + }); + + it("should return an array of resolved data when data is an object", () => { + const data = { + param1: 1, + param2: 2, + param3: 3 + }; + + const result = map_data_to_params(data, endpoint_info); + expect(result).toEqual([1, 2, 3]); + }); + + it("should use the default value when a keyword argument is not provided and has a default value", () => { + const data = { + param1: 1, + param2: 2 + }; + + const result = map_data_to_params(data, endpoint_info); + expect(result).toEqual([1, 2, 3]); + }); + + it("should throw an error when an invalid keyword argument is provided", () => { + const data = { + param1: 1, + param2: 2, + param3: 3, + param4: 4 + }; + + expect(() => map_data_to_params(data, endpoint_info)).toThrowError( + "Parameter `param4` is not a valid keyword argument. Please refer to the API for usage." + ); + }); + + it("should throw an error when no value is provided for a required parameter", () => { + const data = {}; + + expect(() => map_data_to_params(data, endpoint_info)).toThrowError( + "No value provided for required parameter: param1" + ); + }); +}); diff --git a/node_modules/@gradio/client/src/test/data.test.ts b/node_modules/@gradio/client/src/test/data.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..d92a5701cb865e4cb28a1af8f69181c9ef792fbb --- /dev/null +++ b/node_modules/@gradio/client/src/test/data.test.ts @@ -0,0 +1,449 @@ +import { describe, it, expect, vi, afterEach } from "vitest"; +import { + update_object, + walk_and_store_blobs, + skip_queue, + post_message, + handle_file, + handle_payload +} from "../helpers/data"; +import { config_response, endpoint_info } from "./test_data"; +import { BlobRef, Command } from "../types"; +import { FileData } from "../upload"; + +const IS_NODE = process.env.TEST_MODE === "node"; + +describe("walk_and_store_blobs", () => { + it("should convert a Buffer to a Blob", async () => { + const buffer = Buffer.from("test data"); + const parts = await walk_and_store_blobs(buffer, "text"); + + expect(parts).toHaveLength(1); + expect(parts[0].blob).toBeInstanceOf(Blob); + }); + + it("should return a Blob when passed a Blob", async () => { + const blob = new Blob(["test data"]); + const parts = await walk_and_store_blobs( + blob, + undefined, + [], + true, + endpoint_info + ); + + expect(parts[0].blob).toBeInstanceOf(Blob); + }); + + it("should handle arrays", async () => { + const image = new Blob([]); + const parts = await walk_and_store_blobs([image]); + + expect(parts).toHaveLength(1); + expect(parts[0].blob).toBeInstanceOf(Blob); + expect(parts[0].path).toEqual(["0"]); + }); + + it("should handle deep structures", async () => { + const image = new Blob([]); + const parts = await walk_and_store_blobs({ a: { b: { data: { image } } } }); + + expect(parts).toHaveLength(1); + expect(parts[0].blob).toBeInstanceOf(Blob); + expect(parts[0].path).toEqual(["a", "b", "data", "image"]); + }); + + it("should handle deep structures with arrays", async () => { + const image = new Blob([]); + const parts = await walk_and_store_blobs({ + a: [ + { + b: [ + { + data: [ + { + image + } + ] + } + ] + } + ] + }); + + expect(parts[0].blob).toBeInstanceOf(Blob); + }); + + it("should handle deep structures with arrays (with equality check)", async () => { + const image = new Blob([]); + + const obj = { + a: [ + { + b: [ + { + data: [[image], image, [image, [image]]] + } + ] + } + ] + }; + const parts = await walk_and_store_blobs(obj); + + async function map_path(obj: Record, parts: BlobRef[]) { + const { path, blob } = parts[parts.length - 1]; + let ref = obj; + path.forEach((p) => (ref = ref[p])); + + // since ref is a Blob and blob is a Blob, we deep equal check the two buffers instead + if (ref instanceof Blob && blob instanceof Blob) { + const refBuffer = Buffer.from(await ref.arrayBuffer()); + const blobBuffer = Buffer.from(await blob.arrayBuffer()); + return refBuffer.equals(blobBuffer); + } + + return ref === blob; + } + + expect(parts[0].blob).toBeInstanceOf(Blob); + expect(map_path(obj, parts)).toBeTruthy(); + }); + + it("should handle buffer instances and return a BlobRef", async () => { + const buffer = Buffer.from("test"); + const parts = await walk_and_store_blobs(buffer, undefined, ["blob"]); + + expect(parts).toHaveLength(1); + expect(parts[0].blob).toBeInstanceOf(Blob); + expect(parts[0].path).toEqual(["blob"]); + }); + + it("should handle buffer instances with a path and return a BlobRef with the path", async () => { + const buffer = Buffer.from("test data"); + const parts = await walk_and_store_blobs(buffer); + + expect(parts).toHaveLength(1); + expect(parts[0].path).toEqual([]); + expect(parts[0].blob).toBeInstanceOf(Blob); + }); + + it("should convert an object with deep structures to BlobRefs", async () => { + const param = { + a: { + b: { + data: { + image: Buffer.from("test image") + } + } + } + }; + const parts = await walk_and_store_blobs(param); + + expect(parts).toHaveLength(1); + expect(parts[0].path).toEqual(["a", "b", "data", "image"]); + expect(parts[0].blob).toBeInstanceOf(Blob); + }); +}); +describe("update_object", () => { + it("should update the value of a nested property", () => { + const obj = { + a: { + b: { + c: "old value" + } + } + }; + + const stack = ["a", "b", "c"]; + const new_val = "new value"; + + update_object(obj, new_val, stack); + + expect(obj.a.b.c).toBe(new_val); + }); + + it("should throw an error for invalid key type", () => { + const obj = { + a: { + b: { + c: "value" + } + } + }; + + const stack = ["a", "b", true]; + const newValue = "new value"; + + expect(() => { + // @ts-ignore + update_object(obj, newValue, stack); + }).toThrowError("Invalid key type"); + }); +}); + +describe("skip_queue", () => { + const id = 0; + const config = config_response; + + it("should not skip queue when global and dependency queue is enabled", () => { + config.enable_queue = true; + config.dependencies.find((dep) => dep.id === id)!.queue = true; + + const result = skip_queue(id, config_response); + + expect(result).toBe(false); + }); + + it("should not skip queue when global queue is disabled and dependency queue is enabled", () => { + config.enable_queue = false; + config.dependencies.find((dep) => dep.id === id)!.queue = true; + + const result = skip_queue(id, config_response); + + expect(result).toBe(false); + }); + + it("should should skip queue when global queue and dependency queue is disabled", () => { + config.enable_queue = false; + config.dependencies.find((dep) => dep.id === id)!.queue = false; + + const result = skip_queue(id, config_response); + + expect(result).toBe(true); + }); + + it("should should skip queue when global queue is enabled and dependency queue is disabled", () => { + config.enable_queue = true; + config.dependencies.find((dep) => dep.id === id)!.queue = false; + + const result = skip_queue(id, config_response); + + expect(result).toBe(true); + }); +}); + +describe("post_message", () => { + afterEach(() => { + vi.restoreAllMocks(); + }); + + it("should send a message to the parent window and resolve with received data", async () => { + const test_data = { key: "value" }; + const test_origin = "https://huggingface.co"; + + const post_message_mock = vi.fn(); + + global.window = { + // @ts-ignore + parent: { + postMessage: post_message_mock + } + }; + + const message_channel_mock = { + port1: { + onmessage: (handler) => { + onmessage = handler; + }, + close: vi.fn() + }, + port2: {} + }; + + vi.stubGlobal("MessageChannel", function () { + this.port1 = message_channel_mock.port1; + this.port2 = message_channel_mock.port2; + return this; + }); + + const promise = post_message(test_data, test_origin); + + if (message_channel_mock.port1.onmessage) { + message_channel_mock.port1.onmessage({ data: test_data }); + } + + await expect(promise).resolves.toEqual(test_data); + expect(post_message_mock).toHaveBeenCalledWith(test_data, test_origin, [ + message_channel_mock.port2 + ]); + }); +}); + +describe("handle_file", () => { + it("should handle a Blob object and return the blob", () => { + const blob = new Blob(["test data"], { type: "image/png" }); + const result = handle_file(blob) as FileData; + + expect(result).toBe(blob); + }); + + it("should handle a Buffer object and return it as a blob", () => { + const buffer = Buffer.from("test data"); + const result = handle_file(buffer) as FileData; + expect(result).toBeInstanceOf(Blob); + }); + it("should handle a local file path and return a Command object", () => { + const file_path = "./owl.png"; + const result = handle_file(file_path) as Command; + expect(result).toBeInstanceOf(Command); + expect(result).toEqual({ + type: "command", + command: "upload_file", + meta: { path: "./owl.png", name: "./owl.png", orig_path: "./owl.png" }, + fileData: undefined + }); + }); + + it("should handle a File object and return it as FileData", () => { + if (IS_NODE) { + return; + } + const file = new File(["test image"], "test.png", { type: "image/png" }); + const result = handle_file(file) as FileData; + expect(result).toBeInstanceOf(Blob); + }); + + it("should throw an error for invalid input", () => { + const invalid_input = 123; + + expect(() => { + // @ts-ignore + handle_file(invalid_input); + }).toThrowError( + "Invalid input: must be a URL, File, Blob, or Buffer object." + ); + }); +}); + +describe("handle_payload", () => { + it("should return an input payload with null in place of `state` when with_null_state is true", () => { + const resolved_payload = [2]; + const dependency = { + inputs: [1, 2] + }; + const components = [ + { id: 1, type: "number" }, + { id: 2, type: "state" } + ]; + const with_null_state = true; + const result = handle_payload( + resolved_payload, + // @ts-ignore + dependency, + components, + "input", + with_null_state + ); + expect(result).toEqual([2, null]); + }); + it("should return an input payload with null in place of two `state` components when with_null_state is true", () => { + const resolved_payload = ["hello", "goodbye"]; + const dependency = { + inputs: [1, 2, 3, 4] + }; + const components = [ + { id: 1, type: "textbox" }, + { id: 2, type: "state" }, + { id: 3, type: "textbox" }, + { id: 4, type: "state" } + ]; + const with_null_state = true; + const result = handle_payload( + resolved_payload, + // @ts-ignore + dependency, + components, + "input", + with_null_state + ); + expect(result).toEqual(["hello", null, "goodbye", null]); + }); + + it("should return an output payload without the state component value when with_null_state is false", () => { + const resolved_payload = ["hello", null]; + const dependency = { + outputs: [2, 3] + }; + const components = [ + { id: 2, type: "textbox" }, + { id: 3, type: "state" } + ]; + const with_null_state = false; + const result = handle_payload( + resolved_payload, + // @ts-ignore + dependency, + components, + "output", + with_null_state + ); + expect(result).toEqual(["hello"]); + }); + + it("should return an ouput payload without the two state component values when with_null_state is false", () => { + const resolved_payload = ["hello", null, "world", null]; + const dependency = { + outputs: [2, 3, 4, 5] + }; + const components = [ + { id: 2, type: "textbox" }, + { id: 3, type: "state" }, + { id: 4, type: "textbox" }, + { id: 5, type: "state" } + ]; + const with_null_state = false; + const result = handle_payload( + resolved_payload, + // @ts-ignore + dependency, + components, + "output", + with_null_state + ); + expect(result).toEqual(["hello", "world"]); + }); + + it("should return an ouput payload with the two state component values when with_null_state is true", () => { + const resolved_payload = ["hello", null, "world", null]; + const dependency = { + outputs: [2, 3, 4, 5] + }; + const components = [ + { id: 2, type: "textbox" }, + { id: 3, type: "state" }, + { id: 4, type: "textbox" }, + { id: 5, type: "state" } + ]; + const with_null_state = true; + const result = handle_payload( + resolved_payload, + // @ts-ignore + dependency, + components, + "output", + with_null_state + ); + expect(result).toEqual(["hello", null, "world", null]); + }); + + it("should return the same payload where no state components are defined", () => { + const resolved_payload = ["hello", "world"]; + const dependency = { + inputs: [2, 3] + }; + const components = [ + { id: 2, type: "textbox" }, + { id: 3, type: "textbox" } + ]; + const with_null_state = true; + const result = handle_payload( + resolved_payload, + // @ts-ignore + dependency, + components, + "input", + with_null_state + ); + expect(result).toEqual(["hello", "world"]); + }); +}); diff --git a/node_modules/@gradio/client/src/test/handlers.ts b/node_modules/@gradio/client/src/test/handlers.ts new file mode 100644 index 0000000000000000000000000000000000000000..308b8846bc441714ef9bf6caa39245e6415f8458 --- /dev/null +++ b/node_modules/@gradio/client/src/test/handlers.ts @@ -0,0 +1,693 @@ +import { HttpResponse, http, RequestHandler } from "msw"; +import { + HOST_URL, + API_INFO_URL, + CONFIG_URL, + RUNTIME_URL, + SLEEPTIME_URL, + UPLOAD_URL, + BROKEN_CONNECTION_MSG, + LOGIN_URL +} from "../constants"; +import { + response_api_info, + config_response, + whoami_response, + duplicate_response, + hardware_sleeptime_response, + discussions_response, + runtime_response +} from "./test_data"; + +const root_url = "https://huggingface.co"; + +export const direct_space_url = "https://hmb-hello-world.hf.space"; +const private_space_url = "https://hmb-secret-world.hf.space"; +const private_auth_space_url = "https://hmb-private-auth-space.hf.space"; + +const server_error_space_url = "https://hmb-server-error.hf.space"; +const upload_server_test_space_url = "https://hmb-server-test.hf.space"; +const auth_app_space_url = "https://hmb-auth-space.hf.space"; +const unauth_app_space_url = "https://hmb-unauth-space.hf.space"; +const invalid_auth_space_url = "https://hmb-invalid-auth-space.hf.space"; + +const server_error_reference = "hmb/server_error"; +const app_reference = "hmb/hello_world"; +const broken_app_reference = "hmb/bye_world"; +const duplicate_app_reference = "gradio/hello_world"; +const private_app_reference = "hmb/secret_world"; +const server_test_app_reference = "hmb/server_test"; +const auth_app_reference = "hmb/auth_space"; +const unauth_app_reference = "hmb/unauth_space"; +const invalid_auth_app_reference = "hmb/invalid_auth_space"; +const private_auth_app_reference = "hmb/private_auth_space"; + +export const handlers: RequestHandler[] = [ + // /host requests + http.get(`${root_url}/api/spaces/${app_reference}/${HOST_URL}`, () => { + return new HttpResponse( + JSON.stringify({ + subdomain: "hmb-hello-world", + host: "https://hmb-hello-world.hf.space" + }), + { + status: 200, + headers: { + "Content-Type": "application/json" + } + } + ); + }), + http.get(`${root_url}/api/spaces/${broken_app_reference}/${HOST_URL}`, () => { + return new HttpResponse(null, { + status: 404, + headers: { + "Content-Type": "application/json", + hf_token: "hf_123" + } + }); + }), + http.get( + `${root_url}/api/spaces/${private_auth_app_reference}/${HOST_URL}`, + () => { + return new HttpResponse( + JSON.stringify({ + subdomain: "hmb-private-auth-space", + host: "https://hmb-private-auth-space.hf.space" + }), + { + status: 200, + headers: { + "Content-Type": "application/json" + } + } + ); + } + ), + http.get( + `${root_url}/api/spaces/${private_app_reference}/${HOST_URL}`, + ({ request }) => { + const token = request.headers.get("authorization")?.substring(7); + + if (!token || token !== "hf_123") { + return new HttpResponse(null, { + status: 401, + headers: { + "Content-Type": "application/json" + } + }); + } + + return new HttpResponse( + JSON.stringify({ + subdomain: private_app_reference, + host: private_space_url + }), + { + status: 200, + headers: { + "Content-Type": "application/json" + } + } + ); + } + ), + http.get( + `${root_url}/api/spaces/${server_error_reference}/${HOST_URL}`, + () => { + return new HttpResponse( + JSON.stringify({ + subdomain: "hmb-server-test", + host: "https://hmb-server-test.hf.space" + }), + { + status: 200, + headers: { + "Content-Type": "application/json" + } + } + ); + } + ), + http.get( + `${root_url}/api/spaces/${server_test_app_reference}/${HOST_URL}`, + () => { + return new HttpResponse( + JSON.stringify({ + subdomain: "hmb-server-test", + host: "https://hmb-server-test.hf.space" + }), + { + status: 200, + headers: { + "Content-Type": "application/json" + } + } + ); + } + ), + http.get(`${root_url}/api/spaces/${auth_app_reference}/${HOST_URL}`, () => { + return new HttpResponse( + JSON.stringify({ + subdomain: "hmb-auth-space", + host: "https://hmb-auth-space.hf.space" + }), + { + status: 200, + headers: { + "Content-Type": "application/json" + } + } + ); + }), + http.get( + `${root_url}/api/spaces/${invalid_auth_app_reference}/${HOST_URL}`, + () => { + return new HttpResponse( + JSON.stringify({ + subdomain: "hmb-invalid-auth-space", + host: "https://hmb-invalid-auth-space.hf.space" + }), + { + status: 200, + headers: { + "Content-Type": "application/json" + } + } + ); + } + ), + http.get( + `${root_url}/api/spaces/${duplicate_app_reference}/${HOST_URL}`, + () => { + return new HttpResponse( + JSON.stringify({ + subdomain: "gradio-hello-world", + host: "https://gradio-hello-world.hf.space" + }), + { + status: 200, + headers: { + "Content-Type": "application/json" + } + } + ); + } + ), + http.get(`${root_url}/api/spaces/${unauth_app_reference}/${HOST_URL}`, () => { + return new HttpResponse( + JSON.stringify({ + subdomain: "hmb-unath-space", + host: "https://hmb-unauth-space.hf.space" + }), + { + status: 200, + headers: { + "Content-Type": "application/json" + } + } + ); + }), + // /info requests + http.get(`${direct_space_url}/${API_INFO_URL}`, () => { + return new HttpResponse(JSON.stringify(response_api_info), { + status: 200, + headers: { + "Content-Type": "application/json" + } + }); + }), + http.get(`${upload_server_test_space_url}/${API_INFO_URL}`, () => { + return new HttpResponse(JSON.stringify(response_api_info), { + status: 200, + headers: { + "Content-Type": "application/json" + } + }); + }), + http.get(`${private_space_url}/${API_INFO_URL}`, () => { + return new HttpResponse(JSON.stringify(response_api_info), { + status: 200, + headers: { + "Content-Type": "application/json" + } + }); + }), + http.get(`${server_error_space_url}/${API_INFO_URL}`, () => { + return new HttpResponse(JSON.stringify(response_api_info), { + status: 200, + headers: { + "Content-Type": "application/json" + } + }); + }), + http.get(`${auth_app_space_url}/${API_INFO_URL}`, async () => { + return new HttpResponse(JSON.stringify(response_api_info), { + status: 200, + headers: { + "Content-Type": "application/json" + } + }); + }), + http.get(`${private_auth_space_url}/${API_INFO_URL}`, async () => { + return new HttpResponse(JSON.stringify(response_api_info), { + status: 200, + headers: { + "Content-Type": "application/json" + } + }); + }), + // /config requests + http.get(`${direct_space_url}/${CONFIG_URL}`, () => { + return new HttpResponse(JSON.stringify(config_response), { + status: 200, + headers: { + "Content-Type": "application/json" + } + }); + }), + http.get(`${private_space_url}/${CONFIG_URL}`, () => { + return new HttpResponse( + JSON.stringify({ + ...config_response, + root: "https://hmb-secret-world.hf.space" + }), + { + status: 200, + headers: { + "Content-Type": "application/json" + } + } + ); + }), + http.get(`${upload_server_test_space_url}/${CONFIG_URL}`, () => { + return new HttpResponse( + JSON.stringify({ + ...config_response, + root: "https://hmb-server-test.hf.space" + }), + { + status: 200, + headers: { + "Content-Type": "application/json" + } + } + ); + }), + http.get(`${private_auth_space_url}/${CONFIG_URL}`, () => { + return new HttpResponse( + JSON.stringify({ + ...config_response, + root: "https://hmb-private-auth-space.hf.space" + }), + { + status: 200, + headers: { + "Content-Type": "application/json" + } + } + ); + }), + http.get(`${direct_space_url}/${CONFIG_URL}`, () => { + return new HttpResponse(JSON.stringify(config_response), { + status: 500, + headers: { + "Content-Type": "application/json" + } + }); + }), + http.get(`${server_error_space_url}/${CONFIG_URL}`, () => { + return new HttpResponse(JSON.stringify(config_response), { + status: 200, + headers: { + "Content-Type": "application/json" + } + }); + }), + http.get(`${invalid_auth_space_url}/${CONFIG_URL}`, () => { + return new HttpResponse(JSON.stringify({ detail: "Unauthorized" }), { + status: 401, + headers: { + "Content-Type": "application/json" + } + }); + }), + http.get(`${auth_app_space_url}/${CONFIG_URL}`, ({ request }) => { + return new HttpResponse( + JSON.stringify({ + ...config_response, + root: "https://hmb-auth-space.hf.space", + space_id: "hmb/auth_space" + }), + { + status: 200, + headers: { + "Content-Type": "application/json" + } + } + ); + }), + http.get(`${unauth_app_space_url}/${CONFIG_URL}`, () => { + return new HttpResponse( + JSON.stringify({ + detail: "Unauthorized" + }), + { + status: 401, + headers: { + "Content-Type": "application/json" + } + } + ); + }), + // /whoami requests + http.get(`${root_url}/api/whoami-v2`, () => { + return new HttpResponse(JSON.stringify(whoami_response), { + status: 200, + headers: { + "Content-Type": "application/json", + "hf-token": "hf_123" + } + }); + }), + // /duplicate requests + http.post( + `${root_url}/api/spaces/${duplicate_app_reference}/duplicate`, + ({ request }) => { + if (request.headers.get("authorization")?.substring(7) !== "hf_123") { + throw new HttpResponse(null, { + status: 401, + headers: { + "Content-Type": "application/json" + } + }); + } + return new HttpResponse(JSON.stringify(duplicate_response), { + status: 200, + headers: { + "Content-Type": "application/json" + } + }); + } + ), + // /sleeptime requests + http.post(`${root_url}/api/spaces/${app_reference}/${SLEEPTIME_URL}`, () => { + return new HttpResponse(JSON.stringify(hardware_sleeptime_response), { + status: 200, + headers: { + "Content-Type": "application/json" + } + }); + }), + http.post( + `${root_url}/api/spaces/${server_test_app_reference}/${SLEEPTIME_URL}`, + () => { + throw new HttpResponse(null, { + status: 500, + headers: { + "Content-Type": "application/json" + } + }); + } + ), + // /runtime requests + http.get( + `${root_url}/api/spaces/${broken_app_reference}/${RUNTIME_URL}`, + () => { + return new HttpResponse(null, { + status: 404, + headers: { + "Content-Type": "application/json" + } + }); + } + ), + http.get(`${root_url}/api/spaces/${app_reference}/${RUNTIME_URL}`, () => { + return new HttpResponse(JSON.stringify(hardware_sleeptime_response), { + status: 200, + headers: { + "Content-Type": "application/json" + } + }); + }), + // queue requests + http.get(`${direct_space_url}/queue/data`, () => { + return new HttpResponse(JSON.stringify({ event_id: "123" }), { + status: 200, + headers: { + "Content-Type": "application/json" + } + }); + }), + http.post(`${direct_space_url}/queue/join`, () => { + return new HttpResponse(JSON.stringify({ event_id: "123" }), { + status: 200, + headers: { + "Content-Type": "application/json" + } + }); + }), + // upload requests + http.post(`${direct_space_url}/${UPLOAD_URL}`, () => { + return new HttpResponse(JSON.stringify(["lion.jpg"]), { + status: 200, + headers: { + "Content-Type": "application/json" + } + }); + }), + http.post(`${upload_server_test_space_url}/${UPLOAD_URL}`, () => { + throw new HttpResponse(JSON.parse("Internal Server Error"), { + status: 200, + headers: { + "Content-Type": "application/json" + } + }); + }), + // discussions requests + http.head(`${root_url}/api/spaces/${app_reference}/discussions`, () => { + return new HttpResponse(JSON.stringify(discussions_response), { + status: 200, + headers: { + "Content-Type": "application/json" + } + }); + }), + http.head( + `${root_url}/api/spaces/${broken_app_reference}/discussions`, + () => { + throw new HttpResponse( + JSON.parse("Discussions are disabled for this repo"), + { + status: 403, + headers: { + "Content-Type": "application/json" + } + } + ); + } + ), + // space requests + http.get(`${root_url}/api/spaces/${app_reference}`, () => { + return new HttpResponse( + JSON.stringify({ id: app_reference, runtime: runtime_response }), + { + status: 200, + headers: { + "Content-Type": "application/json" + } + } + ); + }), + http.get(`${root_url}/api/spaces/hmb/paused_space`, () => { + return new HttpResponse( + JSON.stringify({ + id: app_reference, + runtime: { ...runtime_response, stage: "PAUSED" } + }), + { + status: 200, + headers: { + "Content-Type": "application/json" + } + } + ); + }), + http.get(`${root_url}/api/spaces/hmb/building_space`, () => { + return new HttpResponse( + JSON.stringify({ + id: app_reference, + runtime: { ...runtime_response, stage: "BUILDING" } + }), + { + status: 200, + headers: { + "Content-Type": "application/json" + } + } + ); + }), + http.get(`${root_url}/api/spaces/hmb/stopped_space`, () => { + return new HttpResponse( + JSON.stringify({ + id: app_reference, + runtime: { ...runtime_response, stage: "STOPPED" } + }), + { + status: 200, + headers: { + "Content-Type": "application/json" + } + } + ); + }), + http.get(`${root_url}/api/spaces/hmb/failed_space`, () => { + throw new HttpResponse(null, { + status: 500, + headers: { + "Content-Type": "application/json" + } + }); + }), + http.get(`${root_url}/api/spaces/${unauth_app_reference}`, () => { + return new HttpResponse( + JSON.stringify({ + id: unauth_app_reference, + runtime: { ...runtime_response } + }), + { + status: 200, + headers: { + "Content-Type": "application/json" + } + } + ); + }), + // jwt requests + http.get(`${root_url}/api/spaces/${app_reference}/jwt`, () => { + return new HttpResponse( + JSON.stringify({ + token: "jwt_123" + }), + { + status: 200, + headers: { + "Content-Type": "application/json" + } + } + ); + }), + http.get(`${root_url}/api/spaces/${broken_app_reference}/jwt`, () => { + return new HttpResponse(null, { + status: 500, + headers: { + "Content-Type": "application/json" + } + }); + }), + // post_data requests + http.post(`${direct_space_url}`, () => { + return new HttpResponse(JSON.stringify({}), { + status: 200, + headers: { + "Content-Type": "application/json" + } + }); + }), + http.post(`${private_space_url}`, () => { + return new HttpResponse(JSON.stringify(BROKEN_CONNECTION_MSG), { + status: 500, + headers: { + "Content-Type": "application/json" + } + }); + }), + // heartbeat requests + http.get(`*/heartbeat/*`, () => { + return new HttpResponse(null, { + status: 200, + headers: { + "Content-Type": "application/json" + } + }); + }), + // login requests + http.post(`${auth_app_space_url}/${LOGIN_URL}`, async ({ request }) => { + let username; + let password; + + await request.formData().then((data) => { + username = data.get("username"); + password = data.get("password"); + }); + + if (username === "admin" && password === "pass1234") { + return new HttpResponse( + JSON.stringify({ + success: true + }), + { + status: 200, + headers: { + "Content-Type": "application/json", + "Set-Cookie": + "access-token-123=abc; HttpOnly; Path=/; SameSite=none; Secure", + // @ts-ignore - multiple Set-Cookie headers are returned + "Set-Cookie": + "access-token-unsecure-123=abc; HttpOnly; Path=/; SameSite=none; Secure" + } + } + ); + } + + return new HttpResponse(null, { + status: 401, + headers: { + "Content-Type": "application/json" + } + }); + }), + http.post(`${invalid_auth_space_url}/${LOGIN_URL}`, async () => { + return new HttpResponse(null, { + status: 401, + headers: { + "Content-Type": "application/json" + } + }); + }), + http.post(`${private_auth_space_url}/${LOGIN_URL}`, async ({ request }) => { + let username; + let password; + + await request.formData().then((data) => { + username = data.get("username"); + password = data.get("password"); + }); + + if (username === "admin" && password === "pass1234") { + return new HttpResponse( + JSON.stringify({ + success: true + }), + { + status: 200, + headers: { + "Content-Type": "application/json", + "Set-Cookie": + "access-token-123=abc; HttpOnly; Path=/; SameSite=none; Secure", + // @ts-ignore - multiple Set-Cookie headers are returned + "Set-Cookie": + "access-token-unsecure-123=abc; HttpOnly; Path=/; SameSite=none; Secure" + } + } + ); + } + + return new HttpResponse(null, { + status: 401, + headers: { + "Content-Type": "application/json" + } + }); + }) +]; diff --git a/node_modules/@gradio/client/src/test/init.test.ts b/node_modules/@gradio/client/src/test/init.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..e1d083d25f7900840b896c30bf25b100c15c1d8b --- /dev/null +++ b/node_modules/@gradio/client/src/test/init.test.ts @@ -0,0 +1,162 @@ +import { + describe, + beforeAll, + afterEach, + afterAll, + test, + expect, + vi +} from "vitest"; + +import { Client, client, duplicate } from ".."; +import { + transformed_api_info, + config_response, + response_api_info +} from "./test_data"; +import { initialise_server } from "./server"; +import { SPACE_METADATA_ERROR_MSG } from "../constants"; + +const app_reference = "hmb/hello_world"; +const broken_app_reference = "hmb/bye_world"; +const direct_app_reference = "https://hmb-hello-world.hf.space"; +const secret_direct_app_reference = "https://hmb-secret-world.hf.space"; + +const server = initialise_server(); + +beforeAll(() => server.listen()); +afterEach(() => server.resetHandlers()); +afterAll(() => server.close()); + +describe("Client class", () => { + describe("initialisation", () => { + test("fetch is bound to the Client instance", async () => { + const test = await Client.connect("hmb/hello_world"); + const fetch_method = test.fetch; + const res = await fetch_method(direct_app_reference + "/info"); + + await expect(res.json()).resolves.toEqual(response_api_info); + }); + + test("stream is bound to the Client instance", async () => { + const test = await Client.connect("hmb/hello_world"); + const stream_method = test.stream; + const url = new URL(`${direct_app_reference}/queue/data`); + const stream = stream_method(url); + + expect(stream).toBeDefined(); + expect(stream.onmessage).toBeDefined(); + }); + + test("backwards compatibility of client using deprecated syntax", async () => { + const app = await client(app_reference); + expect(app.config).toEqual(config_response); + }); + test("connecting to a running app with a space reference", async () => { + const app = await Client.connect(app_reference); + expect(app.config).toEqual(config_response); + }); + + test("connecting to a running app with a direct app URL", async () => { + const app = await Client.connect(direct_app_reference); + expect(app.config).toEqual(config_response); + }); + + test("connecting successfully to a private running app with a space reference", async () => { + const app = await Client.connect("hmb/secret_world", { + hf_token: "hf_123" + }); + + expect(app.config).toEqual({ + ...config_response, + root: "https://hmb-secret-world.hf.space" + }); + }); + + test("connecting successfully to a private running app with a direct app URL ", async () => { + const app = await Client.connect(secret_direct_app_reference, { + hf_token: "hf_123" + }); + + expect(app.config).toEqual({ + ...config_response, + root: "https://hmb-secret-world.hf.space" + }); + }); + + test("unsuccessfully attempting to connect to a private running app", async () => { + await expect( + Client.connect("hmb/secret_world", { + hf_token: "hf_bad_token" + }) + ).rejects.toThrowError(SPACE_METADATA_ERROR_MSG); + }); + + test("viewing the api info of a running app", async () => { + const app = await Client.connect(app_reference); + expect(await app.view_api()).toEqual(transformed_api_info); + }); + + test("viewing the api info of a non-existent app", async () => { + const app = Client.connect(broken_app_reference); + await expect(app).rejects.toThrowError(); + }); + }); + + describe("duplicate", () => { + test("backwards compatibility of duplicate using deprecated syntax", async () => { + const app = await duplicate("gradio/hello_world", { + hf_token: "hf_123", + private: true, + hardware: "cpu-basic" + }); + + expect(app.config).toEqual(config_response); + }); + + test("creating a duplicate of a running app", async () => { + const duplicate = await Client.duplicate("gradio/hello_world", { + hf_token: "hf_123", + private: true, + hardware: "cpu-basic" + }); + + expect(duplicate.config).toEqual(config_response); + }); + + test("creating a duplicate of a running app without a token", async () => { + const duplicate = Client.duplicate("gradio/hello_world", { + private: true, + hardware: "cpu-basic" + }); + + await expect(duplicate).rejects.toThrow("Error: Unauthorized"); + }); + + test("creating a duplicate of a broken app", async () => { + const duplicate = Client.duplicate(broken_app_reference); + + await expect(duplicate).rejects.toThrow(SPACE_METADATA_ERROR_MSG); + }); + }); + + describe("overriding the Client class", () => { + // TODO: broken test since https://github.com/gradio-app/gradio/pull/10890 + test.skip("overriding methods on the Client class", async () => { + const mocked_fetch = vi.fn( + (input: RequestInfo | URL, init?: RequestInit): Promise => { + return Promise.resolve( + new Response(JSON.stringify({ data: "test" })) + ); + } + ); + + class CustomClient extends Client { + fetch = mocked_fetch; + } + + await CustomClient.connect("hmb/hello_world"); + expect(mocked_fetch).toHaveBeenCalled(); + }); + }); +}); diff --git a/node_modules/@gradio/client/src/test/init_helpers.test.ts b/node_modules/@gradio/client/src/test/init_helpers.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..055ad077363a5edd1301f6f276101847ce75cc74 --- /dev/null +++ b/node_modules/@gradio/client/src/test/init_helpers.test.ts @@ -0,0 +1,136 @@ +import { + resolve_root, + get_jwt, + determine_protocol, + parse_and_set_cookies +} from "../helpers/init_helpers"; +import { initialise_server } from "./server"; +import { beforeAll, afterEach, afterAll, it, expect, describe } from "vitest"; +import { Client } from "../client"; +import { INVALID_CREDENTIALS_MSG, MISSING_CREDENTIALS_MSG } from "../constants"; + +const server = initialise_server(); + +beforeAll(() => server.listen()); +afterEach(() => server.resetHandlers()); +afterAll(() => server.close()); + +describe("resolve_root", () => { + it('should return the base URL if the root path starts with "http://"', () => { + const base_url = "https://huggingface.co"; + const root_path = "https://hmb-hello-world.hf.space"; + const prioritize_base = true; + const result = resolve_root(base_url, root_path, prioritize_base); + expect(result).toBe(base_url); + }); + + it('should return the base URL if the root path starts with "https://"', () => { + const base_url = "https://huggingface.co"; + const root_path = "https://hmb-hello-world.hf.space"; + const prioritize_base = true; + const result = resolve_root(base_url, root_path, prioritize_base); + expect(result).toBe(base_url); + }); +}); + +describe("get_jwt", () => { + it("should return a valid JWT token when the API call is successful", async () => { + const space = "hmb/hello_world"; + const token = "hf_123"; + const expected_jwt = "jwt_123"; + + const result = await get_jwt(space, token); + + expect(result).toBe(expected_jwt); + }); + + it("should return false when the API call fails", async () => { + const space = "hmb/bye_world"; + const token = "hf_123"; + + const result = await get_jwt(space, token); + + expect(result).toBe(false); + }); +}); + +describe("determine_protocol", () => { + it('should return the correct protocols and host when the endpoint starts with "http"', () => { + const endpoint = "http://huggingface.co"; + const result = determine_protocol(endpoint); + expect(result).toEqual({ + ws_protocol: "ws", + http_protocol: "http:", + host: "huggingface.co" + }); + }); + + it('should return the correct protocols and host when the endpoint starts with "https"', () => { + const endpoint = "https://huggingface.co"; + const result = determine_protocol(endpoint); + expect(result).toEqual({ + ws_protocol: "wss", + http_protocol: "https:", + host: "huggingface.co" + }); + }); + + it('should return the correct protocols and host when the endpoint starts with "file"', () => { + const endpoint = "file:///path/to/app.html"; + const result = determine_protocol(endpoint); + expect(result).toEqual({ + ws_protocol: "ws", + http_protocol: "http:", + host: "lite.local" + }); + }); +}); + +describe("parse_and_set_cookies", () => { + it("should return an empty array when the cookie header is empty", () => { + const cookie_header = ""; + const result = parse_and_set_cookies(cookie_header); + expect(result).toEqual([]); + }); + + it("should parse the cookie header and return an array of cookies", () => { + const cookie_header = "access-token-123=abc;access-token-unsecured-456=def"; + const result = parse_and_set_cookies(cookie_header); + expect(result).toEqual(["access-token-123=abc"]); + }); +}); + +describe("resolve_cookies", () => { + it("should set the cookies when correct auth credentials are provided", async () => { + const client = await Client.connect("hmb/auth_space", { + auth: ["admin", "pass1234"] + }); + + const api = client.view_api(); + expect((await api).named_endpoints["/predict"]).toBeDefined(); + }); + + it("should connect to a private and authenticated space", async () => { + const client = await Client.connect("hmb/private_auth_space", { + hf_token: "hf_123", + auth: ["admin", "pass1234"] + }); + + const api = client.view_api(); + expect((await api).named_endpoints["/predict"]).toBeDefined(); + }); + + it("should not set the cookies when auth credentials are invalid", async () => { + await expect( + Client.connect("hmb/invalid_auth_space", { + auth: ["admin", "wrong_password"] + }) + ).rejects.toThrowError(INVALID_CREDENTIALS_MSG); + }); + + it("should not set the cookies when auth option is not provided in an auth space", async () => { + await expect(Client.connect("hmb/unauth_space")).rejects.toThrowError( + MISSING_CREDENTIALS_MSG + ); + }); +}); diff --git a/node_modules/@gradio/client/src/test/mock_eventsource.ts b/node_modules/@gradio/client/src/test/mock_eventsource.ts new file mode 100644 index 0000000000000000000000000000000000000000..1f47258cd3b90b03fa1dc97991806bc4fad54dfc --- /dev/null +++ b/node_modules/@gradio/client/src/test/mock_eventsource.ts @@ -0,0 +1,13 @@ +import { vi } from "vitest"; + +if (process.env.TEST_MODE !== "node") { + Object.defineProperty(window, "EventSource", { + writable: true, + value: vi.fn().mockImplementation(() => ({ + close: vi.fn(() => {}), + addEventListener: vi.fn(), + onmessage: vi.fn((_event: MessageEvent) => {}), + onerror: vi.fn((_event: Event) => {}) + })) + }); +} diff --git a/node_modules/@gradio/client/src/test/post_data.test.ts b/node_modules/@gradio/client/src/test/post_data.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..6ae96fed346ce8d2171ef1621ef394ca45d53684 --- /dev/null +++ b/node_modules/@gradio/client/src/test/post_data.test.ts @@ -0,0 +1,45 @@ +import { Client } from "../client"; + +import { initialise_server } from "./server"; +import { BROKEN_CONNECTION_MSG } from "../constants"; +const server = initialise_server(); +import { beforeAll, afterEach, afterAll, it, expect, describe } from "vitest"; + +beforeAll(() => server.listen()); +afterEach(() => server.resetHandlers()); +afterAll(() => server.close()); + +describe("post_data", () => { + it("should send a POST request with the correct headers and body", async () => { + const app = await Client.connect("hmb/hello_world"); + const config = app.config; + const url = config?.root; + const body = { data: "test" }; + + if (!url) { + throw new Error("No URL provided"); + } + + const [response, status] = await app.post_data(url, body); + + expect(response).toEqual({}); + expect(status).toBe(200); + }); + + it("should handle network errors", async () => { + const app = await Client.connect("hmb/secret_world", { + hf_token: "hf_123" + }); + + const url = "https://hmb-secret-world.hf.space"; + + if (!url) { + throw new Error("No URL provided"); + } + + const [response, status] = await app.post_data(url, {}); + + expect(response).toEqual(BROKEN_CONNECTION_MSG); + expect(status).toBe(500); + }); +}); diff --git a/node_modules/@gradio/client/src/test/server.ts b/node_modules/@gradio/client/src/test/server.ts new file mode 100644 index 0000000000000000000000000000000000000000..8eb91f6b278e6abb51965a1bf45561082c527bb6 --- /dev/null +++ b/node_modules/@gradio/client/src/test/server.ts @@ -0,0 +1,6 @@ +import { setupServer } from "msw/node"; +import { handlers } from "./handlers"; + +export function initialise_server(): any { + return setupServer(...handlers); +} diff --git a/node_modules/@gradio/client/src/test/spaces.test.ts b/node_modules/@gradio/client/src/test/spaces.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..77098d8bdff0591e97a8a1c8caf40cf9324531b5 --- /dev/null +++ b/node_modules/@gradio/client/src/test/spaces.test.ts @@ -0,0 +1,145 @@ +import { SPACE_STATUS_ERROR_MSG } from "../constants"; +import { + discussions_enabled, + get_space_hardware, + set_space_timeout, + check_space_status +} from "../helpers/spaces"; +import { beforeAll, afterEach, afterAll, it, expect, describe } from "vitest"; + +import { initialise_server } from "./server"; +import { hardware_sleeptime_response } from "./test_data"; +import { vi } from "vitest"; + +const server = initialise_server(); + +beforeAll(() => server.listen()); +afterEach(() => server.resetHandlers()); +afterAll(() => server.close()); + +describe("set_space_timeout", () => { + it("should set the sleep timeout for a space", async () => { + const space_id = "hmb/hello_world"; + const timeout = 60; + const hf_token = "hf_123"; + + const response = await set_space_timeout(space_id, timeout, hf_token); + + expect(response).toEqual(hardware_sleeptime_response); + }); + + it("should throw an error if the fetch call fails", async () => { + const space_id = "hmb/server_test"; + const timeout = 60; + const hf_token = "hf_123"; + + await expect( + set_space_timeout(space_id, timeout, hf_token) + ).rejects.toThrow( + "Could not set sleep timeout on duplicated Space. Please visit *ADD HF LINK TO SETTINGS* to set a timeout manually to reduce billing charges." + ); + }); +}); + +describe("get_space_hardware", () => { + it("should return the current hardware for a space", async () => { + const space_id = "hmb/hello_world"; + const hf_token = "hf_123"; + + const hardware = await get_space_hardware(space_id, hf_token); + expect(hardware).toEqual(hardware_sleeptime_response.hardware.current); + }); + + it("should throw an error if the fetch call fails", async () => { + const space_id = "hmb/bye_world"; + + await expect(get_space_hardware(space_id)).rejects.toThrow( + "Space hardware could not be obtained." + ); + }); +}); + +describe("discussions_enabled", () => { + it("should return true if discussions are enabled for the space", async () => { + const space_id = "hmb/hello_world"; + const result = await discussions_enabled(space_id); + expect(result).toBe(true); + }); + + it("should return false if discussions are disabled for the space", async () => { + const space_id = "hmb/bye_world"; + const result = await discussions_enabled(space_id); + expect(result).toBe(false); + }); +}); + +describe("check_space_status", () => { + const status_callback = vi.fn(); + + it("should handle a successful response with RUNNING stage", async () => { + const id = "hmb/hello_world"; + const type = "space_name"; + + await check_space_status(id, type, status_callback); + expect(status_callback).toHaveBeenCalledWith({ + status: "running", + load_status: "complete", + message: "Space is running.", + detail: "RUNNING" + }); + }); + + it("should handle a successful response with PAUSED stage", async () => { + const id = "hmb/paused_space"; + const type = "space_name"; + + await check_space_status(id, type, status_callback); + expect(status_callback).toHaveBeenCalledWith({ + status: "paused", + load_status: "error", + message: + "This space has been paused by the author. If you would like to try this demo, consider duplicating the space.", + detail: "PAUSED", + discussions_enabled: true + }); + }); + + it("should handle a successful response with BUILDING stage", async () => { + const id = "hmb/building_space"; + const type = "space_name"; + + await check_space_status(id, type, status_callback); + expect(status_callback).toHaveBeenCalledWith({ + status: "building", + load_status: "pending", + message: "Space is building...", + detail: "BUILDING" + }); + }); + + it("should handle a successful response with STOPPED stage", async () => { + const id = "hmb/stopped_space"; + const type = "space_name"; + + await check_space_status(id, type, status_callback); + expect(status_callback).toHaveBeenCalledWith({ + status: "sleeping", + load_status: "pending", + message: "Space is asleep. Waking it up...", + detail: "STOPPED" + }); + }); + + it("should handle a failed response", async () => { + const id = "hmb/failed_space"; + const type = "space_name"; + + await check_space_status(id, type, status_callback); + expect(status_callback).toHaveBeenCalledWith({ + status: "error", + load_status: "error", + message: SPACE_STATUS_ERROR_MSG, + detail: "NOT_FOUND" + }); + }); +}); diff --git a/node_modules/@gradio/client/src/test/stream.test.ts b/node_modules/@gradio/client/src/test/stream.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..9ac4b6c6a05b70f4fe07b7801eac9821fec62b8b --- /dev/null +++ b/node_modules/@gradio/client/src/test/stream.test.ts @@ -0,0 +1,81 @@ +import { vi, type Mock } from "vitest"; +import { Client } from "../client"; +import { readable_stream } from "../utils/stream"; +import { initialise_server } from "./server"; +import { direct_space_url } from "./handlers.ts"; + +import { + describe, + it, + expect, + afterEach, + beforeAll, + afterAll, + beforeEach +} from "vitest"; + +const server = initialise_server(); + +beforeAll(() => server.listen()); +afterEach(() => server.resetHandlers()); +afterAll(() => server.close()); + +describe("open_stream", () => { + let app: Client; + + beforeEach(async () => { + app = await Client.connect("hmb/hello_world"); + app.stream = vi.fn().mockImplementation(() => { + app.stream_instance = readable_stream( + new URL(`${direct_space_url}/queue/data`) + ); + return app.stream_instance; + }); + }); + + afterEach(() => { + vi.clearAllMocks(); + }); + + it("should throw an error if config is not defined", () => { + app.config = undefined; + + expect(async () => { + await app.open_stream(); + }).rejects.toThrow("Could not resolve app config"); + }); + + it("should connect to the SSE endpoint and handle messages", async () => { + await app.open_stream(); + + const eventsource_mock_call = (app.stream as Mock).mock.calls[0][0]; + + expect(eventsource_mock_call.href).toMatch( + /https:\/\/hmb-hello-world\.hf\.space\/queue\/data\?session_hash/ + ); + + expect(app.stream).toHaveBeenCalledWith(eventsource_mock_call); + + if (!app.stream_instance?.onmessage || !app.stream_instance?.onerror) { + throw new Error("stream instance is not defined"); + } + + const onMessageCallback = app.stream_instance.onmessage.bind(app); + const onErrorCallback = app.stream_instance.onerror.bind(app); + + const message = { msg: "hello jerry" }; + + onMessageCallback({ data: JSON.stringify(message) }); + expect(app.stream_status.open).toBe(true); + + expect(app.event_callbacks).toEqual({}); + expect(app.pending_stream_messages).toEqual({}); + + const close_stream_message = { msg: "close_stream" }; + onMessageCallback({ data: JSON.stringify(close_stream_message) }); + expect(app.stream_status.open).toBe(false); + + onErrorCallback({ data: JSON.stringify("404") }); + expect(app.stream_status.open).toBe(false); + }); +}); diff --git a/node_modules/@gradio/client/src/test/test_data.ts b/node_modules/@gradio/client/src/test/test_data.ts new file mode 100644 index 0000000000000000000000000000000000000000..a89b3eac070f762b09267d3c309107adb68e3c8c --- /dev/null +++ b/node_modules/@gradio/client/src/test/test_data.ts @@ -0,0 +1,559 @@ +// @ts-nocheck +import { ApiData, ApiInfo, Config, EndpointInfo } from "../types"; + +export const runtime_response = { + stage: "RUNNING", + hardware: { + current: "cpu-basic", + requested: "cpu-basic" + }, + storage: { + current: null, + requested: null + }, + gcTimeout: 86400, + replicas: { + current: 1, + requested: 1 + }, + devMode: false, + domains: [ + { + domain: "hmb-hello-world.hf.space", + isCustom: false, + stage: "READY" + } + ] +}; + +export const transformed_api_info: ApiInfo = { + named_endpoints: { + "/predict": { + parameters: [ + { + label: "name", + type: "string", + python_type: { type: "str", description: "" }, + component: "Textbox", + example_input: "Hello!!" + } + ], + returns: [ + { + label: "output", + type: "string", + python_type: { type: "str", description: "" }, + component: "Textbox" + } + ], + type: { generator: false, cancel: false } + } + }, + unnamed_endpoints: { + "0": { + parameters: [ + { + label: "name", + type: "string", + python_type: { type: "str", description: "" }, + component: "Textbox", + example_input: "Hello!!" + } + ], + returns: [ + { + label: "output", + type: "string", + python_type: { type: "str", description: "" }, + component: "Textbox" + } + ], + type: { generator: false, cancel: false } + } + } +}; + +export const response_api_info: ApiInfo = { + named_endpoints: { + "/predict": { + parameters: [ + { + label: "name", + type: { + type: "string" + }, + python_type: { + type: "str", + description: "" + }, + component: "Textbox", + example_input: "Hello!!" + } + ], + returns: [ + { + label: "output", + type: { + type: "string" + }, + python_type: { + type: "str", + description: "" + }, + component: "Textbox" + } + ] + } + }, + unnamed_endpoints: {} +}; + +export const config_response: Config = { + version: "4.27.0", + mode: "interface", + app_id: 123, + dev_mode: false, + analytics_enabled: true, + components: [ + { + id: 3, + type: "row", + props: { + variant: "default", + visible: true, + equal_height: false, + name: "row" + }, + skip_api: true, + component_class_id: "" + }, + { + id: 4, + type: "column", + props: { + scale: 1, + min_width: 320, + variant: "panel", + visible: true, + name: "column" + }, + skip_api: true, + component_class_id: "" + }, + { + id: 5, + type: "column", + props: { + scale: 1, + min_width: 320, + variant: "default", + visible: true, + name: "column" + }, + skip_api: true, + component_class_id: "" + }, + { + id: 1, + type: "textbox", + props: { + lines: 1, + max_lines: 20, + label: "name", + show_label: true, + container: true, + min_width: 160, + visible: true, + autofocus: false, + autoscroll: true, + elem_classes: [], + type: "text", + rtl: false, + show_copy_button: false, + name: "textbox", + _selectable: false + }, + skip_api: false, + component_class_id: "", + api_info: { + type: "string" + }, + example_inputs: "Hello!!" + }, + { + id: 6, + type: "form", + props: { + scale: 0, + min_width: 0, + name: "form" + }, + skip_api: true, + component_class_id: "" + }, + { + id: 7, + type: "row", + props: { + variant: "default", + visible: true, + equal_height: true, + name: "row" + }, + skip_api: true, + component_class_id: "" + }, + { + id: 8, + type: "button", + props: { + value: "Clear", + variant: "secondary", + visible: true, + interactive: true, + elem_classes: [], + show_api: false, + name: "button", + _selectable: false + }, + skip_api: true, + component_class_id: "" + }, + { + id: 9, + type: "button", + props: { + value: "Submit", + variant: "primary", + visible: true, + interactive: true, + elem_classes: [], + name: "button", + _selectable: false + }, + skip_api: true, + component_class_id: "" + }, + { + id: 10, + type: "column", + props: { + scale: 1, + min_width: 320, + variant: "panel", + visible: true, + name: "column" + }, + skip_api: true, + component_class_id: "" + }, + { + id: 2, + type: "textbox", + props: { + lines: 1, + max_lines: 20, + label: "output", + show_label: true, + container: true, + min_width: 160, + interactive: false, + visible: true, + autofocus: false, + autoscroll: true, + elem_classes: [], + type: "text", + rtl: false, + show_copy_button: false, + name: "textbox", + _selectable: false + }, + skip_api: false, + component_class_id: "", + api_info: { + type: "string" + }, + example_inputs: "Hello!!" + }, + { + id: 11, + type: "row", + props: { + variant: "default", + visible: true, + equal_height: true, + name: "row" + }, + skip_api: true, + component_class_id: "" + }, + { + id: 12, + type: "form", + props: { + scale: 0, + min_width: 0, + name: "form" + }, + skip_api: true, + component_class_id: "" + } + ], + css: null, + js: null, + head: null, + title: "Gradio", + space_id: "hmb/hello_world", + enable_queue: true, + show_error: false, + show_api: true, + is_colab: false, + stylesheets: [], + theme: "default", + protocol: "sse_v3", + body_css: { + body_background_fill: "white", + body_text_color: "#1f2937", + body_background_fill_dark: "#0b0f19", + body_text_color_dark: "#f3f4f6" + }, + fill_height: false, + layout: { + id: 0, + children: [ + { + id: 3, + children: [ + { + id: 4, + children: [ + { + id: 5, + children: [ + { + id: 6, + children: [ + { + id: 1 + } + ] + } + ] + }, + { + id: 7, + children: [ + { + id: 8 + }, + { + id: 9 + } + ] + } + ] + }, + { + id: 10, + children: [ + { + id: 12, + children: [ + { + id: 2 + } + ] + }, + { + id: 11, + children: [] + } + ] + } + ] + } + ] + }, + dependencies: [ + { + id: 0, + targets: [ + [9, "click"], + [1, "submit"] + ], + inputs: [1], + outputs: [2], + backend_fn: true, + js: null, + queue: null, + api_name: "predict", + scroll_to_output: false, + show_progress: "full", + every: null, + batch: false, + max_batch_size: 4, + cancels: [], + types: { + generator: false, + cancel: false + }, + collects_event_data: false, + trigger_after: null, + trigger_only_on_success: false, + trigger_mode: "once", + show_api: true, + zerogpu: false + }, + { + id: 1, + targets: [[8, "click"]], + inputs: [], + outputs: [1, 2], + backend_fn: false, + js: "() => [null, null]", + queue: false, + api_name: "js_fn", + scroll_to_output: false, + show_progress: "full", + every: null, + batch: false, + max_batch_size: 4, + cancels: [], + types: { + generator: false, + cancel: false + }, + collects_event_data: false, + trigger_after: null, + trigger_only_on_success: false, + trigger_mode: "once", + show_api: false, + zerogpu: false + }, + { + id: 2, + targets: [[8, "click"]], + inputs: [], + outputs: [5], + backend_fn: false, + js: '() => [{"variant": null, "visible": true, "__type__": "update"}]\n ', + queue: false, + api_name: "js_fn_1", + scroll_to_output: false, + show_progress: "full", + every: null, + batch: false, + max_batch_size: 4, + cancels: [], + types: { + generator: false, + cancel: false + }, + collects_event_data: false, + trigger_after: null, + trigger_only_on_success: false, + trigger_mode: "once", + show_api: false, + zerogpu: false + } + ], + root: "https://hmb-hello-world.hf.space", + path: "" +}; + +export const whoami_response = { + type: "user", + id: "123", + name: "hmb", + fullname: "jerry", + email: "jerry@gradio.com", + emailVerified: true, + canPay: true, + periodEnd: 123, + isPro: false, + avatarUrl: "", + orgs: [], + auth: { + type: "access_token", + accessToken: { + displayName: "Gradio Client", + role: "write" + } + } +}; + +export const duplicate_response = { + url: "https://huggingface.co/spaces/hmb/hello_world" +}; + +export const hardware_sleeptime_response = { + stage: "RUNNING", + hardware: { + current: "cpu-basic", + requested: "cpu-upgrade" + }, + storage: null, + gcTimeout: 300, + replicas: { + current: 1, + requested: 1 + }, + devMode: false, + domains: [ + { + domain: "hmb-hello-world.hf.space", + isCustom: false, + stage: "READY" + } + ] +}; + +export const endpoint_info: EndpointInfo = { + parameters: [ + { + label: "parameter_2", + parameter_name: "im", + parameter_has_default: false, + parameter_default: null, + type: "", + python_type: { + type: "Dict(background: filepath | None, layers: List[filepath], composite: filepath | None, id: str | None)", + description: "" + }, + component: "Imageeditor", + example_input: { + background: { + path: "", + meta: { + _type: "gradio.FileData" + }, + orig_name: "bus.png", + url: "" + }, + layers: [], + composite: null + } + } + ], + returns: [ + { + label: "value_3", + type: "string", + python_type: { + type: "filepath", + description: "" + }, + component: "Image" + } + ], + type: { + generator: false + } +}; + +export const discussions_response = { + discussions: [], + count: 0, + start: 0, + numClosedDiscussions: 0 +}; diff --git a/node_modules/@gradio/client/src/test/upload_files.test.ts b/node_modules/@gradio/client/src/test/upload_files.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..2f50a0984a305d741833eac824b5e112ab6feb00 --- /dev/null +++ b/node_modules/@gradio/client/src/test/upload_files.test.ts @@ -0,0 +1,42 @@ +import { describe, it, expect, afterEach, beforeAll, afterAll } from "vitest"; + +import { Client } from ".."; +import { initialise_server } from "./server"; + +const server = initialise_server(); + +beforeAll(() => server.listen()); +afterEach(() => server.resetHandlers()); +afterAll(() => server.close()); + +describe("upload_files", () => { + it("should upload files successfully", async () => { + const root_url = "https://hmb-hello-world.hf.space"; + + const client = await Client.connect("hmb/hello_world", { + hf_token: "hf_token" + }); + + const files = [new Blob([], { type: "image/jpeg" })]; + + const response = await client.upload_files(root_url, files); + + if (!response.files) { + throw new Error("No files returned"); + } + + expect(response.files).toHaveLength(1); + expect(response.files[0]).toBe("lion.jpg"); + }); + + it.skip("should handle a server error when connected to a running app and uploading files", async () => { + const client = await Client.connect("hmb/server_test"); + + const root_url = "https://hmb-server-test.hf.space"; + const files = [new Blob([""], { type: "text/plain" })]; + + await expect(client.upload_files(root_url, files)).rejects.toThrow( + "Connection errored out. Failed to fetch" + ); + }); +}); diff --git a/node_modules/@gradio/client/src/test/view_api.test.ts b/node_modules/@gradio/client/src/test/view_api.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..c137be6e2d553f17f72ed41f5e85e6985f060226 --- /dev/null +++ b/node_modules/@gradio/client/src/test/view_api.test.ts @@ -0,0 +1,53 @@ +import { describe, beforeAll, afterEach, afterAll, test, expect } from "vitest"; + +import { Client, client, duplicate } from ".."; +import { transformed_api_info, config_response } from "./test_data"; +import { initialise_server } from "./server"; + +const app_reference = "hmb/hello_world"; +const secret_app_reference = "hmb/secret_world"; +const secret_direct_app_reference = "https://hmb-secret-world.hf.space"; + +const server = initialise_server(); + +beforeAll(() => server.listen()); +afterEach(() => server.resetHandlers()); +afterAll(() => server.close()); + +describe("view_api", () => { + test("viewing the api of a running, public app", async () => { + const app = await Client.connect(app_reference); + + expect(await app.view_api()).toEqual(transformed_api_info); + }); + + test("viewing the api of a running, private app", async () => { + const app = await Client.connect(secret_app_reference, { + hf_token: "hf_123" + }); + + expect(app.config).toEqual({ + ...config_response, + root: secret_direct_app_reference + }); + + expect(await app.view_api()).toEqual({ + ...transformed_api_info + }); + }); + + test("viewing the api of a running, private app with a direct app URL", async () => { + const app = await Client.connect(secret_direct_app_reference, { + hf_token: "hf_123" + }); + + expect(app.config).toEqual({ + ...config_response, + root: secret_direct_app_reference + }); + + expect(await app.view_api()).toEqual({ + ...transformed_api_info + }); + }); +}); diff --git a/node_modules/@gradio/client/src/types.ts b/node_modules/@gradio/client/src/types.ts new file mode 100644 index 0000000000000000000000000000000000000000..f84fa06a9c5fe39d43e1d57c53e7479a32c43ccb --- /dev/null +++ b/node_modules/@gradio/client/src/types.ts @@ -0,0 +1,410 @@ +// API Data Types + +import { hardware_types } from "./helpers/spaces"; +import type { SvelteComponent } from "svelte"; +import type { ComponentType } from "svelte"; + +export interface ApiData { + label: string; + parameter_name: string; + parameter_default?: any; + parameter_has_default?: boolean; + type: { + type: any; + description: string; + }; + component: string; + example_input?: any; + python_type: { type: string; description: string }; + serializer: string; +} + +export interface JsApiData { + label: string; + parameter_name: string; + parameter_default?: any; + parameter_has_default?: boolean; + type: string; + description: string; + component: string; + example_input?: any; + serializer: string; + python_type: { type: string; description: string }; +} + +export interface EndpointInfo { + parameters: T[]; + returns: T[]; + type?: DependencyTypes; +} + +export interface ApiInfo { + named_endpoints: Record>; + unnamed_endpoints: Record>; +} + +export interface BlobRef { + path: string[]; + type: string | undefined; + blob: Blob | File | false; +} + +export type DataType = string | Buffer | Record | any[]; + +// custom class used for uploading local files +export class Command { + type: string; + command: string; + meta: { + path: string; + name: string; + orig_path: string; + }; + fileData?: FileData; + + constructor( + command: string, + meta: { path: string; name: string; orig_path: string } + ) { + this.type = "command"; + this.command = command; + this.meta = meta; + } +} + +// Function Signature Types + +export type SubmitFunction = ( + endpoint: string | number, + data?: unknown[] | Record, + event_data?: unknown, + trigger_id?: number | null +) => SubmitIterable; + +export type PredictFunction = ( + endpoint: string | number, + data?: unknown[] | Record, + event_data?: unknown +) => Promise; + +export type client_return = { + config: Config | undefined; + predict: PredictFunction; + submit: SubmitFunction; + component_server: ( + component_id: number, + fn_name: string, + data: unknown[] + ) => any; + view_api: (_fetch: typeof fetch) => Promise>; +}; + +export interface SubmitIterable extends AsyncIterable { + [Symbol.asyncIterator](): AsyncIterator; + cancel: () => Promise; + event_id: () => string; +} + +export type PredictReturn = { + type: EventType; + time: Date; + data: unknown; + endpoint: string; + fn_index: number; +}; + +// Space Status Types + +export type SpaceStatus = SpaceStatusNormal | SpaceStatusError; + +export interface SpaceStatusNormal { + status: + | "sleeping" + | "running" + | "building" + | "error" + | "stopped" + | "starting"; + detail: + | "SLEEPING" + | "RUNNING" + | "RUNNING_BUILDING" + | "BUILDING" + | "APP_STARTING" + | "NOT_FOUND"; + load_status: "pending" | "error" | "complete" | "generating"; + message: string; +} + +export interface SpaceStatusError { + status: "space_error" | "paused"; + detail: + | "NO_APP_FILE" + | "CONFIG_ERROR" + | "BUILD_ERROR" + | "RUNTIME_ERROR" + | "PAUSED"; + load_status: "error"; + message: string; + discussions_enabled: boolean; +} + +export type SpaceStatusCallback = (a: SpaceStatus) => void; + +// Configuration and Response Types +// -------------------------------- +export interface Config { + deep_link_state?: "none" | "valid" | "invalid"; + auth_required?: true; + analytics_enabled: boolean; + connect_heartbeat: boolean; + auth_message: string; + components: ComponentMeta[]; + css: string | null; + js: string | null; + head: string | null; + dependencies: Dependency[]; + dev_mode: boolean; + enable_queue: boolean; + show_error: boolean; + layout: any; + mode: "blocks" | "interface"; + root: string; + root_url?: string; + theme: string; + title: string; + version: string; + space_id: string | null; + is_space: boolean; + is_colab: boolean; + show_api: boolean; + stylesheets: string[]; + path: string; + current_page: string; + page: Record< + string, + { + components: number[]; + dependencies: number[]; + layout: any; + } + >; + pages: [string, string][]; + protocol: "sse_v3" | "sse_v2.1" | "sse_v2" | "sse_v1" | "sse" | "ws"; + max_file_size?: number; + theme_hash?: number; + username: string | null; + api_prefix?: string; + fill_height?: boolean; + fill_width?: boolean; + pwa?: boolean; +} + +// todo: DRY up types +export interface ComponentMeta { + type: string; + id: number; + has_modes: boolean; + props: SharedProps; + instance: SvelteComponent; + component: ComponentType; + documentation?: Documentation; + children?: ComponentMeta[]; + parent?: ComponentMeta; + value?: any; + component_class_id: string; + key: string | number | null; + rendered_in?: number; +} + +interface SharedProps { + elem_id?: string; + elem_classes?: string[]; + components?: string[]; + server_fns?: string[]; + interactive: boolean; + [key: string]: unknown; + root_url?: string; +} + +export interface Documentation { + type?: TypeDescription; + description?: TypeDescription; + example_data?: string; +} + +interface TypeDescription { + input_payload?: string; + response_object?: string; + payload?: string; +} + +export interface Dependency { + id: number; + targets: [number, string][]; + inputs: number[]; + outputs: number[]; + backend_fn: boolean; + js: string | null; + scroll_to_output: boolean; + trigger: "click" | "load" | string; + max_batch_size: number; + show_progress: "full" | "minimal" | "hidden"; + show_progress_on: number[] | null; + frontend_fn: ((...args: unknown[]) => Promise) | null; + status?: string; + queue: boolean | null; + every: number | null; + batch: boolean; + api_name: string | null; + cancels: number[]; + types: DependencyTypes; + collects_event_data: boolean; + pending_request?: boolean; + trigger_after?: number; + trigger_only_on_success?: boolean; + trigger_mode: "once" | "multiple" | "always_last"; + final_event: Payload | null; + show_api: boolean; + rendered_in: number | null; + render_id: number | null; + connection: "stream" | "sse"; + time_limit: number; + stream_every: number; + like_user_message: boolean; + event_specific_args: string[]; + js_implementation: string | null; +} + +export interface DependencyTypes { + generator: boolean; + cancel: boolean; +} + +export interface Payload { + fn_index: number; + data: unknown[]; + time?: Date; + event_data?: unknown; + trigger_id?: number | null; +} + +export interface PostResponse { + error?: string; + [x: string]: any; +} + +export interface UploadResponse { + error?: string; + files?: string[]; +} + +// Client and File Handling Types + +export interface DuplicateOptions extends ClientOptions { + private?: boolean; + hardware?: (typeof hardware_types)[number]; + timeout?: number; +} + +export interface ClientOptions { + hf_token?: `hf_${string}`; + status_callback?: SpaceStatusCallback | null; + auth?: [string, string] | null; + with_null_state?: boolean; + events?: EventType[]; + headers?: Record; + query_params?: Record; +} + +export interface FileData { + name: string; + orig_name?: string; + size?: number; + data: string; + blob?: File; + is_file?: boolean; + mime_type?: string; + alt_text?: string; +} + +// Event and Listener Types + +export type EventType = "data" | "status" | "log" | "render"; + +export interface EventMap { + data: PayloadMessage; + status: StatusMessage; + log: LogMessage; + render: RenderMessage; +} + +export type GradioEvent = { + [P in EventType]: EventMap[P]; +}[EventType]; + +export interface Log { + log: string; + title: string; + level: "warning" | "info" | "success"; +} +export interface Render { + data: { + components: any[]; + layout: any; + dependencies: Dependency[]; + render_id: number; + }; +} + +export interface Status { + queue: boolean; + code?: string; + success?: boolean; + stage: "pending" | "error" | "complete" | "generating" | "streaming"; + duration?: number; + visible?: boolean; + broken?: boolean; + size?: number; + position?: number; + eta?: number; + title?: string; + message?: string; + progress_data?: { + progress: number | null; + index: number | null; + length: number | null; + unit: string | null; + desc: string | null; + }[]; + time?: Date; + changed_state_ids?: number[]; + time_limit?: number; +} + +export interface StatusMessage extends Status { + type: "status"; + endpoint: string; + fn_index: number; + original_msg?: string; +} + +export interface PayloadMessage extends Payload { + type: "data"; + endpoint: string; + fn_index: number; +} + +export interface LogMessage extends Log { + type: "log"; + endpoint: string; + fn_index: number; + duration: number | null; + visible: boolean; +} + +export interface RenderMessage extends Render { + type: "render"; + endpoint: string; + fn_index: number; +} diff --git a/node_modules/@gradio/client/src/upload.ts b/node_modules/@gradio/client/src/upload.ts new file mode 100644 index 0000000000000000000000000000000000000000..175093a2c40f81e52efe5ce4c3d5dc1b9aba922a --- /dev/null +++ b/node_modules/@gradio/client/src/upload.ts @@ -0,0 +1,109 @@ +import type { Client } from "./client"; + +export async function upload( + this: Client, + file_data: FileData[], + root_url: string, + upload_id?: string, + max_file_size?: number +): Promise<(FileData | null)[] | null> { + let files = (Array.isArray(file_data) ? file_data : [file_data]).map( + (file_data) => file_data.blob! + ); + + const oversized_files = files.filter( + (f) => f.size > (max_file_size ?? Infinity) + ); + if (oversized_files.length) { + throw new Error( + `File size exceeds the maximum allowed size of ${max_file_size} bytes: ${oversized_files + .map((f) => f.name) + .join(", ")}` + ); + } + + return await Promise.all( + await this.upload_files(root_url, files, upload_id).then( + async (response: { files?: string[]; error?: string }) => { + if (response.error) { + throw new Error(response.error); + } else { + if (response.files) { + return response.files.map((f, i) => { + const file = new FileData({ + ...file_data[i], + path: f, + url: `${root_url}${this.api_prefix}/file=${f}` + }); + return file; + }); + } + + return []; + } + } + ) + ); +} + +export async function prepare_files( + files: File[], + is_stream?: boolean +): Promise { + return files.map( + (f) => + new FileData({ + path: f.name, + orig_name: f.name, + blob: f, + size: f.size, + mime_type: f.type, + is_stream + }) + ); +} + +export class FileData { + path: string; + url?: string; + orig_name?: string; + size?: number; + blob?: File; + is_stream?: boolean; + mime_type?: string; + alt_text?: string; + b64?: string; + readonly meta = { _type: "gradio.FileData" }; + + constructor({ + path, + url, + orig_name, + size, + blob, + is_stream, + mime_type, + alt_text, + b64 + }: { + path: string; + url?: string; + orig_name?: string; + size?: number; + blob?: File; + is_stream?: boolean; + mime_type?: string; + alt_text?: string; + b64?: string; + }) { + this.path = path; + this.url = url; + this.orig_name = orig_name; + this.size = size; + this.blob = url ? undefined : blob; + this.is_stream = is_stream; + this.mime_type = mime_type; + this.alt_text = alt_text; + this.b64 = b64; + } +} diff --git a/node_modules/@gradio/client/src/utils/duplicate.ts b/node_modules/@gradio/client/src/utils/duplicate.ts new file mode 100644 index 0000000000000000000000000000000000000000..27cecd3ffbce98b52a9f04b744012fb5ea291ba5 --- /dev/null +++ b/node_modules/@gradio/client/src/utils/duplicate.ts @@ -0,0 +1,129 @@ +import { + get_space_hardware, + hardware_types, + set_space_timeout +} from "../helpers/spaces"; +import type { DuplicateOptions } from "../types"; +import { Client } from "../client"; +import { SPACE_METADATA_ERROR_MSG } from "../constants"; +import { + get_cookie_header, + parse_and_set_cookies +} from "../helpers/init_helpers"; +import { process_endpoint } from "../helpers/api_info"; + +export async function duplicate( + app_reference: string, + options: DuplicateOptions +): Promise { + const { hf_token, private: _private, hardware, timeout, auth } = options; + + if (hardware && !hardware_types.includes(hardware)) { + throw new Error( + `Invalid hardware type provided. Valid types are: ${hardware_types + .map((v) => `"${v}"`) + .join(",")}.` + ); + } + + const { http_protocol, host } = await process_endpoint( + app_reference, + hf_token + ); + + let cookies: string[] | null = null; + + if (auth) { + const cookie_header = await get_cookie_header( + http_protocol, + host, + auth, + fetch + ); + + if (cookie_header) cookies = parse_and_set_cookies(cookie_header); + } + + const headers = { + Authorization: `Bearer ${hf_token}`, + "Content-Type": "application/json", + ...(cookies ? { Cookie: cookies.join("; ") } : {}) + }; + + const user = ( + await ( + await fetch(`https://huggingface.co/api/whoami-v2`, { + headers + }) + ).json() + ).name; + + const space_name = app_reference.split("/")[1]; + const body: { + repository: string; + private?: boolean; + hardware?: string; + } = { + repository: `${user}/${space_name}` + }; + + if (_private) { + body.private = true; + } + + let original_hardware; + + try { + if (!hardware) { + original_hardware = await get_space_hardware(app_reference, hf_token); + } + } catch (e) { + throw Error(SPACE_METADATA_ERROR_MSG + (e as Error).message); + } + + const requested_hardware = hardware || original_hardware || "cpu-basic"; + + body.hardware = requested_hardware; + + try { + const response = await fetch( + `https://huggingface.co/api/spaces/${app_reference}/duplicate`, + { + method: "POST", + headers, + body: JSON.stringify(body) + } + ); + + if (response.status === 409) { + try { + const client = await Client.connect(`${user}/${space_name}`, options); + return client; + } catch (error) { + console.error("Failed to connect Client instance:", error); + throw error; + } + } else if (response.status !== 200) { + throw new Error(response.statusText); + } + + const duplicated_space = await response.json(); + + await set_space_timeout(`${user}/${space_name}`, timeout || 300, hf_token); + + return await Client.connect( + get_space_reference(duplicated_space.url), + options + ); + } catch (e: any) { + throw new Error(e); + } +} + +function get_space_reference(url: string): any { + const regex = /https:\/\/huggingface.co\/spaces\/([^/]+\/[^/]+)/; + const match = url.match(regex); + if (match) { + return match[1]; + } +} diff --git a/node_modules/@gradio/client/src/utils/handle_blob.ts b/node_modules/@gradio/client/src/utils/handle_blob.ts new file mode 100644 index 0000000000000000000000000000000000000000..27caac304ec26f20a5c7c882ac0105c501f04ead --- /dev/null +++ b/node_modules/@gradio/client/src/utils/handle_blob.ts @@ -0,0 +1,140 @@ +import { update_object, walk_and_store_blobs } from "../helpers/data"; +import { + Command, + type ApiData, + type EndpointInfo, + type JsApiData +} from "../types"; +import { FileData } from "../upload"; +import type { Client } from ".."; +import { + FILE_PROCESSING_ERROR_MSG, + NODEJS_FS_ERROR_MSG, + ROOT_URL_ERROR_MSG +} from "../constants"; + +export async function handle_blob( + this: Client, + endpoint: string, + data: unknown[], + api_info: EndpointInfo +): Promise { + const self = this; + + await process_local_file_commands(self, data); + + const blobRefs = await walk_and_store_blobs( + data, + undefined, + [], + true, + api_info + ); + + const results = await Promise.all( + blobRefs.map(async ({ path, blob, type }) => { + if (!blob) return { path, type }; + + const response = await self.upload_files(endpoint, [blob]); + const file_url = response.files && response.files[0]; + return { + path, + file_url, + type, + name: + typeof File !== "undefined" && blob instanceof File + ? blob?.name + : undefined + }; + }) + ); + + results.forEach(({ path, file_url, type, name }) => { + if (type === "Gallery") { + update_object(data, file_url, path); + } else if (file_url) { + const file = new FileData({ path: file_url, orig_name: name }); + update_object(data, file, path); + } + }); + + return data; +} + +export async function process_local_file_commands( + client: Client, + data: unknown[] +): Promise { + const root = client.config?.root || client.config?.root_url; + + if (!root) { + throw new Error(ROOT_URL_ERROR_MSG); + } + + await recursively_process_commands(client, data); +} + +async function recursively_process_commands( + client: Client, + data: any, + path: string[] = [] +): Promise { + for (const key in data) { + if (data[key] instanceof Command) { + await process_single_command(client, data, key); + } else if (typeof data[key] === "object" && data[key] !== null) { + await recursively_process_commands(client, data[key], [...path, key]); + } + } +} + +async function process_single_command( + client: Client, + data: any, + key: string +): Promise { + let cmd_item = data[key] as Command; + const root = client.config?.root || client.config?.root_url; + + if (!root) { + throw new Error(ROOT_URL_ERROR_MSG); + } + + try { + let fileBuffer: Buffer; + let fullPath: string; + + // check if running in a Node.js environment + if ( + typeof process !== "undefined" && + process.versions && + process.versions.node + ) { + const fs = await import("fs/promises"); + const path = await import("path"); + + fullPath = path.resolve(process.cwd(), cmd_item.meta.path); + fileBuffer = await fs.readFile(fullPath); // Read file from disk + } else { + throw new Error(NODEJS_FS_ERROR_MSG); + } + + const file = new Blob([fileBuffer], { type: "application/octet-stream" }); + + const response = await client.upload_files(root, [file]); + + const file_url = response.files && response.files[0]; + + if (file_url) { + const fileData = new FileData({ + path: file_url, + orig_name: cmd_item.meta.name || "" + }); + + // replace the command object with the fileData object + data[key] = fileData; + } + } catch (error) { + console.error(FILE_PROCESSING_ERROR_MSG, error); + } +} diff --git a/node_modules/@gradio/client/src/utils/post_data.ts b/node_modules/@gradio/client/src/utils/post_data.ts new file mode 100644 index 0000000000000000000000000000000000000000..53264a3c86f3083df3ff336c867b697e20a3f69e --- /dev/null +++ b/node_modules/@gradio/client/src/utils/post_data.ts @@ -0,0 +1,38 @@ +import { BROKEN_CONNECTION_MSG } from "../constants"; +import type { PostResponse } from "../types"; +import { Client } from ".."; + +export async function post_data( + this: Client, + url: string, + body: unknown, + additional_headers?: any +): Promise<[PostResponse, number]> { + const headers: { + Authorization?: string; + "Content-Type": "application/json"; + } = { "Content-Type": "application/json" }; + if (this.options.hf_token) { + headers.Authorization = `Bearer ${this.options.hf_token}`; + } + try { + var response = await this.fetch(url, { + method: "POST", + body: JSON.stringify(body), + headers: { ...headers, ...additional_headers }, + credentials: "include" + }); + } catch (e) { + return [{ error: BROKEN_CONNECTION_MSG }, 500]; + } + let output: PostResponse; + let status: number; + try { + output = await response.json(); + status = response.status; + } catch (e) { + output = { error: `Could not parse server response: ${e}` }; + status = 500; + } + return [output, status]; +} diff --git a/node_modules/@gradio/client/src/utils/predict.ts b/node_modules/@gradio/client/src/utils/predict.ts new file mode 100644 index 0000000000000000000000000000000000000000..b6eda5831a9e3c7f9e57d85e1ba140f4d854d9fb --- /dev/null +++ b/node_modules/@gradio/client/src/utils/predict.ts @@ -0,0 +1,51 @@ +import { Client } from "../client"; +import type { Dependency, PredictReturn } from "../types"; + +export async function predict( + this: Client, + endpoint: string | number, + data: unknown[] | Record = {} +): Promise { + let data_returned = false; + let status_complete = false; + let dependency: Dependency; + + if (!this.config) { + throw new Error("Could not resolve app config"); + } + + if (typeof endpoint === "number") { + dependency = this.config.dependencies.find((dep) => dep.id == endpoint)!; + } else { + const trimmed_endpoint = endpoint.replace(/^\//, ""); + dependency = this.config.dependencies.find( + (dep) => dep.id == this.api_map[trimmed_endpoint] + )!; + } + + return new Promise(async (resolve, reject) => { + const app = this.submit(endpoint, data, null, null, true); + let result: unknown; + + for await (const message of app) { + if (message.type === "data") { + if (status_complete) { + resolve(result as PredictReturn); + } + data_returned = true; + result = message; + } + + if (message.type === "status") { + if (message.stage === "error") reject(message); + if (message.stage === "complete") { + status_complete = true; + // if complete message comes after data, resolve here + if (data_returned) { + resolve(result as PredictReturn); + } + } + } + } + }); +} diff --git a/node_modules/@gradio/client/src/utils/stream.ts b/node_modules/@gradio/client/src/utils/stream.ts new file mode 100644 index 0000000000000000000000000000000000000000..edfe5e555e8afe27b5f446b1729a7968edc5ab30 --- /dev/null +++ b/node_modules/@gradio/client/src/utils/stream.ts @@ -0,0 +1,228 @@ +import { BROKEN_CONNECTION_MSG, SSE_URL } from "../constants"; +import type { Client } from "../client"; +import { stream } from "fetch-event-stream"; + +export async function open_stream(this: Client): Promise { + let { + event_callbacks, + unclosed_events, + pending_stream_messages, + stream_status, + config, + jwt + } = this; + + const that = this; + + if (!config) { + throw new Error("Could not resolve app config"); + } + + stream_status.open = true; + + let stream: EventSource | null = null; + let params = new URLSearchParams({ + session_hash: this.session_hash + }).toString(); + + let url = new URL(`${config.root}${this.api_prefix}/${SSE_URL}?${params}`); + + if (jwt) { + url.searchParams.set("__sign", jwt); + } + + stream = this.stream(url); + + if (!stream) { + console.warn("Cannot connect to SSE endpoint: " + url.toString()); + return; + } + + stream.onmessage = async function (event: MessageEvent) { + let _data = JSON.parse(event.data); + if (_data.msg === "close_stream") { + close_stream(stream_status, that.abort_controller); + return; + } + const event_id = _data.event_id; + if (!event_id) { + await Promise.all( + Object.keys(event_callbacks).map((event_id) => + event_callbacks[event_id](_data) + ) + ); + } else if (event_callbacks[event_id] && config) { + if ( + _data.msg === "process_completed" && + ["sse", "sse_v1", "sse_v2", "sse_v2.1", "sse_v3"].includes( + config.protocol + ) + ) { + unclosed_events.delete(event_id); + } + let fn: (data: any) => void = event_callbacks[event_id]; + + if (typeof window !== "undefined" && typeof document !== "undefined") { + // fn(_data); // need to do this to put the event on the end of the event loop, so the browser can refresh between callbacks and not freeze in case of quick generations. See + setTimeout(fn, 0, _data); // need to do this to put the event on the end of the event loop, so the browser can refresh between callbacks and not freeze in case of quick generations. See https://github.com/gradio-app/gradio/pull/7055 + } else { + fn(_data); + } + } else { + if (!pending_stream_messages[event_id]) { + pending_stream_messages[event_id] = []; + } + pending_stream_messages[event_id].push(_data); + } + }; + stream.onerror = async function () { + await Promise.all( + Object.keys(event_callbacks).map((event_id) => + event_callbacks[event_id]({ + msg: "unexpected_error", + message: BROKEN_CONNECTION_MSG + }) + ) + ); + }; +} + +export function close_stream( + stream_status: { open: boolean }, + abort_controller: AbortController | null +): void { + if (stream_status) { + stream_status.open = false; + abort_controller?.abort(); + } +} + +export function apply_diff_stream( + pending_diff_streams: Record, + event_id: string, + data: any +): void { + let is_first_generation = !pending_diff_streams[event_id]; + if (is_first_generation) { + pending_diff_streams[event_id] = []; + data.data.forEach((value: any, i: number) => { + pending_diff_streams[event_id][i] = value; + }); + } else { + data.data.forEach((value: any, i: number) => { + let new_data = apply_diff(pending_diff_streams[event_id][i], value); + pending_diff_streams[event_id][i] = new_data; + data.data[i] = new_data; + }); + } +} + +export function apply_diff( + obj: any, + diff: [string, (number | string)[], any][] +): any { + diff.forEach(([action, path, value]) => { + obj = apply_edit(obj, path, action, value); + }); + + return obj; +} + +function apply_edit( + target: any, + path: (number | string)[], + action: string, + value: any +): any { + if (path.length === 0) { + if (action === "replace") { + return value; + } else if (action === "append") { + return target + value; + } + throw new Error(`Unsupported action: ${action}`); + } + + let current = target; + for (let i = 0; i < path.length - 1; i++) { + current = current[path[i]]; + } + + const last_path = path[path.length - 1]; + switch (action) { + case "replace": + current[last_path] = value; + break; + case "append": + current[last_path] += value; + break; + case "add": + if (Array.isArray(current)) { + current.splice(Number(last_path), 0, value); + } else { + current[last_path] = value; + } + break; + case "delete": + if (Array.isArray(current)) { + current.splice(Number(last_path), 1); + } else { + delete current[last_path]; + } + break; + default: + throw new Error(`Unknown action: ${action}`); + } + return target; +} + +export function readable_stream( + input: RequestInfo | URL, + init: RequestInit = {} +): EventSource { + const instance: EventSource & { readyState: number } = { + close: () => { + console.warn("Method not implemented."); + }, + onerror: null, + onmessage: null, + onopen: null, + readyState: 0, + url: input.toString(), + withCredentials: false, + CONNECTING: 0, + OPEN: 1, + CLOSED: 2, + addEventListener: () => { + throw new Error("Method not implemented."); + }, + dispatchEvent: () => { + throw new Error("Method not implemented."); + }, + removeEventListener: () => { + throw new Error("Method not implemented."); + } + }; + + stream(input, init) + .then(async (res) => { + instance.readyState = instance.OPEN; + try { + for await (const chunk of res) { + //@ts-ignore + instance.onmessage && instance.onmessage(chunk); + } + instance.readyState = instance.CLOSED; + } catch (e) { + instance.onerror && instance.onerror(e as Event); + instance.readyState = instance.CLOSED; + } + }) + .catch((e) => { + console.error(e); + instance.onerror && instance.onerror(e as Event); + instance.readyState = instance.CLOSED; + }); + + return instance as EventSource; +} diff --git a/node_modules/@gradio/client/src/utils/submit.ts b/node_modules/@gradio/client/src/utils/submit.ts new file mode 100644 index 0000000000000000000000000000000000000000..4f9b9d6d55c40ea7ab0e5dd0f177efae14d44a60 --- /dev/null +++ b/node_modules/@gradio/client/src/utils/submit.ts @@ -0,0 +1,864 @@ +/* eslint-disable complexity */ +import type { + Status, + Payload, + GradioEvent, + JsApiData, + EndpointInfo, + ApiInfo, + Config, + Dependency, + SubmitIterable +} from "../types"; + +import { skip_queue, post_message, handle_payload } from "../helpers/data"; +import { resolve_root } from "../helpers/init_helpers"; +import { + handle_message, + map_data_to_params, + process_endpoint +} from "../helpers/api_info"; +import semiver from "semiver"; +import { + BROKEN_CONNECTION_MSG, + QUEUE_FULL_MSG, + SSE_URL, + SSE_DATA_URL, + RESET_URL, + CANCEL_URL +} from "../constants"; +import { apply_diff_stream, close_stream } from "./stream"; +import { Client } from "../client"; + +export function submit( + this: Client, + endpoint: string | number, + data: unknown[] | Record = {}, + event_data?: unknown, + trigger_id?: number | null, + all_events?: boolean +): SubmitIterable { + try { + const { hf_token } = this.options; + const { + fetch, + app_reference, + config, + session_hash, + api_info, + api_map, + stream_status, + pending_stream_messages, + pending_diff_streams, + event_callbacks, + unclosed_events, + post_data, + options, + api_prefix + } = this; + + const that = this; + + if (!api_info) throw new Error("No API found"); + if (!config) throw new Error("Could not resolve app config"); + + let { fn_index, endpoint_info, dependency } = get_endpoint_info( + api_info, + endpoint, + api_map, + config + ); + + let resolved_data = map_data_to_params(data, endpoint_info); + + let websocket: WebSocket; + let stream: EventSource | null; + let protocol = config.protocol ?? "ws"; + let event_id_final = ""; + let event_id_cb: () => string = () => event_id_final; + + const _endpoint = typeof endpoint === "number" ? "/predict" : endpoint; + let payload: Payload; + let event_id: string | null = null; + let complete: Status | undefined | false = false; + let last_status: Record = {}; + let url_params = + typeof window !== "undefined" && typeof document !== "undefined" + ? new URLSearchParams(window.location.search).toString() + : ""; + + const events_to_publish = + options?.events?.reduce( + (acc, event) => { + acc[event] = true; + return acc; + }, + {} as Record + ) || {}; + + // event subscription methods + function fire_event(event: GradioEvent): void { + if (all_events || events_to_publish[event.type]) { + push_event(event); + } + } + + async function cancel(): Promise { + const _status: Status = { + stage: "complete", + queue: false, + time: new Date() + }; + complete = _status; + fire_event({ + ..._status, + type: "status", + endpoint: _endpoint, + fn_index: fn_index + }); + + let reset_request = {}; + let cancel_request = {}; + if (protocol === "ws") { + if (websocket && websocket.readyState === 0) { + websocket.addEventListener("open", () => { + websocket.close(); + }); + } else { + websocket.close(); + } + reset_request = { fn_index, session_hash }; + } else { + close_stream(stream_status, that.abort_controller); + close(); + reset_request = { event_id }; + cancel_request = { event_id, session_hash, fn_index }; + } + + try { + if (!config) { + throw new Error("Could not resolve app config"); + } + + if ("event_id" in cancel_request) { + await fetch(`${config.root}${api_prefix}/${CANCEL_URL}`, { + headers: { "Content-Type": "application/json" }, + method: "POST", + body: JSON.stringify(cancel_request) + }); + } + + await fetch(`${config.root}${api_prefix}/${RESET_URL}`, { + headers: { "Content-Type": "application/json" }, + method: "POST", + body: JSON.stringify(reset_request) + }); + } catch (e) { + console.warn( + "The `/reset` endpoint could not be called. Subsequent endpoint results may be unreliable." + ); + } + } + + const resolve_heartbeat = async (config: Config): Promise => { + await this._resolve_hearbeat(config); + }; + + async function handle_render_config(render_config: any): Promise { + if (!config) return; + let render_id: number = render_config.render_id; + config.components = [ + ...config.components.filter((c) => c.props.rendered_in !== render_id), + ...render_config.components + ]; + config.dependencies = [ + ...config.dependencies.filter((d) => d.rendered_in !== render_id), + ...render_config.dependencies + ]; + const any_state = config.components.some((c) => c.type === "state"); + const any_unload = config.dependencies.some((d) => + d.targets.some((t) => t[1] === "unload") + ); + config.connect_heartbeat = any_state || any_unload; + await resolve_heartbeat(config); + fire_event({ + type: "render", + data: render_config, + endpoint: _endpoint, + fn_index + }); + } + + this.handle_blob(config.root, resolved_data, endpoint_info).then( + async (_payload) => { + let input_data = handle_payload( + _payload, + dependency, + config.components, + "input", + true + ); + payload = { + data: input_data || [], + event_data, + fn_index, + trigger_id + }; + if (skip_queue(fn_index, config)) { + fire_event({ + type: "status", + endpoint: _endpoint, + stage: "pending", + queue: false, + fn_index, + time: new Date() + }); + + post_data( + `${config.root}${api_prefix}/run${ + _endpoint.startsWith("/") ? _endpoint : `/${_endpoint}` + }${url_params ? "?" + url_params : ""}`, + { + ...payload, + session_hash + } + ) + .then(([output, status_code]: any) => { + const data = output.data; + if (status_code == 200) { + fire_event({ + type: "data", + endpoint: _endpoint, + fn_index, + data: handle_payload( + data, + dependency, + config.components, + "output", + options.with_null_state + ), + time: new Date(), + event_data, + trigger_id + }); + if (output.render_config) { + handle_render_config(output.render_config); + } + + fire_event({ + type: "status", + endpoint: _endpoint, + fn_index, + stage: "complete", + eta: output.average_duration, + queue: false, + time: new Date() + }); + } else { + fire_event({ + type: "status", + stage: "error", + endpoint: _endpoint, + fn_index, + message: output.error, + queue: false, + time: new Date() + }); + } + }) + .catch((e) => { + fire_event({ + type: "status", + stage: "error", + message: e.message, + endpoint: _endpoint, + fn_index, + queue: false, + time: new Date() + }); + }); + } else if (protocol == "ws") { + const { ws_protocol, host } = await process_endpoint( + app_reference, + hf_token + ); + + fire_event({ + type: "status", + stage: "pending", + queue: true, + endpoint: _endpoint, + fn_index, + time: new Date() + }); + + let url = new URL( + `${ws_protocol}://${resolve_root( + host, + config.path as string, + true + )}/queue/join${url_params ? "?" + url_params : ""}` + ); + + if (this.jwt) { + url.searchParams.set("__sign", this.jwt); + } + + websocket = new WebSocket(url); + + websocket.onclose = (evt) => { + if (!evt.wasClean) { + fire_event({ + type: "status", + stage: "error", + broken: true, + message: BROKEN_CONNECTION_MSG, + queue: true, + endpoint: _endpoint, + fn_index, + time: new Date() + }); + } + }; + + websocket.onmessage = function (event) { + const _data = JSON.parse(event.data); + const { type, status, data } = handle_message( + _data, + last_status[fn_index] + ); + + if (type === "update" && status && !complete) { + // call 'status' listeners + fire_event({ + type: "status", + endpoint: _endpoint, + fn_index, + time: new Date(), + ...status + }); + if (status.stage === "error") { + websocket.close(); + } + } else if (type === "hash") { + websocket.send(JSON.stringify({ fn_index, session_hash })); + return; + } else if (type === "data") { + websocket.send(JSON.stringify({ ...payload, session_hash })); + } else if (type === "complete") { + complete = status; + } else if (type === "log") { + fire_event({ + type: "log", + title: data.title, + log: data.log, + level: data.level, + endpoint: _endpoint, + duration: data.duration, + visible: data.visible, + fn_index + }); + } else if (type === "generating") { + fire_event({ + type: "status", + time: new Date(), + ...status, + stage: status?.stage!, + queue: true, + endpoint: _endpoint, + fn_index + }); + } + if (data) { + fire_event({ + type: "data", + time: new Date(), + data: handle_payload( + data.data, + dependency, + config.components, + "output", + options.with_null_state + ), + endpoint: _endpoint, + fn_index, + event_data, + trigger_id + }); + + if (complete) { + fire_event({ + type: "status", + time: new Date(), + ...complete, + stage: status?.stage!, + queue: true, + endpoint: _endpoint, + fn_index + }); + websocket.close(); + } + } + }; + + // different ws contract for gradio versions older than 3.6.0 + //@ts-ignore + if (semiver(config.version || "2.0.0", "3.6") < 0) { + addEventListener("open", () => + websocket.send(JSON.stringify({ hash: session_hash })) + ); + } + } else if (protocol == "sse") { + fire_event({ + type: "status", + stage: "pending", + queue: true, + endpoint: _endpoint, + fn_index, + time: new Date() + }); + var params = new URLSearchParams({ + fn_index: fn_index.toString(), + session_hash: session_hash + }).toString(); + let url = new URL( + `${config.root}${api_prefix}/${SSE_URL}?${ + url_params ? url_params + "&" : "" + }${params}` + ); + + if (this.jwt) { + url.searchParams.set("__sign", this.jwt); + } + + stream = this.stream(url); + + if (!stream) { + return Promise.reject( + new Error("Cannot connect to SSE endpoint: " + url.toString()) + ); + } + + stream.onmessage = async function (event: MessageEvent) { + const _data = JSON.parse(event.data); + const { type, status, data } = handle_message( + _data, + last_status[fn_index] + ); + + if (type === "update" && status && !complete) { + // call 'status' listeners + fire_event({ + type: "status", + endpoint: _endpoint, + fn_index, + time: new Date(), + ...status + }); + if (status.stage === "error") { + stream?.close(); + close(); + } + } else if (type === "data") { + let [_, status] = await post_data( + `${config.root}${api_prefix}/queue/data`, + { + ...payload, + session_hash, + event_id + } + ); + if (status !== 200) { + fire_event({ + type: "status", + stage: "error", + message: BROKEN_CONNECTION_MSG, + queue: true, + endpoint: _endpoint, + fn_index, + time: new Date() + }); + stream?.close(); + close(); + } + } else if (type === "complete") { + complete = status; + } else if (type === "log") { + fire_event({ + type: "log", + title: data.title, + log: data.log, + level: data.level, + endpoint: _endpoint, + duration: data.duration, + visible: data.visible, + fn_index + }); + } else if (type === "generating" || type === "streaming") { + fire_event({ + type: "status", + time: new Date(), + ...status, + stage: status?.stage!, + queue: true, + endpoint: _endpoint, + fn_index + }); + } + if (data) { + fire_event({ + type: "data", + time: new Date(), + data: handle_payload( + data.data, + dependency, + config.components, + "output", + options.with_null_state + ), + endpoint: _endpoint, + fn_index, + event_data, + trigger_id + }); + + if (complete) { + fire_event({ + type: "status", + time: new Date(), + ...complete, + stage: status?.stage!, + queue: true, + endpoint: _endpoint, + fn_index + }); + stream?.close(); + close(); + } + } + }; + } else if ( + protocol == "sse_v1" || + protocol == "sse_v2" || + protocol == "sse_v2.1" || + protocol == "sse_v3" + ) { + // latest API format. v2 introduces sending diffs for intermediate outputs in generative functions, which makes payloads lighter. + // v3 only closes the stream when the backend sends the close stream message. + fire_event({ + type: "status", + stage: "pending", + queue: true, + endpoint: _endpoint, + fn_index, + time: new Date() + }); + let hostname = ""; + if ( + typeof window !== "undefined" && + typeof document !== "undefined" + ) { + hostname = window?.location?.hostname; + } + + let hfhubdev = "dev.spaces.huggingface.tech"; + const origin = hostname.includes(".dev.") + ? `https://moon-${hostname.split(".")[1]}.${hfhubdev}` + : `https://huggingface.co`; + + const is_zerogpu_iframe = + typeof window !== "undefined" && + typeof document !== "undefined" && + window.parent != window && + window.supports_zerogpu_headers; + const zerogpu_auth_promise = is_zerogpu_iframe + ? post_message>("zerogpu-headers", origin) + : Promise.resolve(null); + const post_data_promise = zerogpu_auth_promise.then((headers) => { + return post_data( + `${config.root}${api_prefix}/${SSE_DATA_URL}?${url_params}`, + { + ...payload, + session_hash + }, + headers + ); + }); + post_data_promise.then(async ([response, status]: any) => { + if (status === 503) { + fire_event({ + type: "status", + stage: "error", + message: QUEUE_FULL_MSG, + queue: true, + endpoint: _endpoint, + fn_index, + time: new Date() + }); + } else if (status !== 200) { + fire_event({ + type: "status", + stage: "error", + message: BROKEN_CONNECTION_MSG, + queue: true, + endpoint: _endpoint, + fn_index, + time: new Date() + }); + } else { + event_id = response.event_id as string; + event_id_final = event_id; + let callback = async function (_data: object): Promise { + try { + const { type, status, data, original_msg } = handle_message( + _data, + last_status[fn_index] + ); + + if (type == "heartbeat") { + return; + } + + if (type === "update" && status && !complete) { + // call 'status' listeners + fire_event({ + type: "status", + endpoint: _endpoint, + fn_index, + time: new Date(), + original_msg: original_msg, + ...status + }); + } else if (type === "complete") { + complete = status; + } else if (type == "unexpected_error") { + console.error("Unexpected error", status?.message); + fire_event({ + type: "status", + stage: "error", + message: + status?.message || "An Unexpected Error Occurred!", + queue: true, + endpoint: _endpoint, + fn_index, + time: new Date() + }); + } else if (type === "log") { + fire_event({ + type: "log", + title: data.title, + log: data.log, + level: data.level, + endpoint: _endpoint, + duration: data.duration, + visible: data.visible, + fn_index + }); + return; + } else if (type === "generating" || type === "streaming") { + fire_event({ + type: "status", + time: new Date(), + ...status, + stage: status?.stage!, + queue: true, + endpoint: _endpoint, + fn_index + }); + if ( + data && + dependency.connection !== "stream" && + ["sse_v2", "sse_v2.1", "sse_v3"].includes(protocol) + ) { + apply_diff_stream(pending_diff_streams, event_id!, data); + } + } + if (data) { + fire_event({ + type: "data", + time: new Date(), + data: handle_payload( + data.data, + dependency, + config.components, + "output", + options.with_null_state + ), + endpoint: _endpoint, + fn_index + }); + if (data.render_config) { + await handle_render_config(data.render_config); + } + + if (complete) { + fire_event({ + type: "status", + time: new Date(), + ...complete, + stage: status?.stage!, + queue: true, + endpoint: _endpoint, + fn_index + }); + + close(); + } + } + + if ( + status?.stage === "complete" || + status?.stage === "error" + ) { + if (event_callbacks[event_id!]) { + delete event_callbacks[event_id!]; + } + if (event_id! in pending_diff_streams) { + delete pending_diff_streams[event_id!]; + } + } + } catch (e) { + console.error("Unexpected client exception", e); + fire_event({ + type: "status", + stage: "error", + message: "An Unexpected Error Occurred!", + queue: true, + endpoint: _endpoint, + fn_index, + time: new Date() + }); + if (["sse_v2", "sse_v2.1", "sse_v3"].includes(protocol)) { + close_stream(stream_status, that.abort_controller); + stream_status.open = false; + close(); + } + } + }; + + if (event_id in pending_stream_messages) { + pending_stream_messages[event_id].forEach((msg) => + callback(msg) + ); + delete pending_stream_messages[event_id]; + } + // @ts-ignore + event_callbacks[event_id] = callback; + unclosed_events.add(event_id); + if (!stream_status.open) { + await this.open_stream(); + } + } + }); + } + } + ); + + let done = false; + const values: (IteratorResult | PromiseLike)[] = []; + const resolvers: (( + value: IteratorResult | PromiseLike + ) => void)[] = []; + + function close(): void { + done = true; + while (resolvers.length > 0) + (resolvers.shift() as (typeof resolvers)[0])({ + value: undefined, + done: true + }); + } + + function push( + data: { value: GradioEvent; done: boolean } | PromiseLike + ): void { + if (done) return; + if (resolvers.length > 0) { + (resolvers.shift() as (typeof resolvers)[0])(data); + } else { + values.push(data); + } + } + + function push_error(error: unknown): void { + push(thenable_reject(error)); + close(); + } + + function push_event(event: GradioEvent): void { + push({ value: event, done: false }); + } + + function next(): Promise> { + if (values.length > 0) + return Promise.resolve(values.shift() as (typeof values)[0]); + if (done) return Promise.resolve({ value: undefined, done: true }); + return new Promise((resolve) => resolvers.push(resolve)); + } + + const iterator = { + [Symbol.asyncIterator]: () => iterator, + next, + throw: async (value: unknown) => { + push_error(value); + return next(); + }, + return: async () => { + close(); + return next(); + }, + cancel, + event_id: event_id_cb + }; + + return iterator; + } catch (error) { + console.error("Submit function encountered an error:", error); + throw error; + } +} + +function thenable_reject(error: T): PromiseLike { + return { + then: ( + resolve: (value: never) => PromiseLike, + reject: (error: T) => PromiseLike + ) => reject(error) + }; +} + +function get_endpoint_info( + api_info: ApiInfo, + endpoint: string | number, + api_map: Record, + config: Config +): { + fn_index: number; + endpoint_info: EndpointInfo; + dependency: Dependency; +} { + let fn_index: number; + let endpoint_info: EndpointInfo; + let dependency: Dependency; + + if (typeof endpoint === "number") { + fn_index = endpoint; + endpoint_info = api_info.unnamed_endpoints[fn_index]; + dependency = config.dependencies.find((dep) => dep.id == endpoint)!; + } else { + const trimmed_endpoint = endpoint.replace(/^\//, ""); + + fn_index = api_map[trimmed_endpoint]; + endpoint_info = api_info.named_endpoints[endpoint.trim()]; + dependency = config.dependencies.find( + (dep) => dep.id == api_map[trimmed_endpoint] + )!; + } + + if (typeof fn_index !== "number") { + throw new Error( + "There is no endpoint matching that name of fn_index matching that number." + ); + } + return { fn_index, endpoint_info, dependency }; +} diff --git a/node_modules/@gradio/client/src/utils/upload_files.ts b/node_modules/@gradio/client/src/utils/upload_files.ts new file mode 100644 index 0000000000000000000000000000000000000000..6babe212bd4943013e93341e8ede61493f4978d3 --- /dev/null +++ b/node_modules/@gradio/client/src/utils/upload_files.ts @@ -0,0 +1,52 @@ +import type { Client } from ".."; +import { BROKEN_CONNECTION_MSG, UPLOAD_URL } from "../constants"; +import type { UploadResponse } from "../types"; + +export async function upload_files( + this: Client, + root_url: string, + files: (Blob | File)[], + upload_id?: string +): Promise { + const headers: { + Authorization?: string; + } = {}; + if (this?.options?.hf_token) { + headers.Authorization = `Bearer ${this.options.hf_token}`; + } + + const chunkSize = 1000; + const uploadResponses = []; + let response: Response; + + for (let i = 0; i < files.length; i += chunkSize) { + const chunk = files.slice(i, i + chunkSize); + const formData = new FormData(); + chunk.forEach((file) => { + formData.append("files", file); + }); + try { + const upload_url = upload_id + ? `${root_url}${this.api_prefix}/${UPLOAD_URL}?upload_id=${upload_id}` + : `${root_url}${this.api_prefix}/${UPLOAD_URL}`; + + response = await this.fetch(upload_url, { + method: "POST", + body: formData, + headers, + credentials: "include" + }); + } catch (e) { + throw new Error(BROKEN_CONNECTION_MSG + (e as Error).message); + } + if (!response.ok) { + const error_text = await response.text(); + return { error: `HTTP ${response.status}: ${error_text}` }; + } + const output: UploadResponse["files"] = await response.json(); + if (output) { + uploadResponses.push(...output); + } + } + return { files: uploadResponses }; +} diff --git a/node_modules/@gradio/client/src/utils/view_api.ts b/node_modules/@gradio/client/src/utils/view_api.ts new file mode 100644 index 0000000000000000000000000000000000000000..592c95dd9473b7bfde4d4dfeec50dc21951dd43a --- /dev/null +++ b/node_modules/@gradio/client/src/utils/view_api.ts @@ -0,0 +1,71 @@ +import type { ApiInfo, ApiData } from "../types"; +import semiver from "semiver"; +import { API_INFO_URL, BROKEN_CONNECTION_MSG } from "../constants"; +import { Client } from "../client"; +import { SPACE_FETCHER_URL } from "../constants"; +import { join_urls, transform_api_info } from "../helpers/api_info"; + +export async function view_api(this: Client): Promise { + if (this.api_info) return this.api_info; + + const { hf_token } = this.options; + const { config } = this; + + const headers: { + Authorization?: string; + "Content-Type": "application/json"; + } = { "Content-Type": "application/json" }; + + if (hf_token) { + headers.Authorization = `Bearer ${hf_token}`; + } + + if (!config) { + return; + } + + try { + let response: Response; + let api_info: ApiInfo | { api: ApiInfo }; + if (typeof window !== "undefined" && window.gradio_api_info) { + api_info = window.gradio_api_info; + } else { + if (semiver(config?.version || "2.0.0", "3.30") < 0) { + response = await this.fetch(SPACE_FETCHER_URL, { + method: "POST", + body: JSON.stringify({ + serialize: false, + config: JSON.stringify(config) + }), + headers, + credentials: "include" + }); + } else { + const url = join_urls(config.root, this.api_prefix, API_INFO_URL); + response = await this.fetch(url, { + headers, + credentials: "include" + }); + } + + if (!response.ok) { + throw new Error(BROKEN_CONNECTION_MSG); + } + api_info = await response.json(); + } + if ("api" in api_info) { + api_info = api_info.api; + } + + if ( + api_info.named_endpoints["/predict"] && + !api_info.unnamed_endpoints["0"] + ) { + api_info.unnamed_endpoints[0] = api_info.named_endpoints["/predict"]; + } + + return transform_api_info(api_info, config, this.api_map); + } catch (e) { + throw new Error("Could not get API info. " + (e as Error).message); + } +} diff --git a/node_modules/@gradio/client/src/vite-env.d.ts b/node_modules/@gradio/client/src/vite-env.d.ts new file mode 100644 index 0000000000000000000000000000000000000000..11f02fe2a0061d6e6e1f271b21da95423b448b32 --- /dev/null +++ b/node_modules/@gradio/client/src/vite-env.d.ts @@ -0,0 +1 @@ +/// diff --git a/node_modules/@gradio/client/tsconfig.json b/node_modules/@gradio/client/tsconfig.json new file mode 100644 index 0000000000000000000000000000000000000000..541ef0cb9d7eabe46d83d046ea2006ce97672c6b --- /dev/null +++ b/node_modules/@gradio/client/tsconfig.json @@ -0,0 +1,27 @@ +{ + "include": ["src/**/*"], + "exclude": ["src/**/*.test.ts", "src/**/*.node-test.ts"], + "compilerOptions": { + "allowJs": true, + "declaration": true, + "emitDeclarationOnly": true, + "outDir": "dist", + "declarationMap": true, + "module": "ESNext", + "target": "ES2020", + "useDefineForClassFields": true, + "lib": ["ES2020", "DOM", "DOM.Iterable"], + "skipLibCheck": true, + + /* Bundler */ + "moduleResolution": "Bundler", + "skipDefaultLibCheck": true, + "allowImportingTsExtensions": true, + "esModuleInterop": true, + "resolveJsonModule": true, + "isolatedModules": true, + + /* Linting */ + "strict": true + } +} diff --git a/node_modules/@gradio/client/vite.config.js b/node_modules/@gradio/client/vite.config.js new file mode 100644 index 0000000000000000000000000000000000000000..257b9baded27725aa23acb8164e824635eaed908 --- /dev/null +++ b/node_modules/@gradio/client/vite.config.js @@ -0,0 +1,45 @@ +import { defineConfig } from "vite"; +import { svelte } from "@sveltejs/vite-plugin-svelte"; + +const TEST_MODE = process.env.TEST_MODE || "happy-dom"; + +export default defineConfig(({ mode }) => { + if (mode === "preview") { + return { + entry: "index.html" + }; + } + return { + build: { + lib: { + entry: "src/index.ts", + formats: ["es"], + fileName: (format) => `index.${format}.js` + }, + rollupOptions: { + input: "src/index.ts", + output: { + dir: "dist" + } + } + }, + plugins: [svelte()], + + mode: process.env.MODE || "development", + test: { + include: ["./src/test/*.test.*"], + environment: TEST_MODE + }, + ssr: { + target: "node", + format: "esm", + noExternal: [ + "ws", + "semiver", + "bufferutil", + "@gradio/upload", + "fetch-event-stream" + ] + } + }; +}); diff --git a/node_modules/@inquirer/confirm/LICENSE b/node_modules/@inquirer/confirm/LICENSE new file mode 100644 index 0000000000000000000000000000000000000000..f7186988726152b8dfb1bbafe940a712da142e3e --- /dev/null +++ b/node_modules/@inquirer/confirm/LICENSE @@ -0,0 +1,22 @@ +Copyright (c) 2025 Simon Boudrias + +Permission is hereby granted, free of charge, to any person +obtaining a copy of this software and associated documentation +files (the "Software"), to deal in the Software without +restriction, including without limitation the rights to use, +copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. diff --git a/node_modules/@inquirer/confirm/README.md b/node_modules/@inquirer/confirm/README.md new file mode 100644 index 0000000000000000000000000000000000000000..0a259af6f573c25710db24c84e4b40c7b19e1325 --- /dev/null +++ b/node_modules/@inquirer/confirm/README.md @@ -0,0 +1,102 @@ +# `@inquirer/confirm` + +Simple interactive command line prompt to gather boolean input from users. + +![Confirm prompt](https://cdn.rawgit.com/SBoudrias/Inquirer.js/28ae8337ba51d93e359ef4f7ee24e79b69898962/assets/screenshots/confirm.svg) + +# Special Thanks + +
+ +[![Graphite](https://github.com/user-attachments/assets/53db40ca-2254-481a-a094-6597f8716e29)](https://graphite.dev/?utm_source=npmjs&utm_medium=repo&utm_campaign=inquirerjs)
+ +### [Graphite is the AI developer productivity platform helping teams on GitHub ship higher quality software, faster](https://graphite.dev/?utm_source=npmjs&utm_medium=repo&utm_campaign=inquirerjs) + +
+ +# Installation + + + + + + + + + + + + + + + + + +
npmyarn
+ +```sh +npm install @inquirer/prompts +``` + + + +```sh +yarn add @inquirer/prompts +``` + +
Or
+ +```sh +npm install @inquirer/confirm +``` + + + +```sh +yarn add @inquirer/confirm +``` + +
+ +# Usage + +```js +import { confirm } from '@inquirer/prompts'; +// Or +// import confirm from '@inquirer/confirm'; + +const answer = await confirm({ message: 'Continue?' }); +``` + +## Options + +| Property | Type | Required | Description | +| ----------- | ----------------------- | -------- | ------------------------------------------------------- | +| message | `string` | yes | The question to ask | +| default | `boolean` | no | Default answer (true or false) | +| transformer | `(boolean) => string` | no | Transform the prompt printed message to a custom string | +| theme | [See Theming](#Theming) | no | Customize look of the prompt. | + +## Theming + +You can theme a prompt by passing a `theme` object option. The theme object only need to includes the keys you wish to modify, we'll fallback on the defaults for the rest. + +```ts +type Theme = { + prefix: string | { idle: string; done: string }; + spinner: { + interval: number; + frames: string[]; + }; + style: { + answer: (text: string) => string; + message: (text: string, status: 'idle' | 'done' | 'loading') => string; + defaultAnswer: (text: string) => string; + }; +}; +``` + +# License + +Copyright (c) 2023 Simon Boudrias (twitter: [@vaxilart](https://twitter.com/Vaxilart))
+Licensed under the MIT license. diff --git a/node_modules/@inquirer/confirm/dist/commonjs/index.d.ts b/node_modules/@inquirer/confirm/dist/commonjs/index.d.ts new file mode 100644 index 0000000000000000000000000000000000000000..d3d323add1e962e96e7547ceaae4d3208ef92360 --- /dev/null +++ b/node_modules/@inquirer/confirm/dist/commonjs/index.d.ts @@ -0,0 +1,10 @@ +import { type Theme } from '@inquirer/core'; +import type { PartialDeep } from '@inquirer/type'; +type ConfirmConfig = { + message: string; + default?: boolean; + transformer?: (value: boolean) => string; + theme?: PartialDeep; +}; +declare const _default: import("@inquirer/type").Prompt; +export default _default; diff --git a/node_modules/@inquirer/confirm/dist/commonjs/index.js b/node_modules/@inquirer/confirm/dist/commonjs/index.js new file mode 100644 index 0000000000000000000000000000000000000000..f4b51f12af7c484e2a424814747d3f2d5f93d3d5 --- /dev/null +++ b/node_modules/@inquirer/confirm/dist/commonjs/index.js @@ -0,0 +1,48 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +const core_1 = require("@inquirer/core"); +function getBooleanValue(value, defaultValue) { + let answer = defaultValue !== false; + if (/^(y|yes)/i.test(value)) + answer = true; + else if (/^(n|no)/i.test(value)) + answer = false; + return answer; +} +function boolToString(value) { + return value ? 'Yes' : 'No'; +} +exports.default = (0, core_1.createPrompt)((config, done) => { + const { transformer = boolToString } = config; + const [status, setStatus] = (0, core_1.useState)('idle'); + const [value, setValue] = (0, core_1.useState)(''); + const theme = (0, core_1.makeTheme)(config.theme); + const prefix = (0, core_1.usePrefix)({ status, theme }); + (0, core_1.useKeypress)((key, rl) => { + if ((0, core_1.isEnterKey)(key)) { + const answer = getBooleanValue(value, config.default); + setValue(transformer(answer)); + setStatus('done'); + done(answer); + } + else if (key.name === 'tab') { + const answer = boolToString(!getBooleanValue(value, config.default)); + rl.clearLine(0); // Remove the tab character. + rl.write(answer); + setValue(answer); + } + else { + setValue(rl.line); + } + }); + let formattedValue = value; + let defaultValue = ''; + if (status === 'done') { + formattedValue = theme.style.answer(value); + } + else { + defaultValue = ` ${theme.style.defaultAnswer(config.default === false ? 'y/N' : 'Y/n')}`; + } + const message = theme.style.message(config.message, status); + return `${prefix} ${message}${defaultValue} ${formattedValue}`; +}); diff --git a/node_modules/@inquirer/confirm/dist/commonjs/package.json b/node_modules/@inquirer/confirm/dist/commonjs/package.json new file mode 100644 index 0000000000000000000000000000000000000000..5bbefffbabee392d1855491b84dc0a716b6a3bf2 --- /dev/null +++ b/node_modules/@inquirer/confirm/dist/commonjs/package.json @@ -0,0 +1,3 @@ +{ + "type": "commonjs" +} diff --git a/node_modules/@inquirer/confirm/dist/esm/index.d.ts b/node_modules/@inquirer/confirm/dist/esm/index.d.ts new file mode 100644 index 0000000000000000000000000000000000000000..d3d323add1e962e96e7547ceaae4d3208ef92360 --- /dev/null +++ b/node_modules/@inquirer/confirm/dist/esm/index.d.ts @@ -0,0 +1,10 @@ +import { type Theme } from '@inquirer/core'; +import type { PartialDeep } from '@inquirer/type'; +type ConfirmConfig = { + message: string; + default?: boolean; + transformer?: (value: boolean) => string; + theme?: PartialDeep; +}; +declare const _default: import("@inquirer/type").Prompt; +export default _default; diff --git a/node_modules/@inquirer/confirm/dist/esm/index.js b/node_modules/@inquirer/confirm/dist/esm/index.js new file mode 100644 index 0000000000000000000000000000000000000000..970c2b65d08a191a11d9a55b18a160052ae15aef --- /dev/null +++ b/node_modules/@inquirer/confirm/dist/esm/index.js @@ -0,0 +1,46 @@ +import { createPrompt, useState, useKeypress, isEnterKey, usePrefix, makeTheme, } from '@inquirer/core'; +function getBooleanValue(value, defaultValue) { + let answer = defaultValue !== false; + if (/^(y|yes)/i.test(value)) + answer = true; + else if (/^(n|no)/i.test(value)) + answer = false; + return answer; +} +function boolToString(value) { + return value ? 'Yes' : 'No'; +} +export default createPrompt((config, done) => { + const { transformer = boolToString } = config; + const [status, setStatus] = useState('idle'); + const [value, setValue] = useState(''); + const theme = makeTheme(config.theme); + const prefix = usePrefix({ status, theme }); + useKeypress((key, rl) => { + if (isEnterKey(key)) { + const answer = getBooleanValue(value, config.default); + setValue(transformer(answer)); + setStatus('done'); + done(answer); + } + else if (key.name === 'tab') { + const answer = boolToString(!getBooleanValue(value, config.default)); + rl.clearLine(0); // Remove the tab character. + rl.write(answer); + setValue(answer); + } + else { + setValue(rl.line); + } + }); + let formattedValue = value; + let defaultValue = ''; + if (status === 'done') { + formattedValue = theme.style.answer(value); + } + else { + defaultValue = ` ${theme.style.defaultAnswer(config.default === false ? 'y/N' : 'Y/n')}`; + } + const message = theme.style.message(config.message, status); + return `${prefix} ${message}${defaultValue} ${formattedValue}`; +}); diff --git a/node_modules/@inquirer/confirm/dist/esm/package.json b/node_modules/@inquirer/confirm/dist/esm/package.json new file mode 100644 index 0000000000000000000000000000000000000000..3dbc1ca591c0557e35b6004aeba250e6a70b56e3 --- /dev/null +++ b/node_modules/@inquirer/confirm/dist/esm/package.json @@ -0,0 +1,3 @@ +{ + "type": "module" +} diff --git a/node_modules/@inquirer/confirm/package.json b/node_modules/@inquirer/confirm/package.json new file mode 100644 index 0000000000000000000000000000000000000000..8cb1cc3c100b7ed7dead567f7a3e4d2b750150a7 --- /dev/null +++ b/node_modules/@inquirer/confirm/package.json @@ -0,0 +1,110 @@ +{ + "name": "@inquirer/confirm", + "version": "5.1.9", + "description": "Inquirer confirm prompt", + "keywords": [ + "answer", + "answers", + "ask", + "base", + "cli", + "command", + "command-line", + "confirm", + "enquirer", + "generate", + "generator", + "hyper", + "input", + "inquire", + "inquirer", + "interface", + "iterm", + "javascript", + "menu", + "node", + "nodejs", + "prompt", + "promptly", + "prompts", + "question", + "readline", + "scaffold", + "scaffolder", + "scaffolding", + "stdin", + "stdout", + "terminal", + "tty", + "ui", + "yeoman", + "yo", + "zsh" + ], + "homepage": "https://github.com/SBoudrias/Inquirer.js/blob/main/packages/confirm/README.md", + "repository": { + "type": "git", + "url": "https://github.com/SBoudrias/Inquirer.js.git" + }, + "license": "MIT", + "author": "Simon Boudrias ", + "sideEffects": false, + "type": "module", + "exports": { + "./package.json": "./package.json", + ".": { + "import": { + "types": "./dist/esm/index.d.ts", + "default": "./dist/esm/index.js" + }, + "require": { + "types": "./dist/commonjs/index.d.ts", + "default": "./dist/commonjs/index.js" + } + } + }, + "main": "./dist/commonjs/index.js", + "module": "./dist/esm/index.js", + "types": "./dist/commonjs/index.d.ts", + "files": [ + "dist" + ], + "scripts": { + "attw": "attw --pack", + "tsc": "tshy" + }, + "dependencies": { + "@inquirer/core": "^10.1.10", + "@inquirer/type": "^3.0.6" + }, + "devDependencies": { + "@arethetypeswrong/cli": "^0.17.4", + "@inquirer/testing": "^2.1.46", + "@repo/tsconfig": "workspace:*", + "tshy": "^3.0.2" + }, + "engines": { + "node": ">=18" + }, + "publishConfig": { + "access": "public" + }, + "tshy": { + "exclude": [ + "src/**/*.test.ts" + ], + "exports": { + "./package.json": "./package.json", + ".": "./src/index.ts" + } + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + }, + "gitHead": "d367155a8d64d8b3e93f9c763adccf708aedc8a8" +} diff --git a/node_modules/@inquirer/core/LICENSE b/node_modules/@inquirer/core/LICENSE new file mode 100644 index 0000000000000000000000000000000000000000..f7186988726152b8dfb1bbafe940a712da142e3e --- /dev/null +++ b/node_modules/@inquirer/core/LICENSE @@ -0,0 +1,22 @@ +Copyright (c) 2025 Simon Boudrias + +Permission is hereby granted, free of charge, to any person +obtaining a copy of this software and associated documentation +files (the "Software"), to deal in the Software without +restriction, including without limitation the rights to use, +copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. diff --git a/node_modules/@inquirer/core/README.md b/node_modules/@inquirer/core/README.md new file mode 100644 index 0000000000000000000000000000000000000000..6f72b0f04666012a5bff6abcc4e7b9fa24d61d35 --- /dev/null +++ b/node_modules/@inquirer/core/README.md @@ -0,0 +1,393 @@ +# `@inquirer/core` + +The `@inquirer/core` package is the library enabling the creation of Inquirer prompts. + +It aims to implements a lightweight API similar to React hooks - but without JSX. + +# Special Thanks + +
+ +[![Graphite](https://github.com/user-attachments/assets/53db40ca-2254-481a-a094-6597f8716e29)](https://graphite.dev/?utm_source=npmjs&utm_medium=repo&utm_campaign=inquirerjs)
+ +### [Graphite is the AI developer productivity platform helping teams on GitHub ship higher quality software, faster](https://graphite.dev/?utm_source=npmjs&utm_medium=repo&utm_campaign=inquirerjs) + +
+ +# Installation + + + + + + + + + + +
npmyarn
+ +```sh +npm install @inquirer/core +``` + + + +```sh +yarn add @inquirer/core +``` + +
+ +# Usage + +## Basic concept + +Visual terminal apps are at their core strings rendered onto the terminal. + +The most basic prompt is a function returning a string that'll be rendered in the terminal. This function will run every time the prompt state change, and the new returned string will replace the previously rendered one. The prompt cursor appears after the string. + +Wrapping the rendering function with `createPrompt()` will setup the rendering layer, inject the state management utilities, and wait until the `done` callback is called. + +```ts +import { createPrompt } from '@inquirer/core'; + +const input = createPrompt((config, done) => { + // Implement logic + + return '? My question'; +}); + +// And it is then called as +const answer = await input({ + /* config */ +}); +``` + +## Hooks + +State management and user interactions are handled through hooks. Hooks are common [within the React ecosystem](https://react.dev/reference/react/hooks), and Inquirer reimplement the common ones. + +### State hook + +State lets a component “remember” information like user input. For example, an input prompt can use state to store the input value, while a list prompt can use state to track the cursor index. + +`useState` declares a state variable that you can update directly. + +```ts +import { createPrompt, useState } from '@inquirer/core'; + +const input = createPrompt((config, done) => { + const [index, setIndex] = useState(0); + + // ... +``` + +### Keypress hook + +Almost all prompts need to react to user actions. In a terminal, this is done through typing. + +`useKeypress` allows you to react to keypress events, and access the prompt line. + +```ts +const input = createPrompt((config, done) => { + useKeypress((key) => { + if (key.name === 'enter') { + done(answer); + } + }); + + // ... +``` + +Behind the scenes, Inquirer prompts are wrappers around [readlines](https://nodejs.org/api/readline.html). Aside the keypress event object, the hook also pass the active readline instance to the event handler. + +```ts +const input = createPrompt((config, done) => { + useKeypress((key, readline) => { + setValue(readline.line); + }); + + // ... +``` + +### Ref hook + +Refs let a prompt hold some information that isn’t used for rendering, like a class instance or a timeout ID. Unlike with state, updating a ref does not re-render your prompt. Refs are an “escape hatch” from the rendering paradigm. + +`useRef` declares a ref. You can hold any value in it, but most often it’s used to hold a timeout ID. + +```ts +const input = createPrompt((config, done) => { + const timeout = useRef(null); + + // ... +``` + +### Effect Hook + +Effects let a prompt connect to and synchronize with external systems. This includes dealing with network or animations. + +`useEffect` connects a component to an external system. + +```ts +const chat = createPrompt((config, done) => { + useEffect(() => { + const connection = createConnection(roomId); + connection.connect(); + return () => connection.disconnect(); + }, [roomId]); + + // ... +``` + +### Performance hook + +A common way to optimize re-rendering performance is to skip unnecessary work. For example, you can tell Inquirer to reuse a cached calculation or to skip a re-render if the data has not changed since the previous render. + +`useMemo` lets you cache the result of an expensive calculation. + +```ts +const todoSelect = createPrompt((config, done) => { + const visibleTodos = useMemo(() => filterTodos(todos, tab), [todos, tab]); + + // ... +``` + +### Rendering hooks + +#### Prefix / loading + +All default prompts, and most custom ones, uses a prefix at the beginning of the prompt line. This helps visually delineate different questions, and provides a convenient area to render a loading spinner. + +`usePrefix` is a built-in hook to do this. + +```ts +const input = createPrompt((config, done) => { + const prefix = usePrefix({ status }); + + return `${prefix} My question`; +}); +``` + +#### Pagination + +When looping through a long list of options (like in the `select` prompt), paginating the results appearing on the screen at once can be necessary. The `usePagination` hook is the utility used within the `select` and `checkbox` prompts to cycle through the list of options. + +Pagination works by taking in the list of options and returning a subset of the rendered items that fit within the page. The hook takes in a few options. It needs a list of options (`items`), and a `pageSize` which is the number of lines to be rendered. The `active` index is the index of the currently selected/selectable item. The `loop` option is a boolean that indicates if the list should loop around when reaching the end: this is the default behavior. The pagination hook renders items only as necessary, so it takes a function that can render an item at an index, including an `active` state, called `renderItem`. + +```js +export default createPrompt((config, done) => { + const [active, setActive] = useState(0); + + const allChoices = config.choices.map((choice) => choice.name); + + const page = usePagination({ + items: allChoices, + active: active, + renderItem: ({ item, index, isActive }) => `${isActive ? ">" : " "}${index}. ${item.toString()}` + pageSize: config.pageSize, + loop: config.loop, + }); + + return `... ${page}`; +}); +``` + +## `createPrompt()` API + +As we saw earlier, the rendering function should return a string, and eventually call `done` to close the prompt and return the answer. + +```ts +const input = createPrompt((config, done) => { + const [value, setValue] = useState(); + + useKeypress((key, readline) => { + if (key.name === 'enter') { + done(answer); + } else { + setValue(readline.line); + } + }); + + return `? ${config.message} ${value}`; +}); +``` + +The rendering function can also return a tuple of 2 string (`[string, string]`.) The first string represents the prompt. The second one is content to render under the prompt, like an error message. The text input cursor will appear after the first string. + +```ts +const number = createPrompt((config, done) => { + // Add some logic here + + return [`? My question ${input}`, `! The input must be a number`]; +}); +``` + +### Typescript + +If using typescript, `createPrompt` takes 2 generic arguments. + +```ts +// createPrompt +const input = createPrompt(// ... +``` + +The first one is the type of the resolved value + +```ts +const answer: string = await input(); +``` + +The second one is the type of the prompt config; in other words the interface the created prompt will provide to users. + +```ts +const answer = await input({ + message: 'My question', +}); +``` + +## Key utilities + +Listening for keypress events inside an inquirer prompt is a very common pattern. To ease this, we export a few utility functions taking in the keypress event object and return a boolean: + +- `isEnterKey()` +- `isBackspaceKey()` +- `isSpaceKey()` +- `isUpKey()` - Note: this utility will handle vim and emacs keybindings (up, `k`, and `ctrl+p`) +- `isDownKey()` - Note: this utility will handle vim and emacs keybindings (down, `j`, and `ctrl+n`) +- `isNumberKey()` one of 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 + +## Theming + +Theming utilities will allow you to expose customization of the prompt style. Inquirer also has a few standard theme values shared across all the official prompts. + +To allow standard customization: + +```ts +import { createPrompt, usePrefix, makeTheme, type Theme } from '@inquirer/core'; +import type { PartialDeep } from '@inquirer/type'; + +type PromptConfig = { + theme?: PartialDeep; +}; + +export default createPrompt((config, done) => { + const theme = makeTheme(config.theme); + + const prefix = usePrefix({ status, theme }); + + return `${prefix} ${theme.style.highlight('hello')}`; +}); +``` + +To setup a custom theme: + +```ts +import { createPrompt, makeTheme, type Theme } from '@inquirer/core'; +import type { PartialDeep } from '@inquirer/type'; + +type PromptTheme = {}; + +const promptTheme: PromptTheme = { + icon: '!', +}; + +type PromptConfig = { + theme?: PartialDeep>; +}; + +export default createPrompt((config, done) => { + const theme = makeTheme(promptTheme, config.theme); + + const prefix = usePrefix({ status, theme }); + + return `${prefix} ${theme.icon}`; +}); +``` + +The [default theme keys cover](https://github.com/SBoudrias/Inquirer.js/blob/main/packages/core/src/lib/theme.ts): + +```ts +type DefaultTheme = { + prefix: string | { idle: string; done: string }; + spinner: { + interval: number; + frames: string[]; + }; + style: { + answer: (text: string) => string; + message: (text: string, status: 'idle' | 'done' | 'loading') => string; + error: (text: string) => string; + defaultAnswer: (text: string) => string; + help: (text: string) => string; + highlight: (text: string) => string; + key: (text: string) => string; + }; +}; +``` + +# Examples + +You can refer to any `@inquirer/prompts` prompts for real examples: + +- [Confirm Prompt](https://github.com/SBoudrias/Inquirer.js/blob/main/packages/confirm/src/index.ts) +- [Input Prompt](https://github.com/SBoudrias/Inquirer.js/blob/main/packages/input/src/index.ts) +- [Password Prompt](https://github.com/SBoudrias/Inquirer.js/blob/main/packages/password/src/index.ts) +- [Editor Prompt](https://github.com/SBoudrias/Inquirer.js/blob/main/packages/editor/src/index.ts) +- [Select Prompt](https://github.com/SBoudrias/Inquirer.js/blob/main/packages/select/src/index.ts) +- [Checkbox Prompt](https://github.com/SBoudrias/Inquirer.js/blob/main/packages/checkbox/src/index.ts) +- [Rawlist Prompt](https://github.com/SBoudrias/Inquirer.js/blob/main/packages/rawlist/src/index.ts) +- [Expand Prompt](https://github.com/SBoudrias/Inquirer.js/blob/main/packages/expand/src/index.ts) + +```ts +import colors from 'yoctocolors'; +import { + createPrompt, + useState, + useKeypress, + isEnterKey, + usePrefix, + type Status, +} from '@inquirer/core'; + +const confirm = createPrompt( + (config, done) => { + const [status, setStatus] = useState('idle'); + const [value, setValue] = useState(''); + const prefix = usePrefix({}); + + useKeypress((key, rl) => { + if (isEnterKey(key)) { + const answer = value ? /^y(es)?/i.test(value) : config.default !== false; + setValue(answer ? 'yes' : 'no'); + setStatus('done'); + done(answer); + } else { + setValue(rl.line); + } + }); + + let formattedValue = value; + let defaultValue = ''; + if (status === 'done') { + formattedValue = colors.cyan(value); + } else { + defaultValue = colors.dim(config.default === false ? ' (y/N)' : ' (Y/n)'); + } + + const message = colors.bold(config.message); + return `${prefix} ${message}${defaultValue} ${formattedValue}`; + }, +); + +/** + * Which then can be used like this: + */ +const answer = await confirm({ message: 'Do you want to continue?' }); +``` + +# License + +Copyright (c) 2023 Simon Boudrias (twitter: [@vaxilart](https://twitter.com/Vaxilart))
+Licensed under the MIT license. diff --git a/node_modules/@inquirer/core/dist/commonjs/index.d.ts b/node_modules/@inquirer/core/dist/commonjs/index.d.ts new file mode 100644 index 0000000000000000000000000000000000000000..2f285728f6d497acd9ce2561fa2291412146b220 --- /dev/null +++ b/node_modules/@inquirer/core/dist/commonjs/index.d.ts @@ -0,0 +1,13 @@ +export * from './lib/key.ts'; +export * from './lib/errors.ts'; +export { usePrefix } from './lib/use-prefix.ts'; +export { useState } from './lib/use-state.ts'; +export { useEffect } from './lib/use-effect.ts'; +export { useMemo } from './lib/use-memo.ts'; +export { useRef } from './lib/use-ref.ts'; +export { useKeypress } from './lib/use-keypress.ts'; +export { makeTheme } from './lib/make-theme.ts'; +export type { Theme, Status } from './lib/theme.ts'; +export { usePagination } from './lib/pagination/use-pagination.ts'; +export { createPrompt } from './lib/create-prompt.ts'; +export { Separator } from './lib/Separator.ts'; diff --git a/node_modules/@inquirer/core/dist/commonjs/index.js b/node_modules/@inquirer/core/dist/commonjs/index.js new file mode 100644 index 0000000000000000000000000000000000000000..256d5f7861971790168caef8a08e7c6f1cd5555f --- /dev/null +++ b/node_modules/@inquirer/core/dist/commonjs/index.js @@ -0,0 +1,39 @@ +"use strict"; +var __createBinding = (this && this.__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 __exportStar = (this && this.__exportStar) || function(m, exports) { + for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p); +}; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.Separator = exports.createPrompt = exports.usePagination = exports.makeTheme = exports.useKeypress = exports.useRef = exports.useMemo = exports.useEffect = exports.useState = exports.usePrefix = void 0; +__exportStar(require("./lib/key.js"), exports); +__exportStar(require("./lib/errors.js"), exports); +var use_prefix_ts_1 = require("./lib/use-prefix.js"); +Object.defineProperty(exports, "usePrefix", { enumerable: true, get: function () { return use_prefix_ts_1.usePrefix; } }); +var use_state_ts_1 = require("./lib/use-state.js"); +Object.defineProperty(exports, "useState", { enumerable: true, get: function () { return use_state_ts_1.useState; } }); +var use_effect_ts_1 = require("./lib/use-effect.js"); +Object.defineProperty(exports, "useEffect", { enumerable: true, get: function () { return use_effect_ts_1.useEffect; } }); +var use_memo_ts_1 = require("./lib/use-memo.js"); +Object.defineProperty(exports, "useMemo", { enumerable: true, get: function () { return use_memo_ts_1.useMemo; } }); +var use_ref_ts_1 = require("./lib/use-ref.js"); +Object.defineProperty(exports, "useRef", { enumerable: true, get: function () { return use_ref_ts_1.useRef; } }); +var use_keypress_ts_1 = require("./lib/use-keypress.js"); +Object.defineProperty(exports, "useKeypress", { enumerable: true, get: function () { return use_keypress_ts_1.useKeypress; } }); +var make_theme_ts_1 = require("./lib/make-theme.js"); +Object.defineProperty(exports, "makeTheme", { enumerable: true, get: function () { return make_theme_ts_1.makeTheme; } }); +var use_pagination_ts_1 = require("./lib/pagination/use-pagination.js"); +Object.defineProperty(exports, "usePagination", { enumerable: true, get: function () { return use_pagination_ts_1.usePagination; } }); +var create_prompt_ts_1 = require("./lib/create-prompt.js"); +Object.defineProperty(exports, "createPrompt", { enumerable: true, get: function () { return create_prompt_ts_1.createPrompt; } }); +var Separator_ts_1 = require("./lib/Separator.js"); +Object.defineProperty(exports, "Separator", { enumerable: true, get: function () { return Separator_ts_1.Separator; } }); diff --git a/node_modules/@inquirer/core/dist/commonjs/lib/Separator.d.ts b/node_modules/@inquirer/core/dist/commonjs/lib/Separator.d.ts new file mode 100644 index 0000000000000000000000000000000000000000..028355567638da2eac0e8c759ce6a3ce07dd643b --- /dev/null +++ b/node_modules/@inquirer/core/dist/commonjs/lib/Separator.d.ts @@ -0,0 +1,10 @@ +/** + * Separator object + * Used to space/separate choices group + */ +export declare class Separator { + readonly separator: string; + readonly type: string; + constructor(separator?: string); + static isSeparator(choice: unknown): choice is Separator; +} diff --git a/node_modules/@inquirer/core/dist/commonjs/lib/Separator.js b/node_modules/@inquirer/core/dist/commonjs/lib/Separator.js new file mode 100644 index 0000000000000000000000000000000000000000..5f4ab93733791f31b6952b13f8598f9313a02087 --- /dev/null +++ b/node_modules/@inquirer/core/dist/commonjs/lib/Separator.js @@ -0,0 +1,28 @@ +"use strict"; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.Separator = void 0; +const yoctocolors_cjs_1 = __importDefault(require("yoctocolors-cjs")); +const figures_1 = __importDefault(require("@inquirer/figures")); +/** + * Separator object + * Used to space/separate choices group + */ +class Separator { + separator = yoctocolors_cjs_1.default.dim(Array.from({ length: 15 }).join(figures_1.default.line)); + type = 'separator'; + constructor(separator) { + if (separator) { + this.separator = separator; + } + } + static isSeparator(choice) { + return Boolean(choice && + typeof choice === 'object' && + 'type' in choice && + choice.type === 'separator'); + } +} +exports.Separator = Separator; diff --git a/node_modules/@inquirer/core/dist/commonjs/lib/create-prompt.d.ts b/node_modules/@inquirer/core/dist/commonjs/lib/create-prompt.d.ts new file mode 100644 index 0000000000000000000000000000000000000000..4414db45697e4e2d9dc2f0d3894b4891746cb4b3 --- /dev/null +++ b/node_modules/@inquirer/core/dist/commonjs/lib/create-prompt.d.ts @@ -0,0 +1,4 @@ +import { type Prompt, type Prettify } from '@inquirer/type'; +type ViewFunction = (config: Prettify, done: (value: Value) => void) => string | [string, string | undefined]; +export declare function createPrompt(view: ViewFunction): Prompt; +export {}; diff --git a/node_modules/@inquirer/core/dist/commonjs/lib/create-prompt.js b/node_modules/@inquirer/core/dist/commonjs/lib/create-prompt.js new file mode 100644 index 0000000000000000000000000000000000000000..241cab08468af800b8e6593fb0c27868077dee2b --- /dev/null +++ b/node_modules/@inquirer/core/dist/commonjs/lib/create-prompt.js @@ -0,0 +1,149 @@ +"use strict"; +var __createBinding = (this && this.__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 = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { + Object.defineProperty(o, "default", { enumerable: true, value: v }); +}) : function(o, v) { + o["default"] = v; +}); +var __importStar = (this && this.__importStar) || (function () { + var ownKeys = function(o) { + ownKeys = Object.getOwnPropertyNames || function (o) { + var ar = []; + for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; + return ar; + }; + return ownKeys(o); + }; + return function (mod) { + if (mod && mod.__esModule) return mod; + var result = {}; + if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); + __setModuleDefault(result, mod); + return result; + }; +})(); +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.createPrompt = createPrompt; +const readline = __importStar(require("node:readline")); +const node_async_hooks_1 = require("node:async_hooks"); +const mute_stream_1 = __importDefault(require("mute-stream")); +const signal_exit_1 = require("signal-exit"); +const screen_manager_ts_1 = __importDefault(require("./screen-manager.js")); +const promise_polyfill_ts_1 = require("./promise-polyfill.js"); +const hook_engine_ts_1 = require("./hook-engine.js"); +const errors_ts_1 = require("./errors.js"); +function getCallSites() { + const _prepareStackTrace = Error.prepareStackTrace; + let result = []; + try { + Error.prepareStackTrace = (_, callSites) => { + const callSitesWithoutCurrent = callSites.slice(1); + result = callSitesWithoutCurrent; + return callSitesWithoutCurrent; + }; + // eslint-disable-next-line @typescript-eslint/no-unused-expressions, unicorn/error-message + new Error().stack; + } + catch { + // An error will occur if the Node flag --frozen-intrinsics is used. + // https://nodejs.org/api/cli.html#--frozen-intrinsics + return result; + } + Error.prepareStackTrace = _prepareStackTrace; + return result; +} +function createPrompt(view) { + const callSites = getCallSites(); + const prompt = (config, context = {}) => { + // Default `input` to stdin + const { input = process.stdin, signal } = context; + const cleanups = new Set(); + // Add mute capabilities to the output + const output = new mute_stream_1.default(); + output.pipe(context.output ?? process.stdout); + const rl = readline.createInterface({ + terminal: true, + input, + output, + }); + const screen = new screen_manager_ts_1.default(rl); + const { promise, resolve, reject } = promise_polyfill_ts_1.PromisePolyfill.withResolver(); + const cancel = () => reject(new errors_ts_1.CancelPromptError()); + if (signal) { + const abort = () => reject(new errors_ts_1.AbortPromptError({ cause: signal.reason })); + if (signal.aborted) { + abort(); + return Object.assign(promise, { cancel }); + } + signal.addEventListener('abort', abort); + cleanups.add(() => signal.removeEventListener('abort', abort)); + } + cleanups.add((0, signal_exit_1.onExit)((code, signal) => { + reject(new errors_ts_1.ExitPromptError(`User force closed the prompt with ${code} ${signal}`)); + })); + // Re-renders only happen when the state change; but the readline cursor could change position + // and that also requires a re-render (and a manual one because we mute the streams). + // We set the listener after the initial workLoop to avoid a double render if render triggered + // by a state change sets the cursor to the right position. + const checkCursorPos = () => screen.checkCursorPos(); + rl.input.on('keypress', checkCursorPos); + cleanups.add(() => rl.input.removeListener('keypress', checkCursorPos)); + return (0, hook_engine_ts_1.withHooks)(rl, (cycle) => { + // The close event triggers immediately when the user press ctrl+c. SignalExit on the other hand + // triggers after the process is done (which happens after timeouts are done triggering.) + // We triggers the hooks cleanup phase on rl `close` so active timeouts can be cleared. + const hooksCleanup = node_async_hooks_1.AsyncResource.bind(() => hook_engine_ts_1.effectScheduler.clearAll()); + rl.on('close', hooksCleanup); + cleanups.add(() => rl.removeListener('close', hooksCleanup)); + cycle(() => { + try { + const nextView = view(config, (value) => { + setImmediate(() => resolve(value)); + }); + // Typescript won't allow this, but not all users rely on typescript. + // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition + if (nextView === undefined) { + const callerFilename = callSites[1]?.getFileName(); + throw new Error(`Prompt functions must return a string.\n at ${callerFilename}`); + } + const [content, bottomContent] = typeof nextView === 'string' ? [nextView] : nextView; + screen.render(content, bottomContent); + hook_engine_ts_1.effectScheduler.run(); + } + catch (error) { + reject(error); + } + }); + return Object.assign(promise + .then((answer) => { + hook_engine_ts_1.effectScheduler.clearAll(); + return answer; + }, (error) => { + hook_engine_ts_1.effectScheduler.clearAll(); + throw error; + }) + // Wait for the promise to settle, then cleanup. + .finally(() => { + cleanups.forEach((cleanup) => cleanup()); + screen.done({ clearContent: Boolean(context.clearPromptOnDone) }); + output.end(); + }) + // Once cleanup is done, let the expose promise resolve/reject to the internal one. + .then(() => promise), { cancel }); + }); + }; + return prompt; +} diff --git a/node_modules/@inquirer/core/dist/commonjs/lib/errors.d.ts b/node_modules/@inquirer/core/dist/commonjs/lib/errors.d.ts new file mode 100644 index 0000000000000000000000000000000000000000..b9df681e623b3a0798c95080f009ff994e4e7010 --- /dev/null +++ b/node_modules/@inquirer/core/dist/commonjs/lib/errors.d.ts @@ -0,0 +1,20 @@ +export declare class AbortPromptError extends Error { + name: string; + message: string; + constructor(options?: { + cause?: unknown; + }); +} +export declare class CancelPromptError extends Error { + name: string; + message: string; +} +export declare class ExitPromptError extends Error { + name: string; +} +export declare class HookError extends Error { + name: string; +} +export declare class ValidationError extends Error { + name: string; +} diff --git a/node_modules/@inquirer/core/dist/commonjs/lib/errors.js b/node_modules/@inquirer/core/dist/commonjs/lib/errors.js new file mode 100644 index 0000000000000000000000000000000000000000..df3b9749333f6c09d86b85b85d4ba3769c4eecf5 --- /dev/null +++ b/node_modules/@inquirer/core/dist/commonjs/lib/errors.js @@ -0,0 +1,29 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.ValidationError = exports.HookError = exports.ExitPromptError = exports.CancelPromptError = exports.AbortPromptError = void 0; +class AbortPromptError extends Error { + name = 'AbortPromptError'; + message = 'Prompt was aborted'; + constructor(options) { + super(); + this.cause = options?.cause; + } +} +exports.AbortPromptError = AbortPromptError; +class CancelPromptError extends Error { + name = 'CancelPromptError'; + message = 'Prompt was canceled'; +} +exports.CancelPromptError = CancelPromptError; +class ExitPromptError extends Error { + name = 'ExitPromptError'; +} +exports.ExitPromptError = ExitPromptError; +class HookError extends Error { + name = 'HookError'; +} +exports.HookError = HookError; +class ValidationError extends Error { + name = 'ValidationError'; +} +exports.ValidationError = ValidationError; diff --git a/node_modules/@inquirer/core/dist/commonjs/lib/hook-engine.d.ts b/node_modules/@inquirer/core/dist/commonjs/lib/hook-engine.d.ts new file mode 100644 index 0000000000000000000000000000000000000000..c4715a8843bfe2fa80c14b542dc56ee84dc1e250 --- /dev/null +++ b/node_modules/@inquirer/core/dist/commonjs/lib/hook-engine.d.ts @@ -0,0 +1,23 @@ +import type { InquirerReadline } from '@inquirer/type'; +export declare function withHooks(rl: InquirerReadline, cb: (cycle: (render: () => void) => void) => T): T; +export declare function readline(): InquirerReadline; +export declare function withUpdates R>(fn: T): (...args: Parameters) => R; +type SetPointer = { + get(): Value; + set(value: Value): void; + initialized: true; +}; +type UnsetPointer = { + get(): void; + set(value: Value): void; + initialized: false; +}; +type Pointer = SetPointer | UnsetPointer; +export declare function withPointer(cb: (pointer: Pointer) => ReturnValue): ReturnValue; +export declare function handleChange(): void; +export declare const effectScheduler: { + queue(cb: (readline: InquirerReadline) => void | (() => void)): void; + run(): void; + clearAll(): void; +}; +export {}; diff --git a/node_modules/@inquirer/core/dist/commonjs/lib/hook-engine.js b/node_modules/@inquirer/core/dist/commonjs/lib/hook-engine.js new file mode 100644 index 0000000000000000000000000000000000000000..479b91f496bf3344fcbe2fc89565f204c8a8f0b0 --- /dev/null +++ b/node_modules/@inquirer/core/dist/commonjs/lib/hook-engine.js @@ -0,0 +1,118 @@ +"use strict"; +/* eslint @typescript-eslint/no-explicit-any: ["off"] */ +Object.defineProperty(exports, "__esModule", { value: true }); +exports.effectScheduler = void 0; +exports.withHooks = withHooks; +exports.readline = readline; +exports.withUpdates = withUpdates; +exports.withPointer = withPointer; +exports.handleChange = handleChange; +const node_async_hooks_1 = require("node:async_hooks"); +const errors_ts_1 = require("./errors.js"); +const hookStorage = new node_async_hooks_1.AsyncLocalStorage(); +function createStore(rl) { + const store = { + rl, + hooks: [], + hooksCleanup: [], + hooksEffect: [], + index: 0, + handleChange() { }, + }; + return store; +} +// Run callback in with the hook engine setup. +function withHooks(rl, cb) { + const store = createStore(rl); + return hookStorage.run(store, () => { + function cycle(render) { + store.handleChange = () => { + store.index = 0; + render(); + }; + store.handleChange(); + } + return cb(cycle); + }); +} +// Safe getStore utility that'll return the store or throw if undefined. +function getStore() { + const store = hookStorage.getStore(); + if (!store) { + throw new errors_ts_1.HookError('[Inquirer] Hook functions can only be called from within a prompt'); + } + return store; +} +function readline() { + return getStore().rl; +} +// Merge state updates happening within the callback function to avoid multiple renders. +function withUpdates(fn) { + const wrapped = (...args) => { + const store = getStore(); + let shouldUpdate = false; + const oldHandleChange = store.handleChange; + store.handleChange = () => { + shouldUpdate = true; + }; + const returnValue = fn(...args); + if (shouldUpdate) { + oldHandleChange(); + } + store.handleChange = oldHandleChange; + return returnValue; + }; + return node_async_hooks_1.AsyncResource.bind(wrapped); +} +function withPointer(cb) { + const store = getStore(); + const { index } = store; + const pointer = { + get() { + return store.hooks[index]; + }, + set(value) { + store.hooks[index] = value; + }, + initialized: index in store.hooks, + }; + const returnValue = cb(pointer); + store.index++; + return returnValue; +} +function handleChange() { + getStore().handleChange(); +} +exports.effectScheduler = { + queue(cb) { + const store = getStore(); + const { index } = store; + store.hooksEffect.push(() => { + store.hooksCleanup[index]?.(); + const cleanFn = cb(readline()); + if (cleanFn != null && typeof cleanFn !== 'function') { + throw new errors_ts_1.ValidationError('useEffect return value must be a cleanup function or nothing.'); + } + store.hooksCleanup[index] = cleanFn; + }); + }, + run() { + const store = getStore(); + withUpdates(() => { + store.hooksEffect.forEach((effect) => { + effect(); + }); + // Warning: Clean the hooks before exiting the `withUpdates` block. + // Failure to do so means an updates would hit the same effects again. + store.hooksEffect.length = 0; + })(); + }, + clearAll() { + const store = getStore(); + store.hooksCleanup.forEach((cleanFn) => { + cleanFn?.(); + }); + store.hooksEffect.length = 0; + store.hooksCleanup.length = 0; + }, +}; diff --git a/node_modules/@inquirer/core/dist/commonjs/lib/key.d.ts b/node_modules/@inquirer/core/dist/commonjs/lib/key.d.ts new file mode 100644 index 0000000000000000000000000000000000000000..e2ad3dc2aeb8372dd0c900c3408326339ae46045 --- /dev/null +++ b/node_modules/@inquirer/core/dist/commonjs/lib/key.d.ts @@ -0,0 +1,10 @@ +export type KeypressEvent = { + name: string; + ctrl: boolean; +}; +export declare const isUpKey: (key: KeypressEvent) => boolean; +export declare const isDownKey: (key: KeypressEvent) => boolean; +export declare const isSpaceKey: (key: KeypressEvent) => boolean; +export declare const isBackspaceKey: (key: KeypressEvent) => boolean; +export declare const isNumberKey: (key: KeypressEvent) => boolean; +export declare const isEnterKey: (key: KeypressEvent) => boolean; diff --git a/node_modules/@inquirer/core/dist/commonjs/lib/key.js b/node_modules/@inquirer/core/dist/commonjs/lib/key.js new file mode 100644 index 0000000000000000000000000000000000000000..d571f185557d63efa155245020a9c3efa35db8ed --- /dev/null +++ b/node_modules/@inquirer/core/dist/commonjs/lib/key.js @@ -0,0 +1,27 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.isEnterKey = exports.isNumberKey = exports.isBackspaceKey = exports.isSpaceKey = exports.isDownKey = exports.isUpKey = void 0; +const isUpKey = (key) => +// The up key +key.name === 'up' || + // Vim keybinding + key.name === 'k' || + // Emacs keybinding + (key.ctrl && key.name === 'p'); +exports.isUpKey = isUpKey; +const isDownKey = (key) => +// The down key +key.name === 'down' || + // Vim keybinding + key.name === 'j' || + // Emacs keybinding + (key.ctrl && key.name === 'n'); +exports.isDownKey = isDownKey; +const isSpaceKey = (key) => key.name === 'space'; +exports.isSpaceKey = isSpaceKey; +const isBackspaceKey = (key) => key.name === 'backspace'; +exports.isBackspaceKey = isBackspaceKey; +const isNumberKey = (key) => '1234567890'.includes(key.name); +exports.isNumberKey = isNumberKey; +const isEnterKey = (key) => key.name === 'enter' || key.name === 'return'; +exports.isEnterKey = isEnterKey; diff --git a/node_modules/@inquirer/core/dist/commonjs/lib/make-theme.d.ts b/node_modules/@inquirer/core/dist/commonjs/lib/make-theme.d.ts new file mode 100644 index 0000000000000000000000000000000000000000..c7aae8b225c01c27c531617a09cec62ba2c1e4f6 --- /dev/null +++ b/node_modules/@inquirer/core/dist/commonjs/lib/make-theme.d.ts @@ -0,0 +1,3 @@ +import type { Prettify, PartialDeep } from '@inquirer/type'; +import { type Theme } from './theme.ts'; +export declare function makeTheme(...themes: ReadonlyArray>>): Prettify>; diff --git a/node_modules/@inquirer/core/dist/commonjs/lib/make-theme.js b/node_modules/@inquirer/core/dist/commonjs/lib/make-theme.js new file mode 100644 index 0000000000000000000000000000000000000000..b4b2c6635a91ae5546e9b8fa3c8da40c764a5427 --- /dev/null +++ b/node_modules/@inquirer/core/dist/commonjs/lib/make-theme.js @@ -0,0 +1,33 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.makeTheme = makeTheme; +const theme_ts_1 = require("./theme.js"); +function isPlainObject(value) { + if (typeof value !== 'object' || value === null) + return false; + let proto = value; + while (Object.getPrototypeOf(proto) !== null) { + proto = Object.getPrototypeOf(proto); + } + return Object.getPrototypeOf(value) === proto; +} +function deepMerge(...objects) { + const output = {}; + for (const obj of objects) { + for (const [key, value] of Object.entries(obj)) { + const prevValue = output[key]; + output[key] = + isPlainObject(prevValue) && isPlainObject(value) + ? deepMerge(prevValue, value) + : value; + } + } + return output; +} +function makeTheme(...themes) { + const themesToMerge = [ + theme_ts_1.defaultTheme, + ...themes.filter((theme) => theme != null), + ]; + return deepMerge(...themesToMerge); +} diff --git a/node_modules/@inquirer/core/dist/commonjs/lib/pagination/lines.d.ts b/node_modules/@inquirer/core/dist/commonjs/lib/pagination/lines.d.ts new file mode 100644 index 0000000000000000000000000000000000000000..576619594e2faf3fe0cc55ca35fd525f5d5de8ff --- /dev/null +++ b/node_modules/@inquirer/core/dist/commonjs/lib/pagination/lines.d.ts @@ -0,0 +1,26 @@ +import { type Prettify } from '@inquirer/type'; +/** Represents an item that's part of a layout, about to be rendered */ +export type Layout = { + item: T; + index: number; + isActive: boolean; +}; +/** + * Renders a page of items as lines that fit within the given width ensuring + * that the number of lines is not greater than the page size, and the active + * item renders at the provided position, while prioritizing that as many lines + * of the active item get rendered as possible. + */ +export declare function lines({ items, width, renderItem, active, position: requested, pageSize, }: { + items: ReadonlyArray; + /** The width of a rendered line in characters. */ + width: number; + /** Renders an item as part of a page. */ + renderItem: (layout: Prettify>) => string; + /** The index of the active item in the list of items. */ + active: number; + /** The position on the page at which to render the active item. */ + position: number; + /** The number of lines to render per page. */ + pageSize: number; +}): string[]; diff --git a/node_modules/@inquirer/core/dist/commonjs/lib/pagination/lines.js b/node_modules/@inquirer/core/dist/commonjs/lib/pagination/lines.js new file mode 100644 index 0000000000000000000000000000000000000000..2f25af7903160db930ce980205726c15c82fb90f --- /dev/null +++ b/node_modules/@inquirer/core/dist/commonjs/lib/pagination/lines.js @@ -0,0 +1,62 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.lines = lines; +const utils_ts_1 = require("../utils.js"); +function split(content, width) { + return (0, utils_ts_1.breakLines)(content, width).split('\n'); +} +/** + * Rotates an array of items by an integer number of positions. + * @param {number} count The number of positions to rotate by + * @param {T[]} items The items to rotate + */ +function rotate(count, items) { + const max = items.length; + const offset = ((count % max) + max) % max; + return [...items.slice(offset), ...items.slice(0, offset)]; +} +/** + * Renders a page of items as lines that fit within the given width ensuring + * that the number of lines is not greater than the page size, and the active + * item renders at the provided position, while prioritizing that as many lines + * of the active item get rendered as possible. + */ +function lines({ items, width, renderItem, active, position: requested, pageSize, }) { + const layouts = items.map((item, index) => ({ + item, + index, + isActive: index === active, + })); + const layoutsInPage = rotate(active - requested, layouts).slice(0, pageSize); + const renderItemAt = (index) => layoutsInPage[index] == null ? [] : split(renderItem(layoutsInPage[index]), width); + // Create a blank array of lines for the page + const pageBuffer = Array.from({ length: pageSize }); + // Render the active item to decide the position + const activeItem = renderItemAt(requested).slice(0, pageSize); + const position = requested + activeItem.length <= pageSize ? requested : pageSize - activeItem.length; + // Add the lines of the active item into the page + pageBuffer.splice(position, activeItem.length, ...activeItem); + // Fill the page under the active item + let bufferPointer = position + activeItem.length; + let layoutPointer = requested + 1; + while (bufferPointer < pageSize && layoutPointer < layoutsInPage.length) { + for (const line of renderItemAt(layoutPointer)) { + pageBuffer[bufferPointer++] = line; + if (bufferPointer >= pageSize) + break; + } + layoutPointer++; + } + // Fill the page over the active item + bufferPointer = position - 1; + layoutPointer = requested - 1; + while (bufferPointer >= 0 && layoutPointer >= 0) { + for (const line of renderItemAt(layoutPointer).reverse()) { + pageBuffer[bufferPointer--] = line; + if (bufferPointer < 0) + break; + } + layoutPointer--; + } + return pageBuffer.filter((line) => typeof line === 'string'); +} diff --git a/node_modules/@inquirer/core/dist/commonjs/lib/pagination/position.d.ts b/node_modules/@inquirer/core/dist/commonjs/lib/pagination/position.d.ts new file mode 100644 index 0000000000000000000000000000000000000000..d74870e6c816b2a2b04d02ffa3b359f4d103ec8d --- /dev/null +++ b/node_modules/@inquirer/core/dist/commonjs/lib/pagination/position.d.ts @@ -0,0 +1,20 @@ +/** + * Creates the next position for the active item considering a finite list of + * items to be rendered on a page. + */ +export declare function finite({ active, pageSize, total, }: { + active: number; + pageSize: number; + total: number; +}): number; +/** + * Creates the next position for the active item considering an infinitely + * looping list of items to be rendered on the page. + */ +export declare function infinite({ active, lastActive, total, pageSize, pointer, }: { + active: number; + lastActive: number; + total: number; + pageSize: number; + pointer: number; +}): number; diff --git a/node_modules/@inquirer/core/dist/commonjs/lib/pagination/position.js b/node_modules/@inquirer/core/dist/commonjs/lib/pagination/position.js new file mode 100644 index 0000000000000000000000000000000000000000..9fb765817741bfb9f6c6e7842a581976b93dc422 --- /dev/null +++ b/node_modules/@inquirer/core/dist/commonjs/lib/pagination/position.js @@ -0,0 +1,31 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.finite = finite; +exports.infinite = infinite; +/** + * Creates the next position for the active item considering a finite list of + * items to be rendered on a page. + */ +function finite({ active, pageSize, total, }) { + const middle = Math.floor(pageSize / 2); + if (total <= pageSize || active < middle) + return active; + if (active >= total - middle) + return active + pageSize - total; + return middle; +} +/** + * Creates the next position for the active item considering an infinitely + * looping list of items to be rendered on the page. + */ +function infinite({ active, lastActive, total, pageSize, pointer, }) { + if (total <= pageSize) + return active; + // Move the position only when the user moves down, and when the + // navigation fits within a single page + if (lastActive < active && active - lastActive < pageSize) { + // Limit it to the middle of the list + return Math.min(Math.floor(pageSize / 2), pointer + active - lastActive); + } + return pointer; +} diff --git a/node_modules/@inquirer/core/dist/commonjs/lib/pagination/use-pagination.d.ts b/node_modules/@inquirer/core/dist/commonjs/lib/pagination/use-pagination.d.ts new file mode 100644 index 0000000000000000000000000000000000000000..7af6097ab2210957dea3355bde1adcd82dc0b228 --- /dev/null +++ b/node_modules/@inquirer/core/dist/commonjs/lib/pagination/use-pagination.d.ts @@ -0,0 +1,15 @@ +import type { Prettify } from '@inquirer/type'; +import { type Theme } from '../theme.ts'; +import { type Layout } from './lines.ts'; +export declare function usePagination({ items, active, renderItem, pageSize, loop, }: { + items: ReadonlyArray; + /** The index of the active item. */ + active: number; + /** Renders an item as part of a page. */ + renderItem: (layout: Prettify>) => string; + /** The size of the page. */ + pageSize: number; + /** Allows creating an infinitely looping list. `true` if unspecified. */ + loop?: boolean; + theme?: Theme; +}): string; diff --git a/node_modules/@inquirer/core/dist/commonjs/lib/pagination/use-pagination.js b/node_modules/@inquirer/core/dist/commonjs/lib/pagination/use-pagination.js new file mode 100644 index 0000000000000000000000000000000000000000..5bef5aeafc4d12aa41bdde99ecd7c621a954f2f2 --- /dev/null +++ b/node_modules/@inquirer/core/dist/commonjs/lib/pagination/use-pagination.js @@ -0,0 +1,33 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.usePagination = usePagination; +const use_ref_ts_1 = require("../use-ref.js"); +const utils_ts_1 = require("../utils.js"); +const lines_ts_1 = require("./lines.js"); +const position_ts_1 = require("./position.js"); +function usePagination({ items, active, renderItem, pageSize, loop = true, }) { + const state = (0, use_ref_ts_1.useRef)({ position: 0, lastActive: 0 }); + const position = loop + ? (0, position_ts_1.infinite)({ + active, + lastActive: state.current.lastActive, + total: items.length, + pageSize, + pointer: state.current.position, + }) + : (0, position_ts_1.finite)({ + active, + total: items.length, + pageSize, + }); + state.current.position = position; + state.current.lastActive = active; + return (0, lines_ts_1.lines)({ + items, + width: (0, utils_ts_1.readlineWidth)(), + renderItem, + active, + position, + pageSize, + }).join('\n'); +} diff --git a/node_modules/@inquirer/core/dist/commonjs/lib/promise-polyfill.d.ts b/node_modules/@inquirer/core/dist/commonjs/lib/promise-polyfill.d.ts new file mode 100644 index 0000000000000000000000000000000000000000..0e4f74ca61d0b9ad9e7f092c436b79d137c0bb22 --- /dev/null +++ b/node_modules/@inquirer/core/dist/commonjs/lib/promise-polyfill.d.ts @@ -0,0 +1,7 @@ +export declare class PromisePolyfill extends Promise { + static withResolver(): { + promise: Promise; + resolve: (value: T) => void; + reject: (error: unknown) => void; + }; +} diff --git a/node_modules/@inquirer/core/dist/commonjs/lib/promise-polyfill.js b/node_modules/@inquirer/core/dist/commonjs/lib/promise-polyfill.js new file mode 100644 index 0000000000000000000000000000000000000000..7e6bdc4123bf559cd48fdf779a277a32d0118167 --- /dev/null +++ b/node_modules/@inquirer/core/dist/commonjs/lib/promise-polyfill.js @@ -0,0 +1,18 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.PromisePolyfill = void 0; +// TODO: Remove this class once Node 22 becomes the minimum supported version. +class PromisePolyfill extends Promise { + // Available starting from Node 22 + // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/withResolvers + static withResolver() { + let resolve; + let reject; + const promise = new Promise((res, rej) => { + resolve = res; + reject = rej; + }); + return { promise, resolve: resolve, reject: reject }; + } +} +exports.PromisePolyfill = PromisePolyfill; diff --git a/node_modules/@inquirer/core/dist/commonjs/lib/screen-manager.d.ts b/node_modules/@inquirer/core/dist/commonjs/lib/screen-manager.d.ts new file mode 100644 index 0000000000000000000000000000000000000000..de4c1e00fb09d30464dbebf43b87a04c8a9b8e8f --- /dev/null +++ b/node_modules/@inquirer/core/dist/commonjs/lib/screen-manager.d.ts @@ -0,0 +1,14 @@ +import type { InquirerReadline } from '@inquirer/type'; +export default class ScreenManager { + private height; + private extraLinesUnderPrompt; + private cursorPos; + private readonly rl; + constructor(rl: InquirerReadline); + write(content: string): void; + render(content: string, bottomContent?: string): void; + checkCursorPos(): void; + done({ clearContent }: { + clearContent: boolean; + }): void; +} diff --git a/node_modules/@inquirer/core/dist/commonjs/lib/screen-manager.js b/node_modules/@inquirer/core/dist/commonjs/lib/screen-manager.js new file mode 100644 index 0000000000000000000000000000000000000000..a195edee31110c0b2a5bd7d9041ac50e613dc411 --- /dev/null +++ b/node_modules/@inquirer/core/dist/commonjs/lib/screen-manager.js @@ -0,0 +1,90 @@ +"use strict"; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +const node_util_1 = require("node:util"); +const ansi_escapes_1 = __importDefault(require("ansi-escapes")); +const utils_ts_1 = require("./utils.js"); +const height = (content) => content.split('\n').length; +const lastLine = (content) => content.split('\n').pop() ?? ''; +function cursorDown(n) { + return n > 0 ? ansi_escapes_1.default.cursorDown(n) : ''; +} +class ScreenManager { + // These variables are keeping information to allow correct prompt re-rendering + height = 0; + extraLinesUnderPrompt = 0; + cursorPos; + rl; + constructor(rl) { + this.rl = rl; + this.cursorPos = rl.getCursorPos(); + } + write(content) { + this.rl.output.unmute(); + this.rl.output.write(content); + this.rl.output.mute(); + } + render(content, bottomContent = '') { + // Write message to screen and setPrompt to control backspace + const promptLine = lastLine(content); + const rawPromptLine = (0, node_util_1.stripVTControlCharacters)(promptLine); + // Remove the rl.line from our prompt. We can't rely on the content of + // rl.line (mainly because of the password prompt), so just rely on it's + // length. + let prompt = rawPromptLine; + if (this.rl.line.length > 0) { + prompt = prompt.slice(0, -this.rl.line.length); + } + this.rl.setPrompt(prompt); + // SetPrompt will change cursor position, now we can get correct value + this.cursorPos = this.rl.getCursorPos(); + const width = (0, utils_ts_1.readlineWidth)(); + content = (0, utils_ts_1.breakLines)(content, width); + bottomContent = (0, utils_ts_1.breakLines)(bottomContent, width); + // Manually insert an extra line if we're at the end of the line. + // This prevent the cursor from appearing at the beginning of the + // current line. + if (rawPromptLine.length % width === 0) { + content += '\n'; + } + let output = content + (bottomContent ? '\n' + bottomContent : ''); + /** + * Re-adjust the cursor at the correct position. + */ + // We need to consider parts of the prompt under the cursor as part of the bottom + // content in order to correctly cleanup and re-render. + const promptLineUpDiff = Math.floor(rawPromptLine.length / width) - this.cursorPos.rows; + const bottomContentHeight = promptLineUpDiff + (bottomContent ? height(bottomContent) : 0); + // Return cursor to the input position (on top of the bottomContent) + if (bottomContentHeight > 0) + output += ansi_escapes_1.default.cursorUp(bottomContentHeight); + // Return cursor to the initial left offset. + output += ansi_escapes_1.default.cursorTo(this.cursorPos.cols); + /** + * Render and store state for future re-rendering + */ + this.write(cursorDown(this.extraLinesUnderPrompt) + + ansi_escapes_1.default.eraseLines(this.height) + + output); + this.extraLinesUnderPrompt = bottomContentHeight; + this.height = height(output); + } + checkCursorPos() { + const cursorPos = this.rl.getCursorPos(); + if (cursorPos.cols !== this.cursorPos.cols) { + this.write(ansi_escapes_1.default.cursorTo(cursorPos.cols)); + this.cursorPos = cursorPos; + } + } + done({ clearContent }) { + this.rl.setPrompt(''); + let output = cursorDown(this.extraLinesUnderPrompt); + output += clearContent ? ansi_escapes_1.default.eraseLines(this.height) : '\n'; + output += ansi_escapes_1.default.cursorShow; + this.write(output); + this.rl.close(); + } +} +exports.default = ScreenManager; diff --git a/node_modules/@inquirer/core/dist/commonjs/lib/theme.d.ts b/node_modules/@inquirer/core/dist/commonjs/lib/theme.d.ts new file mode 100644 index 0000000000000000000000000000000000000000..f1529b0a309a88409d09ba766467bb51742cb652 --- /dev/null +++ b/node_modules/@inquirer/core/dist/commonjs/lib/theme.d.ts @@ -0,0 +1,155 @@ +import type { Prettify } from '@inquirer/type'; +/** + * Union type representing the possible statuses of a prompt. + * + * - `'loading'`: The prompt is currently loading. + * - `'idle'`: The prompt is loaded and currently waiting for the user to + * submit an answer. + * - `'done'`: The user has submitted an answer and the prompt is finished. + * - `string`: Any other string: The prompt is in a custom state. + */ +export type Status = 'loading' | 'idle' | 'done' | (string & {}); +type DefaultTheme = { + /** + * Prefix to prepend to the message. If a function is provided, it will be + * called with the current status of the prompt, and the return value will be + * used as the prefix. + * + * @remarks + * If `status === 'loading'`, this property is ignored and the spinner (styled + * by the `spinner` property) will be displayed instead. + * + * @defaultValue + * ```ts + * // import colors from 'yoctocolors-cjs'; + * (status) => status === 'done' ? colors.green('✔') : colors.blue('?') + * ``` + */ + prefix: string | Prettify, 'loading'>>; + /** + * Configuration for the spinner that is displayed when the prompt is in the + * `'loading'` state. + * + * We recommend the use of {@link https://github.com/sindresorhus/cli-spinners|cli-spinners} for a list of available spinners. + */ + spinner: { + /** + * The time interval between frames, in milliseconds. + * + * @defaultValue + * ```ts + * 80 + * ``` + */ + interval: number; + /** + * A list of frames to show for the spinner. + * + * @defaultValue + * ```ts + * ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'] + * ``` + */ + frames: string[]; + }; + /** + * Object containing functions to style different parts of the prompt. + */ + style: { + /** + * Style to apply to the user's answer once it has been submitted. + * + * @param text - The user's answer. + * @returns The styled answer. + * + * @defaultValue + * ```ts + * // import colors from 'yoctocolors-cjs'; + * (text) => colors.cyan(text) + * ``` + */ + answer: (text: string) => string; + /** + * Style to apply to the message displayed to the user. + * + * @param text - The message to style. + * @param status - The current status of the prompt. + * @returns The styled message. + * + * @defaultValue + * ```ts + * // import colors from 'yoctocolors-cjs'; + * (text, status) => colors.bold(text) + * ``` + */ + message: (text: string, status: Status) => string; + /** + * Style to apply to error messages. + * + * @param text - The error message. + * @returns The styled error message. + * + * @defaultValue + * ```ts + * // import colors from 'yoctocolors-cjs'; + * (text) => colors.red(`> ${text}`) + * ``` + */ + error: (text: string) => string; + /** + * Style to apply to the default answer when one is provided. + * + * @param text - The default answer. + * @returns The styled default answer. + * + * @defaultValue + * ```ts + * // import colors from 'yoctocolors-cjs'; + * (text) => colors.dim(`(${text})`) + * ``` + */ + defaultAnswer: (text: string) => string; + /** + * Style to apply to help text. + * + * @param text - The help text. + * @returns The styled help text. + * + * @defaultValue + * ```ts + * // import colors from 'yoctocolors-cjs'; + * (text) => colors.dim(text) + * ``` + */ + help: (text: string) => string; + /** + * Style to apply to highlighted text. + * + * @param text - The text to highlight. + * @returns The highlighted text. + * + * @defaultValue + * ```ts + * // import colors from 'yoctocolors-cjs'; + * (text) => colors.cyan(text) + * ``` + */ + highlight: (text: string) => string; + /** + * Style to apply to keyboard keys referred to in help texts. + * + * @param text - The key to style. + * @returns The styled key. + * + * @defaultValue + * ```ts + * // import colors from 'yoctocolors-cjs'; + * (text) => colors.cyan(colors.bold(`<${text}>`)) + * ``` + */ + key: (text: string) => string; + }; +}; +export type Theme = Prettify; +export declare const defaultTheme: DefaultTheme; +export {}; diff --git a/node_modules/@inquirer/core/dist/commonjs/lib/theme.js b/node_modules/@inquirer/core/dist/commonjs/lib/theme.js new file mode 100644 index 0000000000000000000000000000000000000000..3bb4fa8737a48b055b2bf453396ae6f92fc05d01 --- /dev/null +++ b/node_modules/@inquirer/core/dist/commonjs/lib/theme.js @@ -0,0 +1,28 @@ +"use strict"; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.defaultTheme = void 0; +const yoctocolors_cjs_1 = __importDefault(require("yoctocolors-cjs")); +const figures_1 = __importDefault(require("@inquirer/figures")); +exports.defaultTheme = { + prefix: { + idle: yoctocolors_cjs_1.default.blue('?'), + // TODO: use figure + done: yoctocolors_cjs_1.default.green(figures_1.default.tick), + }, + spinner: { + interval: 80, + frames: ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'].map((frame) => yoctocolors_cjs_1.default.yellow(frame)), + }, + style: { + answer: yoctocolors_cjs_1.default.cyan, + message: yoctocolors_cjs_1.default.bold, + error: (text) => yoctocolors_cjs_1.default.red(`> ${text}`), + defaultAnswer: (text) => yoctocolors_cjs_1.default.dim(`(${text})`), + help: yoctocolors_cjs_1.default.dim, + highlight: yoctocolors_cjs_1.default.cyan, + key: (text) => yoctocolors_cjs_1.default.cyan(yoctocolors_cjs_1.default.bold(`<${text}>`)), + }, +}; diff --git a/node_modules/@inquirer/core/dist/commonjs/lib/use-effect.d.ts b/node_modules/@inquirer/core/dist/commonjs/lib/use-effect.d.ts new file mode 100644 index 0000000000000000000000000000000000000000..abee90639f181a2a64ec31dd47e3920586edc9ad --- /dev/null +++ b/node_modules/@inquirer/core/dist/commonjs/lib/use-effect.d.ts @@ -0,0 +1,2 @@ +import type { InquirerReadline } from '@inquirer/type'; +export declare function useEffect(cb: (rl: InquirerReadline) => void | (() => void), depArray: ReadonlyArray): void; diff --git a/node_modules/@inquirer/core/dist/commonjs/lib/use-effect.js b/node_modules/@inquirer/core/dist/commonjs/lib/use-effect.js new file mode 100644 index 0000000000000000000000000000000000000000..b82c206d443d47792357cb69b3ee590acdf173c3 --- /dev/null +++ b/node_modules/@inquirer/core/dist/commonjs/lib/use-effect.js @@ -0,0 +1,14 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.useEffect = useEffect; +const hook_engine_ts_1 = require("./hook-engine.js"); +function useEffect(cb, depArray) { + (0, hook_engine_ts_1.withPointer)((pointer) => { + const oldDeps = pointer.get(); + const hasChanged = !Array.isArray(oldDeps) || depArray.some((dep, i) => !Object.is(dep, oldDeps[i])); + if (hasChanged) { + hook_engine_ts_1.effectScheduler.queue(cb); + } + pointer.set(depArray); + }); +} diff --git a/node_modules/@inquirer/core/dist/commonjs/lib/use-keypress.d.ts b/node_modules/@inquirer/core/dist/commonjs/lib/use-keypress.d.ts new file mode 100644 index 0000000000000000000000000000000000000000..ccdeefaf26be3e47e9c2459f23707e7b50af0ddf --- /dev/null +++ b/node_modules/@inquirer/core/dist/commonjs/lib/use-keypress.d.ts @@ -0,0 +1,3 @@ +import { type InquirerReadline } from '@inquirer/type'; +import { type KeypressEvent } from './key.ts'; +export declare function useKeypress(userHandler: (event: KeypressEvent, rl: InquirerReadline) => void | Promise): void; diff --git a/node_modules/@inquirer/core/dist/commonjs/lib/use-keypress.js b/node_modules/@inquirer/core/dist/commonjs/lib/use-keypress.js new file mode 100644 index 0000000000000000000000000000000000000000..1f78f15d14f9edb034c82f1afc5682ca3a6558a8 --- /dev/null +++ b/node_modules/@inquirer/core/dist/commonjs/lib/use-keypress.js @@ -0,0 +1,23 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.useKeypress = useKeypress; +const use_ref_ts_1 = require("./use-ref.js"); +const use_effect_ts_1 = require("./use-effect.js"); +const hook_engine_ts_1 = require("./hook-engine.js"); +function useKeypress(userHandler) { + const signal = (0, use_ref_ts_1.useRef)(userHandler); + signal.current = userHandler; + (0, use_effect_ts_1.useEffect)((rl) => { + let ignore = false; + const handler = (0, hook_engine_ts_1.withUpdates)((_input, event) => { + if (ignore) + return; + void signal.current(event, rl); + }); + rl.input.on('keypress', handler); + return () => { + ignore = true; + rl.input.removeListener('keypress', handler); + }; + }, []); +} diff --git a/node_modules/@inquirer/core/dist/commonjs/lib/use-memo.d.ts b/node_modules/@inquirer/core/dist/commonjs/lib/use-memo.d.ts new file mode 100644 index 0000000000000000000000000000000000000000..19d164433d1f17a0bb9e0557e8b9eedc307271f7 --- /dev/null +++ b/node_modules/@inquirer/core/dist/commonjs/lib/use-memo.d.ts @@ -0,0 +1 @@ +export declare function useMemo(fn: () => Value, dependencies: ReadonlyArray): Value; diff --git a/node_modules/@inquirer/core/dist/commonjs/lib/use-memo.js b/node_modules/@inquirer/core/dist/commonjs/lib/use-memo.js new file mode 100644 index 0000000000000000000000000000000000000000..d6fcadb7c9e2efdb08f730b77919f5a41e57f6e3 --- /dev/null +++ b/node_modules/@inquirer/core/dist/commonjs/lib/use-memo.js @@ -0,0 +1,17 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.useMemo = useMemo; +const hook_engine_ts_1 = require("./hook-engine.js"); +function useMemo(fn, dependencies) { + return (0, hook_engine_ts_1.withPointer)((pointer) => { + const prev = pointer.get(); + if (!prev || + prev.dependencies.length !== dependencies.length || + prev.dependencies.some((dep, i) => dep !== dependencies[i])) { + const value = fn(); + pointer.set({ value, dependencies }); + return value; + } + return prev.value; + }); +} diff --git a/node_modules/@inquirer/core/dist/commonjs/lib/use-prefix.d.ts b/node_modules/@inquirer/core/dist/commonjs/lib/use-prefix.d.ts new file mode 100644 index 0000000000000000000000000000000000000000..db1dabb13a37372d17b7ec3f944586ffc3916c17 --- /dev/null +++ b/node_modules/@inquirer/core/dist/commonjs/lib/use-prefix.d.ts @@ -0,0 +1,5 @@ +import type { Theme, Status } from './theme.ts'; +export declare function usePrefix({ status, theme, }: { + status?: Status; + theme?: Theme; +}): string; diff --git a/node_modules/@inquirer/core/dist/commonjs/lib/use-prefix.js b/node_modules/@inquirer/core/dist/commonjs/lib/use-prefix.js new file mode 100644 index 0000000000000000000000000000000000000000..40927bce10c8a8a3d02ae29159662b813566d71c --- /dev/null +++ b/node_modules/@inquirer/core/dist/commonjs/lib/use-prefix.js @@ -0,0 +1,39 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.usePrefix = usePrefix; +const node_async_hooks_1 = require("node:async_hooks"); +const use_state_ts_1 = require("./use-state.js"); +const use_effect_ts_1 = require("./use-effect.js"); +const make_theme_ts_1 = require("./make-theme.js"); +function usePrefix({ status = 'idle', theme, }) { + const [showLoader, setShowLoader] = (0, use_state_ts_1.useState)(false); + const [tick, setTick] = (0, use_state_ts_1.useState)(0); + const { prefix, spinner } = (0, make_theme_ts_1.makeTheme)(theme); + (0, use_effect_ts_1.useEffect)(() => { + if (status === 'loading') { + let tickInterval; + let inc = -1; + // Delay displaying spinner by 300ms, to avoid flickering + const delayTimeout = setTimeout(node_async_hooks_1.AsyncResource.bind(() => { + setShowLoader(true); + tickInterval = setInterval(node_async_hooks_1.AsyncResource.bind(() => { + inc = inc + 1; + setTick(inc % spinner.frames.length); + }), spinner.interval); + }), 300); + return () => { + clearTimeout(delayTimeout); + clearInterval(tickInterval); + }; + } + else { + setShowLoader(false); + } + }, [status]); + if (showLoader) { + return spinner.frames[tick]; + } + // There's a delay before we show the loader. So we want to ignore `loading` here, and pass idle instead. + const iconName = status === 'loading' ? 'idle' : status; + return typeof prefix === 'string' ? prefix : (prefix[iconName] ?? prefix['idle']); +} diff --git a/node_modules/@inquirer/core/dist/commonjs/lib/use-ref.d.ts b/node_modules/@inquirer/core/dist/commonjs/lib/use-ref.d.ts new file mode 100644 index 0000000000000000000000000000000000000000..be7126b9e8784bebfe6526bdca70895a388a0c16 --- /dev/null +++ b/node_modules/@inquirer/core/dist/commonjs/lib/use-ref.d.ts @@ -0,0 +1,6 @@ +export declare function useRef(val: Value): { + current: Value; +}; +export declare function useRef(val?: Value): { + current: Value | undefined; +}; diff --git a/node_modules/@inquirer/core/dist/commonjs/lib/use-ref.js b/node_modules/@inquirer/core/dist/commonjs/lib/use-ref.js new file mode 100644 index 0000000000000000000000000000000000000000..513b2ee385309c19201d450bfcbd0f00a187ba2b --- /dev/null +++ b/node_modules/@inquirer/core/dist/commonjs/lib/use-ref.js @@ -0,0 +1,7 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.useRef = useRef; +const use_state_ts_1 = require("./use-state.js"); +function useRef(val) { + return (0, use_state_ts_1.useState)({ current: val })[0]; +} diff --git a/node_modules/@inquirer/core/dist/commonjs/lib/use-state.d.ts b/node_modules/@inquirer/core/dist/commonjs/lib/use-state.d.ts new file mode 100644 index 0000000000000000000000000000000000000000..fba0b621f9dce863bbd33d7dac60cf19894d7a9f --- /dev/null +++ b/node_modules/@inquirer/core/dist/commonjs/lib/use-state.d.ts @@ -0,0 +1,4 @@ +type NotFunction = T extends (...args: never) => unknown ? never : T; +export declare function useState(defaultValue: NotFunction | (() => Value)): [Value, (newValue: Value) => void]; +export declare function useState(defaultValue?: NotFunction | (() => Value)): [Value | undefined, (newValue?: Value) => void]; +export {}; diff --git a/node_modules/@inquirer/core/dist/commonjs/lib/use-state.js b/node_modules/@inquirer/core/dist/commonjs/lib/use-state.js new file mode 100644 index 0000000000000000000000000000000000000000..e4560699dc65c0d006ad232db65c0d9b18e38cf0 --- /dev/null +++ b/node_modules/@inquirer/core/dist/commonjs/lib/use-state.js @@ -0,0 +1,22 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.useState = useState; +const hook_engine_ts_1 = require("./hook-engine.js"); +function useState(defaultValue) { + return (0, hook_engine_ts_1.withPointer)((pointer) => { + const setFn = (newValue) => { + // Noop if the value is still the same. + if (pointer.get() !== newValue) { + pointer.set(newValue); + // Trigger re-render + (0, hook_engine_ts_1.handleChange)(); + } + }; + if (pointer.initialized) { + return [pointer.get(), setFn]; + } + const value = typeof defaultValue === 'function' ? defaultValue() : defaultValue; + pointer.set(value); + return [value, setFn]; + }); +} diff --git a/node_modules/@inquirer/core/dist/commonjs/lib/utils.d.ts b/node_modules/@inquirer/core/dist/commonjs/lib/utils.d.ts new file mode 100644 index 0000000000000000000000000000000000000000..14f8fc438e8a481cf90a4c071b18751e26f9f4d0 --- /dev/null +++ b/node_modules/@inquirer/core/dist/commonjs/lib/utils.d.ts @@ -0,0 +1,13 @@ +/** + * Force line returns at specific width. This function is ANSI code friendly and it'll + * ignore invisible codes during width calculation. + * @param {string} content + * @param {number} width + * @return {string} + */ +export declare function breakLines(content: string, width: number): string; +/** + * Returns the width of the active readline, or 80 as default value. + * @returns {number} + */ +export declare function readlineWidth(): number; diff --git a/node_modules/@inquirer/core/dist/commonjs/lib/utils.js b/node_modules/@inquirer/core/dist/commonjs/lib/utils.js new file mode 100644 index 0000000000000000000000000000000000000000..ae9e12a15a979c690b2276e629485c8e9e3090a4 --- /dev/null +++ b/node_modules/@inquirer/core/dist/commonjs/lib/utils.js @@ -0,0 +1,32 @@ +"use strict"; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.breakLines = breakLines; +exports.readlineWidth = readlineWidth; +const cli_width_1 = __importDefault(require("cli-width")); +const wrap_ansi_1 = __importDefault(require("wrap-ansi")); +const hook_engine_ts_1 = require("./hook-engine.js"); +/** + * Force line returns at specific width. This function is ANSI code friendly and it'll + * ignore invisible codes during width calculation. + * @param {string} content + * @param {number} width + * @return {string} + */ +function breakLines(content, width) { + return content + .split('\n') + .flatMap((line) => (0, wrap_ansi_1.default)(line, width, { trim: false, hard: true }) + .split('\n') + .map((str) => str.trimEnd())) + .join('\n'); +} +/** + * Returns the width of the active readline, or 80 as default value. + * @returns {number} + */ +function readlineWidth() { + return (0, cli_width_1.default)({ defaultWidth: 80, output: (0, hook_engine_ts_1.readline)().output }); +} diff --git a/node_modules/@inquirer/core/dist/commonjs/package.json b/node_modules/@inquirer/core/dist/commonjs/package.json new file mode 100644 index 0000000000000000000000000000000000000000..5bbefffbabee392d1855491b84dc0a716b6a3bf2 --- /dev/null +++ b/node_modules/@inquirer/core/dist/commonjs/package.json @@ -0,0 +1,3 @@ +{ + "type": "commonjs" +} diff --git a/node_modules/@inquirer/core/dist/esm/index.d.ts b/node_modules/@inquirer/core/dist/esm/index.d.ts new file mode 100644 index 0000000000000000000000000000000000000000..2f285728f6d497acd9ce2561fa2291412146b220 --- /dev/null +++ b/node_modules/@inquirer/core/dist/esm/index.d.ts @@ -0,0 +1,13 @@ +export * from './lib/key.ts'; +export * from './lib/errors.ts'; +export { usePrefix } from './lib/use-prefix.ts'; +export { useState } from './lib/use-state.ts'; +export { useEffect } from './lib/use-effect.ts'; +export { useMemo } from './lib/use-memo.ts'; +export { useRef } from './lib/use-ref.ts'; +export { useKeypress } from './lib/use-keypress.ts'; +export { makeTheme } from './lib/make-theme.ts'; +export type { Theme, Status } from './lib/theme.ts'; +export { usePagination } from './lib/pagination/use-pagination.ts'; +export { createPrompt } from './lib/create-prompt.ts'; +export { Separator } from './lib/Separator.ts'; diff --git a/node_modules/@inquirer/core/dist/esm/index.js b/node_modules/@inquirer/core/dist/esm/index.js new file mode 100644 index 0000000000000000000000000000000000000000..a2ab0e3fb695f10fc21ca03ff470120c810c9ff5 --- /dev/null +++ b/node_modules/@inquirer/core/dist/esm/index.js @@ -0,0 +1,12 @@ +export * from "./lib/key.js"; +export * from "./lib/errors.js"; +export { usePrefix } from "./lib/use-prefix.js"; +export { useState } from "./lib/use-state.js"; +export { useEffect } from "./lib/use-effect.js"; +export { useMemo } from "./lib/use-memo.js"; +export { useRef } from "./lib/use-ref.js"; +export { useKeypress } from "./lib/use-keypress.js"; +export { makeTheme } from "./lib/make-theme.js"; +export { usePagination } from "./lib/pagination/use-pagination.js"; +export { createPrompt } from "./lib/create-prompt.js"; +export { Separator } from "./lib/Separator.js"; diff --git a/node_modules/@inquirer/core/dist/esm/lib/Separator.d.ts b/node_modules/@inquirer/core/dist/esm/lib/Separator.d.ts new file mode 100644 index 0000000000000000000000000000000000000000..028355567638da2eac0e8c759ce6a3ce07dd643b --- /dev/null +++ b/node_modules/@inquirer/core/dist/esm/lib/Separator.d.ts @@ -0,0 +1,10 @@ +/** + * Separator object + * Used to space/separate choices group + */ +export declare class Separator { + readonly separator: string; + readonly type: string; + constructor(separator?: string); + static isSeparator(choice: unknown): choice is Separator; +} diff --git a/node_modules/@inquirer/core/dist/esm/lib/Separator.js b/node_modules/@inquirer/core/dist/esm/lib/Separator.js new file mode 100644 index 0000000000000000000000000000000000000000..f0d8409ae4eb9a735f539353f9b0eaefa9fc2c73 --- /dev/null +++ b/node_modules/@inquirer/core/dist/esm/lib/Separator.js @@ -0,0 +1,21 @@ +import colors from 'yoctocolors-cjs'; +import figures from '@inquirer/figures'; +/** + * Separator object + * Used to space/separate choices group + */ +export class Separator { + separator = colors.dim(Array.from({ length: 15 }).join(figures.line)); + type = 'separator'; + constructor(separator) { + if (separator) { + this.separator = separator; + } + } + static isSeparator(choice) { + return Boolean(choice && + typeof choice === 'object' && + 'type' in choice && + choice.type === 'separator'); + } +} diff --git a/node_modules/@inquirer/core/dist/esm/lib/create-prompt.d.ts b/node_modules/@inquirer/core/dist/esm/lib/create-prompt.d.ts new file mode 100644 index 0000000000000000000000000000000000000000..4414db45697e4e2d9dc2f0d3894b4891746cb4b3 --- /dev/null +++ b/node_modules/@inquirer/core/dist/esm/lib/create-prompt.d.ts @@ -0,0 +1,4 @@ +import { type Prompt, type Prettify } from '@inquirer/type'; +type ViewFunction = (config: Prettify, done: (value: Value) => void) => string | [string, string | undefined]; +export declare function createPrompt(view: ViewFunction): Prompt; +export {}; diff --git a/node_modules/@inquirer/core/dist/esm/lib/create-prompt.js b/node_modules/@inquirer/core/dist/esm/lib/create-prompt.js new file mode 100644 index 0000000000000000000000000000000000000000..8c33570ce18cdba74b74bc4ee2f2162b8420cae0 --- /dev/null +++ b/node_modules/@inquirer/core/dist/esm/lib/create-prompt.js @@ -0,0 +1,110 @@ +import * as readline from 'node:readline'; +import { AsyncResource } from 'node:async_hooks'; +import MuteStream from 'mute-stream'; +import { onExit as onSignalExit } from 'signal-exit'; +import ScreenManager from "./screen-manager.js"; +import { PromisePolyfill } from "./promise-polyfill.js"; +import { withHooks, effectScheduler } from "./hook-engine.js"; +import { AbortPromptError, CancelPromptError, ExitPromptError } from "./errors.js"; +function getCallSites() { + const _prepareStackTrace = Error.prepareStackTrace; + let result = []; + try { + Error.prepareStackTrace = (_, callSites) => { + const callSitesWithoutCurrent = callSites.slice(1); + result = callSitesWithoutCurrent; + return callSitesWithoutCurrent; + }; + // eslint-disable-next-line @typescript-eslint/no-unused-expressions, unicorn/error-message + new Error().stack; + } + catch { + // An error will occur if the Node flag --frozen-intrinsics is used. + // https://nodejs.org/api/cli.html#--frozen-intrinsics + return result; + } + Error.prepareStackTrace = _prepareStackTrace; + return result; +} +export function createPrompt(view) { + const callSites = getCallSites(); + const prompt = (config, context = {}) => { + // Default `input` to stdin + const { input = process.stdin, signal } = context; + const cleanups = new Set(); + // Add mute capabilities to the output + const output = new MuteStream(); + output.pipe(context.output ?? process.stdout); + const rl = readline.createInterface({ + terminal: true, + input, + output, + }); + const screen = new ScreenManager(rl); + const { promise, resolve, reject } = PromisePolyfill.withResolver(); + const cancel = () => reject(new CancelPromptError()); + if (signal) { + const abort = () => reject(new AbortPromptError({ cause: signal.reason })); + if (signal.aborted) { + abort(); + return Object.assign(promise, { cancel }); + } + signal.addEventListener('abort', abort); + cleanups.add(() => signal.removeEventListener('abort', abort)); + } + cleanups.add(onSignalExit((code, signal) => { + reject(new ExitPromptError(`User force closed the prompt with ${code} ${signal}`)); + })); + // Re-renders only happen when the state change; but the readline cursor could change position + // and that also requires a re-render (and a manual one because we mute the streams). + // We set the listener after the initial workLoop to avoid a double render if render triggered + // by a state change sets the cursor to the right position. + const checkCursorPos = () => screen.checkCursorPos(); + rl.input.on('keypress', checkCursorPos); + cleanups.add(() => rl.input.removeListener('keypress', checkCursorPos)); + return withHooks(rl, (cycle) => { + // The close event triggers immediately when the user press ctrl+c. SignalExit on the other hand + // triggers after the process is done (which happens after timeouts are done triggering.) + // We triggers the hooks cleanup phase on rl `close` so active timeouts can be cleared. + const hooksCleanup = AsyncResource.bind(() => effectScheduler.clearAll()); + rl.on('close', hooksCleanup); + cleanups.add(() => rl.removeListener('close', hooksCleanup)); + cycle(() => { + try { + const nextView = view(config, (value) => { + setImmediate(() => resolve(value)); + }); + // Typescript won't allow this, but not all users rely on typescript. + // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition + if (nextView === undefined) { + const callerFilename = callSites[1]?.getFileName(); + throw new Error(`Prompt functions must return a string.\n at ${callerFilename}`); + } + const [content, bottomContent] = typeof nextView === 'string' ? [nextView] : nextView; + screen.render(content, bottomContent); + effectScheduler.run(); + } + catch (error) { + reject(error); + } + }); + return Object.assign(promise + .then((answer) => { + effectScheduler.clearAll(); + return answer; + }, (error) => { + effectScheduler.clearAll(); + throw error; + }) + // Wait for the promise to settle, then cleanup. + .finally(() => { + cleanups.forEach((cleanup) => cleanup()); + screen.done({ clearContent: Boolean(context.clearPromptOnDone) }); + output.end(); + }) + // Once cleanup is done, let the expose promise resolve/reject to the internal one. + .then(() => promise), { cancel }); + }); + }; + return prompt; +} diff --git a/node_modules/@inquirer/core/dist/esm/lib/errors.d.ts b/node_modules/@inquirer/core/dist/esm/lib/errors.d.ts new file mode 100644 index 0000000000000000000000000000000000000000..b9df681e623b3a0798c95080f009ff994e4e7010 --- /dev/null +++ b/node_modules/@inquirer/core/dist/esm/lib/errors.d.ts @@ -0,0 +1,20 @@ +export declare class AbortPromptError extends Error { + name: string; + message: string; + constructor(options?: { + cause?: unknown; + }); +} +export declare class CancelPromptError extends Error { + name: string; + message: string; +} +export declare class ExitPromptError extends Error { + name: string; +} +export declare class HookError extends Error { + name: string; +} +export declare class ValidationError extends Error { + name: string; +} diff --git a/node_modules/@inquirer/core/dist/esm/lib/errors.js b/node_modules/@inquirer/core/dist/esm/lib/errors.js new file mode 100644 index 0000000000000000000000000000000000000000..153a9363ee96a4ef0d4d5ce024d755e71f13a5f3 --- /dev/null +++ b/node_modules/@inquirer/core/dist/esm/lib/errors.js @@ -0,0 +1,21 @@ +export class AbortPromptError extends Error { + name = 'AbortPromptError'; + message = 'Prompt was aborted'; + constructor(options) { + super(); + this.cause = options?.cause; + } +} +export class CancelPromptError extends Error { + name = 'CancelPromptError'; + message = 'Prompt was canceled'; +} +export class ExitPromptError extends Error { + name = 'ExitPromptError'; +} +export class HookError extends Error { + name = 'HookError'; +} +export class ValidationError extends Error { + name = 'ValidationError'; +} diff --git a/node_modules/@inquirer/core/dist/esm/lib/hook-engine.d.ts b/node_modules/@inquirer/core/dist/esm/lib/hook-engine.d.ts new file mode 100644 index 0000000000000000000000000000000000000000..c4715a8843bfe2fa80c14b542dc56ee84dc1e250 --- /dev/null +++ b/node_modules/@inquirer/core/dist/esm/lib/hook-engine.d.ts @@ -0,0 +1,23 @@ +import type { InquirerReadline } from '@inquirer/type'; +export declare function withHooks(rl: InquirerReadline, cb: (cycle: (render: () => void) => void) => T): T; +export declare function readline(): InquirerReadline; +export declare function withUpdates R>(fn: T): (...args: Parameters) => R; +type SetPointer = { + get(): Value; + set(value: Value): void; + initialized: true; +}; +type UnsetPointer = { + get(): void; + set(value: Value): void; + initialized: false; +}; +type Pointer = SetPointer | UnsetPointer; +export declare function withPointer(cb: (pointer: Pointer) => ReturnValue): ReturnValue; +export declare function handleChange(): void; +export declare const effectScheduler: { + queue(cb: (readline: InquirerReadline) => void | (() => void)): void; + run(): void; + clearAll(): void; +}; +export {}; diff --git a/node_modules/@inquirer/core/dist/esm/lib/hook-engine.js b/node_modules/@inquirer/core/dist/esm/lib/hook-engine.js new file mode 100644 index 0000000000000000000000000000000000000000..3ed04320d747fe22d8667711f19ae901918f7089 --- /dev/null +++ b/node_modules/@inquirer/core/dist/esm/lib/hook-engine.js @@ -0,0 +1,110 @@ +/* eslint @typescript-eslint/no-explicit-any: ["off"] */ +import { AsyncLocalStorage, AsyncResource } from 'node:async_hooks'; +import { HookError, ValidationError } from "./errors.js"; +const hookStorage = new AsyncLocalStorage(); +function createStore(rl) { + const store = { + rl, + hooks: [], + hooksCleanup: [], + hooksEffect: [], + index: 0, + handleChange() { }, + }; + return store; +} +// Run callback in with the hook engine setup. +export function withHooks(rl, cb) { + const store = createStore(rl); + return hookStorage.run(store, () => { + function cycle(render) { + store.handleChange = () => { + store.index = 0; + render(); + }; + store.handleChange(); + } + return cb(cycle); + }); +} +// Safe getStore utility that'll return the store or throw if undefined. +function getStore() { + const store = hookStorage.getStore(); + if (!store) { + throw new HookError('[Inquirer] Hook functions can only be called from within a prompt'); + } + return store; +} +export function readline() { + return getStore().rl; +} +// Merge state updates happening within the callback function to avoid multiple renders. +export function withUpdates(fn) { + const wrapped = (...args) => { + const store = getStore(); + let shouldUpdate = false; + const oldHandleChange = store.handleChange; + store.handleChange = () => { + shouldUpdate = true; + }; + const returnValue = fn(...args); + if (shouldUpdate) { + oldHandleChange(); + } + store.handleChange = oldHandleChange; + return returnValue; + }; + return AsyncResource.bind(wrapped); +} +export function withPointer(cb) { + const store = getStore(); + const { index } = store; + const pointer = { + get() { + return store.hooks[index]; + }, + set(value) { + store.hooks[index] = value; + }, + initialized: index in store.hooks, + }; + const returnValue = cb(pointer); + store.index++; + return returnValue; +} +export function handleChange() { + getStore().handleChange(); +} +export const effectScheduler = { + queue(cb) { + const store = getStore(); + const { index } = store; + store.hooksEffect.push(() => { + store.hooksCleanup[index]?.(); + const cleanFn = cb(readline()); + if (cleanFn != null && typeof cleanFn !== 'function') { + throw new ValidationError('useEffect return value must be a cleanup function or nothing.'); + } + store.hooksCleanup[index] = cleanFn; + }); + }, + run() { + const store = getStore(); + withUpdates(() => { + store.hooksEffect.forEach((effect) => { + effect(); + }); + // Warning: Clean the hooks before exiting the `withUpdates` block. + // Failure to do so means an updates would hit the same effects again. + store.hooksEffect.length = 0; + })(); + }, + clearAll() { + const store = getStore(); + store.hooksCleanup.forEach((cleanFn) => { + cleanFn?.(); + }); + store.hooksEffect.length = 0; + store.hooksCleanup.length = 0; + }, +}; diff --git a/node_modules/@inquirer/core/dist/esm/lib/key.d.ts b/node_modules/@inquirer/core/dist/esm/lib/key.d.ts new file mode 100644 index 0000000000000000000000000000000000000000..e2ad3dc2aeb8372dd0c900c3408326339ae46045 --- /dev/null +++ b/node_modules/@inquirer/core/dist/esm/lib/key.d.ts @@ -0,0 +1,10 @@ +export type KeypressEvent = { + name: string; + ctrl: boolean; +}; +export declare const isUpKey: (key: KeypressEvent) => boolean; +export declare const isDownKey: (key: KeypressEvent) => boolean; +export declare const isSpaceKey: (key: KeypressEvent) => boolean; +export declare const isBackspaceKey: (key: KeypressEvent) => boolean; +export declare const isNumberKey: (key: KeypressEvent) => boolean; +export declare const isEnterKey: (key: KeypressEvent) => boolean; diff --git a/node_modules/@inquirer/core/dist/esm/lib/key.js b/node_modules/@inquirer/core/dist/esm/lib/key.js new file mode 100644 index 0000000000000000000000000000000000000000..36a6f5cfbadf519269ac4aa4e5175c0affe8dcc6 --- /dev/null +++ b/node_modules/@inquirer/core/dist/esm/lib/key.js @@ -0,0 +1,18 @@ +export const isUpKey = (key) => +// The up key +key.name === 'up' || + // Vim keybinding + key.name === 'k' || + // Emacs keybinding + (key.ctrl && key.name === 'p'); +export const isDownKey = (key) => +// The down key +key.name === 'down' || + // Vim keybinding + key.name === 'j' || + // Emacs keybinding + (key.ctrl && key.name === 'n'); +export const isSpaceKey = (key) => key.name === 'space'; +export const isBackspaceKey = (key) => key.name === 'backspace'; +export const isNumberKey = (key) => '1234567890'.includes(key.name); +export const isEnterKey = (key) => key.name === 'enter' || key.name === 'return'; diff --git a/node_modules/@inquirer/core/dist/esm/lib/make-theme.d.ts b/node_modules/@inquirer/core/dist/esm/lib/make-theme.d.ts new file mode 100644 index 0000000000000000000000000000000000000000..c7aae8b225c01c27c531617a09cec62ba2c1e4f6 --- /dev/null +++ b/node_modules/@inquirer/core/dist/esm/lib/make-theme.d.ts @@ -0,0 +1,3 @@ +import type { Prettify, PartialDeep } from '@inquirer/type'; +import { type Theme } from './theme.ts'; +export declare function makeTheme(...themes: ReadonlyArray>>): Prettify>; diff --git a/node_modules/@inquirer/core/dist/esm/lib/make-theme.js b/node_modules/@inquirer/core/dist/esm/lib/make-theme.js new file mode 100644 index 0000000000000000000000000000000000000000..8086da6fc8f2248b8a1ddc91eadca4b8ac2e8689 --- /dev/null +++ b/node_modules/@inquirer/core/dist/esm/lib/make-theme.js @@ -0,0 +1,30 @@ +import { defaultTheme } from "./theme.js"; +function isPlainObject(value) { + if (typeof value !== 'object' || value === null) + return false; + let proto = value; + while (Object.getPrototypeOf(proto) !== null) { + proto = Object.getPrototypeOf(proto); + } + return Object.getPrototypeOf(value) === proto; +} +function deepMerge(...objects) { + const output = {}; + for (const obj of objects) { + for (const [key, value] of Object.entries(obj)) { + const prevValue = output[key]; + output[key] = + isPlainObject(prevValue) && isPlainObject(value) + ? deepMerge(prevValue, value) + : value; + } + } + return output; +} +export function makeTheme(...themes) { + const themesToMerge = [ + defaultTheme, + ...themes.filter((theme) => theme != null), + ]; + return deepMerge(...themesToMerge); +} diff --git a/node_modules/@inquirer/core/dist/esm/lib/pagination/lines.d.ts b/node_modules/@inquirer/core/dist/esm/lib/pagination/lines.d.ts new file mode 100644 index 0000000000000000000000000000000000000000..576619594e2faf3fe0cc55ca35fd525f5d5de8ff --- /dev/null +++ b/node_modules/@inquirer/core/dist/esm/lib/pagination/lines.d.ts @@ -0,0 +1,26 @@ +import { type Prettify } from '@inquirer/type'; +/** Represents an item that's part of a layout, about to be rendered */ +export type Layout = { + item: T; + index: number; + isActive: boolean; +}; +/** + * Renders a page of items as lines that fit within the given width ensuring + * that the number of lines is not greater than the page size, and the active + * item renders at the provided position, while prioritizing that as many lines + * of the active item get rendered as possible. + */ +export declare function lines({ items, width, renderItem, active, position: requested, pageSize, }: { + items: ReadonlyArray; + /** The width of a rendered line in characters. */ + width: number; + /** Renders an item as part of a page. */ + renderItem: (layout: Prettify>) => string; + /** The index of the active item in the list of items. */ + active: number; + /** The position on the page at which to render the active item. */ + position: number; + /** The number of lines to render per page. */ + pageSize: number; +}): string[]; diff --git a/node_modules/@inquirer/core/dist/esm/lib/pagination/lines.js b/node_modules/@inquirer/core/dist/esm/lib/pagination/lines.js new file mode 100644 index 0000000000000000000000000000000000000000..071a8cd8fd0bc335874d59dd5e719cf479f49159 --- /dev/null +++ b/node_modules/@inquirer/core/dist/esm/lib/pagination/lines.js @@ -0,0 +1,59 @@ +import { breakLines } from "../utils.js"; +function split(content, width) { + return breakLines(content, width).split('\n'); +} +/** + * Rotates an array of items by an integer number of positions. + * @param {number} count The number of positions to rotate by + * @param {T[]} items The items to rotate + */ +function rotate(count, items) { + const max = items.length; + const offset = ((count % max) + max) % max; + return [...items.slice(offset), ...items.slice(0, offset)]; +} +/** + * Renders a page of items as lines that fit within the given width ensuring + * that the number of lines is not greater than the page size, and the active + * item renders at the provided position, while prioritizing that as many lines + * of the active item get rendered as possible. + */ +export function lines({ items, width, renderItem, active, position: requested, pageSize, }) { + const layouts = items.map((item, index) => ({ + item, + index, + isActive: index === active, + })); + const layoutsInPage = rotate(active - requested, layouts).slice(0, pageSize); + const renderItemAt = (index) => layoutsInPage[index] == null ? [] : split(renderItem(layoutsInPage[index]), width); + // Create a blank array of lines for the page + const pageBuffer = Array.from({ length: pageSize }); + // Render the active item to decide the position + const activeItem = renderItemAt(requested).slice(0, pageSize); + const position = requested + activeItem.length <= pageSize ? requested : pageSize - activeItem.length; + // Add the lines of the active item into the page + pageBuffer.splice(position, activeItem.length, ...activeItem); + // Fill the page under the active item + let bufferPointer = position + activeItem.length; + let layoutPointer = requested + 1; + while (bufferPointer < pageSize && layoutPointer < layoutsInPage.length) { + for (const line of renderItemAt(layoutPointer)) { + pageBuffer[bufferPointer++] = line; + if (bufferPointer >= pageSize) + break; + } + layoutPointer++; + } + // Fill the page over the active item + bufferPointer = position - 1; + layoutPointer = requested - 1; + while (bufferPointer >= 0 && layoutPointer >= 0) { + for (const line of renderItemAt(layoutPointer).reverse()) { + pageBuffer[bufferPointer--] = line; + if (bufferPointer < 0) + break; + } + layoutPointer--; + } + return pageBuffer.filter((line) => typeof line === 'string'); +} diff --git a/node_modules/@inquirer/core/dist/esm/lib/pagination/position.d.ts b/node_modules/@inquirer/core/dist/esm/lib/pagination/position.d.ts new file mode 100644 index 0000000000000000000000000000000000000000..d74870e6c816b2a2b04d02ffa3b359f4d103ec8d --- /dev/null +++ b/node_modules/@inquirer/core/dist/esm/lib/pagination/position.d.ts @@ -0,0 +1,20 @@ +/** + * Creates the next position for the active item considering a finite list of + * items to be rendered on a page. + */ +export declare function finite({ active, pageSize, total, }: { + active: number; + pageSize: number; + total: number; +}): number; +/** + * Creates the next position for the active item considering an infinitely + * looping list of items to be rendered on the page. + */ +export declare function infinite({ active, lastActive, total, pageSize, pointer, }: { + active: number; + lastActive: number; + total: number; + pageSize: number; + pointer: number; +}): number; diff --git a/node_modules/@inquirer/core/dist/esm/lib/pagination/position.js b/node_modules/@inquirer/core/dist/esm/lib/pagination/position.js new file mode 100644 index 0000000000000000000000000000000000000000..9e3cc2eb8bacca63c209c17112b913e7ef9c665e --- /dev/null +++ b/node_modules/@inquirer/core/dist/esm/lib/pagination/position.js @@ -0,0 +1,27 @@ +/** + * Creates the next position for the active item considering a finite list of + * items to be rendered on a page. + */ +export function finite({ active, pageSize, total, }) { + const middle = Math.floor(pageSize / 2); + if (total <= pageSize || active < middle) + return active; + if (active >= total - middle) + return active + pageSize - total; + return middle; +} +/** + * Creates the next position for the active item considering an infinitely + * looping list of items to be rendered on the page. + */ +export function infinite({ active, lastActive, total, pageSize, pointer, }) { + if (total <= pageSize) + return active; + // Move the position only when the user moves down, and when the + // navigation fits within a single page + if (lastActive < active && active - lastActive < pageSize) { + // Limit it to the middle of the list + return Math.min(Math.floor(pageSize / 2), pointer + active - lastActive); + } + return pointer; +} diff --git a/node_modules/@inquirer/core/dist/esm/lib/pagination/use-pagination.d.ts b/node_modules/@inquirer/core/dist/esm/lib/pagination/use-pagination.d.ts new file mode 100644 index 0000000000000000000000000000000000000000..7af6097ab2210957dea3355bde1adcd82dc0b228 --- /dev/null +++ b/node_modules/@inquirer/core/dist/esm/lib/pagination/use-pagination.d.ts @@ -0,0 +1,15 @@ +import type { Prettify } from '@inquirer/type'; +import { type Theme } from '../theme.ts'; +import { type Layout } from './lines.ts'; +export declare function usePagination({ items, active, renderItem, pageSize, loop, }: { + items: ReadonlyArray; + /** The index of the active item. */ + active: number; + /** Renders an item as part of a page. */ + renderItem: (layout: Prettify>) => string; + /** The size of the page. */ + pageSize: number; + /** Allows creating an infinitely looping list. `true` if unspecified. */ + loop?: boolean; + theme?: Theme; +}): string; diff --git a/node_modules/@inquirer/core/dist/esm/lib/pagination/use-pagination.js b/node_modules/@inquirer/core/dist/esm/lib/pagination/use-pagination.js new file mode 100644 index 0000000000000000000000000000000000000000..cd2131699740519907ae7b17962a77c448fc8e9b --- /dev/null +++ b/node_modules/@inquirer/core/dist/esm/lib/pagination/use-pagination.js @@ -0,0 +1,30 @@ +import { useRef } from "../use-ref.js"; +import { readlineWidth } from "../utils.js"; +import { lines } from "./lines.js"; +import { finite, infinite } from "./position.js"; +export function usePagination({ items, active, renderItem, pageSize, loop = true, }) { + const state = useRef({ position: 0, lastActive: 0 }); + const position = loop + ? infinite({ + active, + lastActive: state.current.lastActive, + total: items.length, + pageSize, + pointer: state.current.position, + }) + : finite({ + active, + total: items.length, + pageSize, + }); + state.current.position = position; + state.current.lastActive = active; + return lines({ + items, + width: readlineWidth(), + renderItem, + active, + position, + pageSize, + }).join('\n'); +} diff --git a/node_modules/@inquirer/core/dist/esm/lib/promise-polyfill.d.ts b/node_modules/@inquirer/core/dist/esm/lib/promise-polyfill.d.ts new file mode 100644 index 0000000000000000000000000000000000000000..0e4f74ca61d0b9ad9e7f092c436b79d137c0bb22 --- /dev/null +++ b/node_modules/@inquirer/core/dist/esm/lib/promise-polyfill.d.ts @@ -0,0 +1,7 @@ +export declare class PromisePolyfill extends Promise { + static withResolver(): { + promise: Promise; + resolve: (value: T) => void; + reject: (error: unknown) => void; + }; +} diff --git a/node_modules/@inquirer/core/dist/esm/lib/promise-polyfill.js b/node_modules/@inquirer/core/dist/esm/lib/promise-polyfill.js new file mode 100644 index 0000000000000000000000000000000000000000..621708ee2a568a6afa8207f555d1a5f1ef1791f6 --- /dev/null +++ b/node_modules/@inquirer/core/dist/esm/lib/promise-polyfill.js @@ -0,0 +1,14 @@ +// TODO: Remove this class once Node 22 becomes the minimum supported version. +export class PromisePolyfill extends Promise { + // Available starting from Node 22 + // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/withResolvers + static withResolver() { + let resolve; + let reject; + const promise = new Promise((res, rej) => { + resolve = res; + reject = rej; + }); + return { promise, resolve: resolve, reject: reject }; + } +} diff --git a/node_modules/@inquirer/core/dist/esm/lib/screen-manager.d.ts b/node_modules/@inquirer/core/dist/esm/lib/screen-manager.d.ts new file mode 100644 index 0000000000000000000000000000000000000000..de4c1e00fb09d30464dbebf43b87a04c8a9b8e8f --- /dev/null +++ b/node_modules/@inquirer/core/dist/esm/lib/screen-manager.d.ts @@ -0,0 +1,14 @@ +import type { InquirerReadline } from '@inquirer/type'; +export default class ScreenManager { + private height; + private extraLinesUnderPrompt; + private cursorPos; + private readonly rl; + constructor(rl: InquirerReadline); + write(content: string): void; + render(content: string, bottomContent?: string): void; + checkCursorPos(): void; + done({ clearContent }: { + clearContent: boolean; + }): void; +} diff --git a/node_modules/@inquirer/core/dist/esm/lib/screen-manager.js b/node_modules/@inquirer/core/dist/esm/lib/screen-manager.js new file mode 100644 index 0000000000000000000000000000000000000000..b77aad69a02d0c4523f3dcb68dab5acca4676a8a --- /dev/null +++ b/node_modules/@inquirer/core/dist/esm/lib/screen-manager.js @@ -0,0 +1,84 @@ +import { stripVTControlCharacters } from 'node:util'; +import ansiEscapes from 'ansi-escapes'; +import { breakLines, readlineWidth } from "./utils.js"; +const height = (content) => content.split('\n').length; +const lastLine = (content) => content.split('\n').pop() ?? ''; +function cursorDown(n) { + return n > 0 ? ansiEscapes.cursorDown(n) : ''; +} +export default class ScreenManager { + // These variables are keeping information to allow correct prompt re-rendering + height = 0; + extraLinesUnderPrompt = 0; + cursorPos; + rl; + constructor(rl) { + this.rl = rl; + this.cursorPos = rl.getCursorPos(); + } + write(content) { + this.rl.output.unmute(); + this.rl.output.write(content); + this.rl.output.mute(); + } + render(content, bottomContent = '') { + // Write message to screen and setPrompt to control backspace + const promptLine = lastLine(content); + const rawPromptLine = stripVTControlCharacters(promptLine); + // Remove the rl.line from our prompt. We can't rely on the content of + // rl.line (mainly because of the password prompt), so just rely on it's + // length. + let prompt = rawPromptLine; + if (this.rl.line.length > 0) { + prompt = prompt.slice(0, -this.rl.line.length); + } + this.rl.setPrompt(prompt); + // SetPrompt will change cursor position, now we can get correct value + this.cursorPos = this.rl.getCursorPos(); + const width = readlineWidth(); + content = breakLines(content, width); + bottomContent = breakLines(bottomContent, width); + // Manually insert an extra line if we're at the end of the line. + // This prevent the cursor from appearing at the beginning of the + // current line. + if (rawPromptLine.length % width === 0) { + content += '\n'; + } + let output = content + (bottomContent ? '\n' + bottomContent : ''); + /** + * Re-adjust the cursor at the correct position. + */ + // We need to consider parts of the prompt under the cursor as part of the bottom + // content in order to correctly cleanup and re-render. + const promptLineUpDiff = Math.floor(rawPromptLine.length / width) - this.cursorPos.rows; + const bottomContentHeight = promptLineUpDiff + (bottomContent ? height(bottomContent) : 0); + // Return cursor to the input position (on top of the bottomContent) + if (bottomContentHeight > 0) + output += ansiEscapes.cursorUp(bottomContentHeight); + // Return cursor to the initial left offset. + output += ansiEscapes.cursorTo(this.cursorPos.cols); + /** + * Render and store state for future re-rendering + */ + this.write(cursorDown(this.extraLinesUnderPrompt) + + ansiEscapes.eraseLines(this.height) + + output); + this.extraLinesUnderPrompt = bottomContentHeight; + this.height = height(output); + } + checkCursorPos() { + const cursorPos = this.rl.getCursorPos(); + if (cursorPos.cols !== this.cursorPos.cols) { + this.write(ansiEscapes.cursorTo(cursorPos.cols)); + this.cursorPos = cursorPos; + } + } + done({ clearContent }) { + this.rl.setPrompt(''); + let output = cursorDown(this.extraLinesUnderPrompt); + output += clearContent ? ansiEscapes.eraseLines(this.height) : '\n'; + output += ansiEscapes.cursorShow; + this.write(output); + this.rl.close(); + } +} diff --git a/node_modules/@inquirer/core/dist/esm/lib/theme.d.ts b/node_modules/@inquirer/core/dist/esm/lib/theme.d.ts new file mode 100644 index 0000000000000000000000000000000000000000..f1529b0a309a88409d09ba766467bb51742cb652 --- /dev/null +++ b/node_modules/@inquirer/core/dist/esm/lib/theme.d.ts @@ -0,0 +1,155 @@ +import type { Prettify } from '@inquirer/type'; +/** + * Union type representing the possible statuses of a prompt. + * + * - `'loading'`: The prompt is currently loading. + * - `'idle'`: The prompt is loaded and currently waiting for the user to + * submit an answer. + * - `'done'`: The user has submitted an answer and the prompt is finished. + * - `string`: Any other string: The prompt is in a custom state. + */ +export type Status = 'loading' | 'idle' | 'done' | (string & {}); +type DefaultTheme = { + /** + * Prefix to prepend to the message. If a function is provided, it will be + * called with the current status of the prompt, and the return value will be + * used as the prefix. + * + * @remarks + * If `status === 'loading'`, this property is ignored and the spinner (styled + * by the `spinner` property) will be displayed instead. + * + * @defaultValue + * ```ts + * // import colors from 'yoctocolors-cjs'; + * (status) => status === 'done' ? colors.green('✔') : colors.blue('?') + * ``` + */ + prefix: string | Prettify, 'loading'>>; + /** + * Configuration for the spinner that is displayed when the prompt is in the + * `'loading'` state. + * + * We recommend the use of {@link https://github.com/sindresorhus/cli-spinners|cli-spinners} for a list of available spinners. + */ + spinner: { + /** + * The time interval between frames, in milliseconds. + * + * @defaultValue + * ```ts + * 80 + * ``` + */ + interval: number; + /** + * A list of frames to show for the spinner. + * + * @defaultValue + * ```ts + * ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'] + * ``` + */ + frames: string[]; + }; + /** + * Object containing functions to style different parts of the prompt. + */ + style: { + /** + * Style to apply to the user's answer once it has been submitted. + * + * @param text - The user's answer. + * @returns The styled answer. + * + * @defaultValue + * ```ts + * // import colors from 'yoctocolors-cjs'; + * (text) => colors.cyan(text) + * ``` + */ + answer: (text: string) => string; + /** + * Style to apply to the message displayed to the user. + * + * @param text - The message to style. + * @param status - The current status of the prompt. + * @returns The styled message. + * + * @defaultValue + * ```ts + * // import colors from 'yoctocolors-cjs'; + * (text, status) => colors.bold(text) + * ``` + */ + message: (text: string, status: Status) => string; + /** + * Style to apply to error messages. + * + * @param text - The error message. + * @returns The styled error message. + * + * @defaultValue + * ```ts + * // import colors from 'yoctocolors-cjs'; + * (text) => colors.red(`> ${text}`) + * ``` + */ + error: (text: string) => string; + /** + * Style to apply to the default answer when one is provided. + * + * @param text - The default answer. + * @returns The styled default answer. + * + * @defaultValue + * ```ts + * // import colors from 'yoctocolors-cjs'; + * (text) => colors.dim(`(${text})`) + * ``` + */ + defaultAnswer: (text: string) => string; + /** + * Style to apply to help text. + * + * @param text - The help text. + * @returns The styled help text. + * + * @defaultValue + * ```ts + * // import colors from 'yoctocolors-cjs'; + * (text) => colors.dim(text) + * ``` + */ + help: (text: string) => string; + /** + * Style to apply to highlighted text. + * + * @param text - The text to highlight. + * @returns The highlighted text. + * + * @defaultValue + * ```ts + * // import colors from 'yoctocolors-cjs'; + * (text) => colors.cyan(text) + * ``` + */ + highlight: (text: string) => string; + /** + * Style to apply to keyboard keys referred to in help texts. + * + * @param text - The key to style. + * @returns The styled key. + * + * @defaultValue + * ```ts + * // import colors from 'yoctocolors-cjs'; + * (text) => colors.cyan(colors.bold(`<${text}>`)) + * ``` + */ + key: (text: string) => string; + }; +}; +export type Theme = Prettify; +export declare const defaultTheme: DefaultTheme; +export {}; diff --git a/node_modules/@inquirer/core/dist/esm/lib/theme.js b/node_modules/@inquirer/core/dist/esm/lib/theme.js new file mode 100644 index 0000000000000000000000000000000000000000..d52a2da8abda902beda9427a7e1f4a40914f6f9c --- /dev/null +++ b/node_modules/@inquirer/core/dist/esm/lib/theme.js @@ -0,0 +1,22 @@ +import colors from 'yoctocolors-cjs'; +import figures from '@inquirer/figures'; +export const defaultTheme = { + prefix: { + idle: colors.blue('?'), + // TODO: use figure + done: colors.green(figures.tick), + }, + spinner: { + interval: 80, + frames: ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'].map((frame) => colors.yellow(frame)), + }, + style: { + answer: colors.cyan, + message: colors.bold, + error: (text) => colors.red(`> ${text}`), + defaultAnswer: (text) => colors.dim(`(${text})`), + help: colors.dim, + highlight: colors.cyan, + key: (text) => colors.cyan(colors.bold(`<${text}>`)), + }, +}; diff --git a/node_modules/@inquirer/core/dist/esm/lib/use-effect.d.ts b/node_modules/@inquirer/core/dist/esm/lib/use-effect.d.ts new file mode 100644 index 0000000000000000000000000000000000000000..abee90639f181a2a64ec31dd47e3920586edc9ad --- /dev/null +++ b/node_modules/@inquirer/core/dist/esm/lib/use-effect.d.ts @@ -0,0 +1,2 @@ +import type { InquirerReadline } from '@inquirer/type'; +export declare function useEffect(cb: (rl: InquirerReadline) => void | (() => void), depArray: ReadonlyArray): void; diff --git a/node_modules/@inquirer/core/dist/esm/lib/use-effect.js b/node_modules/@inquirer/core/dist/esm/lib/use-effect.js new file mode 100644 index 0000000000000000000000000000000000000000..1c1a9cabf040acee58e0f4fa2777408a5a2eae3f --- /dev/null +++ b/node_modules/@inquirer/core/dist/esm/lib/use-effect.js @@ -0,0 +1,11 @@ +import { withPointer, effectScheduler } from "./hook-engine.js"; +export function useEffect(cb, depArray) { + withPointer((pointer) => { + const oldDeps = pointer.get(); + const hasChanged = !Array.isArray(oldDeps) || depArray.some((dep, i) => !Object.is(dep, oldDeps[i])); + if (hasChanged) { + effectScheduler.queue(cb); + } + pointer.set(depArray); + }); +} diff --git a/node_modules/@inquirer/core/dist/esm/lib/use-keypress.d.ts b/node_modules/@inquirer/core/dist/esm/lib/use-keypress.d.ts new file mode 100644 index 0000000000000000000000000000000000000000..ccdeefaf26be3e47e9c2459f23707e7b50af0ddf --- /dev/null +++ b/node_modules/@inquirer/core/dist/esm/lib/use-keypress.d.ts @@ -0,0 +1,3 @@ +import { type InquirerReadline } from '@inquirer/type'; +import { type KeypressEvent } from './key.ts'; +export declare function useKeypress(userHandler: (event: KeypressEvent, rl: InquirerReadline) => void | Promise): void; diff --git a/node_modules/@inquirer/core/dist/esm/lib/use-keypress.js b/node_modules/@inquirer/core/dist/esm/lib/use-keypress.js new file mode 100644 index 0000000000000000000000000000000000000000..4ff9b89be42e5bd69aa3062cee4e3a333625085a --- /dev/null +++ b/node_modules/@inquirer/core/dist/esm/lib/use-keypress.js @@ -0,0 +1,20 @@ +import { useRef } from "./use-ref.js"; +import { useEffect } from "./use-effect.js"; +import { withUpdates } from "./hook-engine.js"; +export function useKeypress(userHandler) { + const signal = useRef(userHandler); + signal.current = userHandler; + useEffect((rl) => { + let ignore = false; + const handler = withUpdates((_input, event) => { + if (ignore) + return; + void signal.current(event, rl); + }); + rl.input.on('keypress', handler); + return () => { + ignore = true; + rl.input.removeListener('keypress', handler); + }; + }, []); +} diff --git a/node_modules/@inquirer/core/dist/esm/lib/use-memo.d.ts b/node_modules/@inquirer/core/dist/esm/lib/use-memo.d.ts new file mode 100644 index 0000000000000000000000000000000000000000..19d164433d1f17a0bb9e0557e8b9eedc307271f7 --- /dev/null +++ b/node_modules/@inquirer/core/dist/esm/lib/use-memo.d.ts @@ -0,0 +1 @@ +export declare function useMemo(fn: () => Value, dependencies: ReadonlyArray): Value; diff --git a/node_modules/@inquirer/core/dist/esm/lib/use-memo.js b/node_modules/@inquirer/core/dist/esm/lib/use-memo.js new file mode 100644 index 0000000000000000000000000000000000000000..0395f4ed1b4c55362d1b59b6579f5f0e65e164d4 --- /dev/null +++ b/node_modules/@inquirer/core/dist/esm/lib/use-memo.js @@ -0,0 +1,14 @@ +import { withPointer } from "./hook-engine.js"; +export function useMemo(fn, dependencies) { + return withPointer((pointer) => { + const prev = pointer.get(); + if (!prev || + prev.dependencies.length !== dependencies.length || + prev.dependencies.some((dep, i) => dep !== dependencies[i])) { + const value = fn(); + pointer.set({ value, dependencies }); + return value; + } + return prev.value; + }); +} diff --git a/node_modules/@inquirer/core/dist/esm/lib/use-prefix.d.ts b/node_modules/@inquirer/core/dist/esm/lib/use-prefix.d.ts new file mode 100644 index 0000000000000000000000000000000000000000..db1dabb13a37372d17b7ec3f944586ffc3916c17 --- /dev/null +++ b/node_modules/@inquirer/core/dist/esm/lib/use-prefix.d.ts @@ -0,0 +1,5 @@ +import type { Theme, Status } from './theme.ts'; +export declare function usePrefix({ status, theme, }: { + status?: Status; + theme?: Theme; +}): string; diff --git a/node_modules/@inquirer/core/dist/esm/lib/use-prefix.js b/node_modules/@inquirer/core/dist/esm/lib/use-prefix.js new file mode 100644 index 0000000000000000000000000000000000000000..b95d38e8fc11774a5a5f89a043de3594d790fa3d --- /dev/null +++ b/node_modules/@inquirer/core/dist/esm/lib/use-prefix.js @@ -0,0 +1,36 @@ +import { AsyncResource } from 'node:async_hooks'; +import { useState } from "./use-state.js"; +import { useEffect } from "./use-effect.js"; +import { makeTheme } from "./make-theme.js"; +export function usePrefix({ status = 'idle', theme, }) { + const [showLoader, setShowLoader] = useState(false); + const [tick, setTick] = useState(0); + const { prefix, spinner } = makeTheme(theme); + useEffect(() => { + if (status === 'loading') { + let tickInterval; + let inc = -1; + // Delay displaying spinner by 300ms, to avoid flickering + const delayTimeout = setTimeout(AsyncResource.bind(() => { + setShowLoader(true); + tickInterval = setInterval(AsyncResource.bind(() => { + inc = inc + 1; + setTick(inc % spinner.frames.length); + }), spinner.interval); + }), 300); + return () => { + clearTimeout(delayTimeout); + clearInterval(tickInterval); + }; + } + else { + setShowLoader(false); + } + }, [status]); + if (showLoader) { + return spinner.frames[tick]; + } + // There's a delay before we show the loader. So we want to ignore `loading` here, and pass idle instead. + const iconName = status === 'loading' ? 'idle' : status; + return typeof prefix === 'string' ? prefix : (prefix[iconName] ?? prefix['idle']); +} diff --git a/node_modules/@inquirer/core/dist/esm/lib/use-ref.d.ts b/node_modules/@inquirer/core/dist/esm/lib/use-ref.d.ts new file mode 100644 index 0000000000000000000000000000000000000000..be7126b9e8784bebfe6526bdca70895a388a0c16 --- /dev/null +++ b/node_modules/@inquirer/core/dist/esm/lib/use-ref.d.ts @@ -0,0 +1,6 @@ +export declare function useRef(val: Value): { + current: Value; +}; +export declare function useRef(val?: Value): { + current: Value | undefined; +}; diff --git a/node_modules/@inquirer/core/dist/esm/lib/use-ref.js b/node_modules/@inquirer/core/dist/esm/lib/use-ref.js new file mode 100644 index 0000000000000000000000000000000000000000..a0255614e16b311f40ce53174a4106f3f8e6612f --- /dev/null +++ b/node_modules/@inquirer/core/dist/esm/lib/use-ref.js @@ -0,0 +1,4 @@ +import { useState } from "./use-state.js"; +export function useRef(val) { + return useState({ current: val })[0]; +} diff --git a/node_modules/@inquirer/core/dist/esm/lib/use-state.d.ts b/node_modules/@inquirer/core/dist/esm/lib/use-state.d.ts new file mode 100644 index 0000000000000000000000000000000000000000..fba0b621f9dce863bbd33d7dac60cf19894d7a9f --- /dev/null +++ b/node_modules/@inquirer/core/dist/esm/lib/use-state.d.ts @@ -0,0 +1,4 @@ +type NotFunction = T extends (...args: never) => unknown ? never : T; +export declare function useState(defaultValue: NotFunction | (() => Value)): [Value, (newValue: Value) => void]; +export declare function useState(defaultValue?: NotFunction | (() => Value)): [Value | undefined, (newValue?: Value) => void]; +export {}; diff --git a/node_modules/@inquirer/core/dist/esm/lib/use-state.js b/node_modules/@inquirer/core/dist/esm/lib/use-state.js new file mode 100644 index 0000000000000000000000000000000000000000..2fa60c38b666e2737169aa217b18b42ba50335e9 --- /dev/null +++ b/node_modules/@inquirer/core/dist/esm/lib/use-state.js @@ -0,0 +1,19 @@ +import { withPointer, handleChange } from "./hook-engine.js"; +export function useState(defaultValue) { + return withPointer((pointer) => { + const setFn = (newValue) => { + // Noop if the value is still the same. + if (pointer.get() !== newValue) { + pointer.set(newValue); + // Trigger re-render + handleChange(); + } + }; + if (pointer.initialized) { + return [pointer.get(), setFn]; + } + const value = typeof defaultValue === 'function' ? defaultValue() : defaultValue; + pointer.set(value); + return [value, setFn]; + }); +} diff --git a/node_modules/@inquirer/core/dist/esm/lib/utils.d.ts b/node_modules/@inquirer/core/dist/esm/lib/utils.d.ts new file mode 100644 index 0000000000000000000000000000000000000000..14f8fc438e8a481cf90a4c071b18751e26f9f4d0 --- /dev/null +++ b/node_modules/@inquirer/core/dist/esm/lib/utils.d.ts @@ -0,0 +1,13 @@ +/** + * Force line returns at specific width. This function is ANSI code friendly and it'll + * ignore invisible codes during width calculation. + * @param {string} content + * @param {number} width + * @return {string} + */ +export declare function breakLines(content: string, width: number): string; +/** + * Returns the width of the active readline, or 80 as default value. + * @returns {number} + */ +export declare function readlineWidth(): number; diff --git a/node_modules/@inquirer/core/dist/esm/lib/utils.js b/node_modules/@inquirer/core/dist/esm/lib/utils.js new file mode 100644 index 0000000000000000000000000000000000000000..259eb07eaa4b41c6f13d9a3f8acca96f540f1788 --- /dev/null +++ b/node_modules/@inquirer/core/dist/esm/lib/utils.js @@ -0,0 +1,25 @@ +import cliWidth from 'cli-width'; +import wrapAnsi from 'wrap-ansi'; +import { readline } from "./hook-engine.js"; +/** + * Force line returns at specific width. This function is ANSI code friendly and it'll + * ignore invisible codes during width calculation. + * @param {string} content + * @param {number} width + * @return {string} + */ +export function breakLines(content, width) { + return content + .split('\n') + .flatMap((line) => wrapAnsi(line, width, { trim: false, hard: true }) + .split('\n') + .map((str) => str.trimEnd())) + .join('\n'); +} +/** + * Returns the width of the active readline, or 80 as default value. + * @returns {number} + */ +export function readlineWidth() { + return cliWidth({ defaultWidth: 80, output: readline().output }); +} diff --git a/node_modules/@inquirer/core/dist/esm/package.json b/node_modules/@inquirer/core/dist/esm/package.json new file mode 100644 index 0000000000000000000000000000000000000000..3dbc1ca591c0557e35b6004aeba250e6a70b56e3 --- /dev/null +++ b/node_modules/@inquirer/core/dist/esm/package.json @@ -0,0 +1,3 @@ +{ + "type": "module" +} diff --git a/node_modules/@inquirer/core/package.json b/node_modules/@inquirer/core/package.json new file mode 100644 index 0000000000000000000000000000000000000000..6c1c23a6ab965f6ba2bcfa6c39e7aae32cdfd638 --- /dev/null +++ b/node_modules/@inquirer/core/package.json @@ -0,0 +1,119 @@ +{ + "name": "@inquirer/core", + "version": "10.1.10", + "description": "Core Inquirer prompt API", + "keywords": [ + "answer", + "answers", + "ask", + "base", + "cli", + "command", + "command-line", + "confirm", + "enquirer", + "generate", + "generator", + "hyper", + "input", + "inquire", + "inquirer", + "interface", + "iterm", + "javascript", + "menu", + "node", + "nodejs", + "prompt", + "promptly", + "prompts", + "question", + "readline", + "scaffold", + "scaffolder", + "scaffolding", + "stdin", + "stdout", + "terminal", + "tty", + "ui", + "yeoman", + "yo", + "zsh" + ], + "homepage": "https://github.com/SBoudrias/Inquirer.js/blob/main/packages/core/README.md", + "repository": { + "type": "git", + "url": "https://github.com/SBoudrias/Inquirer.js.git" + }, + "license": "MIT", + "author": "Simon Boudrias ", + "sideEffects": false, + "type": "module", + "exports": { + "./package.json": "./package.json", + ".": { + "import": { + "types": "./dist/esm/index.d.ts", + "default": "./dist/esm/index.js" + }, + "require": { + "types": "./dist/commonjs/index.d.ts", + "default": "./dist/commonjs/index.js" + } + } + }, + "main": "./dist/commonjs/index.js", + "module": "./dist/esm/index.js", + "types": "./dist/commonjs/index.d.ts", + "files": [ + "dist" + ], + "scripts": { + "attw": "attw --pack", + "tsc": "tshy" + }, + "dependencies": { + "@inquirer/figures": "^1.0.11", + "@inquirer/type": "^3.0.6", + "ansi-escapes": "^4.3.2", + "cli-width": "^4.1.0", + "mute-stream": "^2.0.0", + "signal-exit": "^4.1.0", + "wrap-ansi": "^6.2.0", + "yoctocolors-cjs": "^2.1.2" + }, + "devDependencies": { + "@arethetypeswrong/cli": "^0.17.4", + "@inquirer/testing": "^2.1.46", + "@repo/tsconfig": "workspace:*", + "@types/mute-stream": "^0.0.4", + "@types/node": "^22.14.0", + "@types/wrap-ansi": "^3.0.0", + "tshy": "^3.0.2" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + }, + "engines": { + "node": ">=18" + }, + "publishConfig": { + "access": "public" + }, + "tshy": { + "exclude": [ + "src/**/*.test.ts" + ], + "exports": { + "./package.json": "./package.json", + ".": "./src/index.ts" + } + }, + "gitHead": "d367155a8d64d8b3e93f9c763adccf708aedc8a8" +} diff --git a/node_modules/@inquirer/figures/LICENSE b/node_modules/@inquirer/figures/LICENSE new file mode 100644 index 0000000000000000000000000000000000000000..f7186988726152b8dfb1bbafe940a712da142e3e --- /dev/null +++ b/node_modules/@inquirer/figures/LICENSE @@ -0,0 +1,22 @@ +Copyright (c) 2025 Simon Boudrias + +Permission is hereby granted, free of charge, to any person +obtaining a copy of this software and associated documentation +files (the "Software"), to deal in the Software without +restriction, including without limitation the rights to use, +copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. diff --git a/node_modules/@inquirer/figures/dist/commonjs/index.d.ts b/node_modules/@inquirer/figures/dist/commonjs/index.d.ts new file mode 100644 index 0000000000000000000000000000000000000000..f8202e508b5f7c560c1c0ae5ad16bf4ecc93b877 --- /dev/null +++ b/node_modules/@inquirer/figures/dist/commonjs/index.d.ts @@ -0,0 +1,465 @@ +export declare const mainSymbols: { + tick: string; + info: string; + warning: string; + cross: string; + squareSmall: string; + squareSmallFilled: string; + circle: string; + circleFilled: string; + circleDotted: string; + circleDouble: string; + circleCircle: string; + circleCross: string; + circlePipe: string; + radioOn: string; + radioOff: string; + checkboxOn: string; + checkboxOff: string; + checkboxCircleOn: string; + checkboxCircleOff: string; + pointer: string; + triangleUpOutline: string; + triangleLeft: string; + triangleRight: string; + lozenge: string; + lozengeOutline: string; + hamburger: string; + smiley: string; + mustache: string; + star: string; + play: string; + nodejs: string; + oneSeventh: string; + oneNinth: string; + oneTenth: string; + circleQuestionMark: string; + questionMarkPrefix: string; + square: string; + squareDarkShade: string; + squareMediumShade: string; + squareLightShade: string; + squareTop: string; + squareBottom: string; + squareLeft: string; + squareRight: string; + squareCenter: string; + bullet: string; + dot: string; + ellipsis: string; + pointerSmall: string; + triangleUp: string; + triangleUpSmall: string; + triangleDown: string; + triangleDownSmall: string; + triangleLeftSmall: string; + triangleRightSmall: string; + home: string; + heart: string; + musicNote: string; + musicNoteBeamed: string; + arrowUp: string; + arrowDown: string; + arrowLeft: string; + arrowRight: string; + arrowLeftRight: string; + arrowUpDown: string; + almostEqual: string; + notEqual: string; + lessOrEqual: string; + greaterOrEqual: string; + identical: string; + infinity: string; + subscriptZero: string; + subscriptOne: string; + subscriptTwo: string; + subscriptThree: string; + subscriptFour: string; + subscriptFive: string; + subscriptSix: string; + subscriptSeven: string; + subscriptEight: string; + subscriptNine: string; + oneHalf: string; + oneThird: string; + oneQuarter: string; + oneFifth: string; + oneSixth: string; + oneEighth: string; + twoThirds: string; + twoFifths: string; + threeQuarters: string; + threeFifths: string; + threeEighths: string; + fourFifths: string; + fiveSixths: string; + fiveEighths: string; + sevenEighths: string; + line: string; + lineBold: string; + lineDouble: string; + lineDashed0: string; + lineDashed1: string; + lineDashed2: string; + lineDashed3: string; + lineDashed4: string; + lineDashed5: string; + lineDashed6: string; + lineDashed7: string; + lineDashed8: string; + lineDashed9: string; + lineDashed10: string; + lineDashed11: string; + lineDashed12: string; + lineDashed13: string; + lineDashed14: string; + lineDashed15: string; + lineVertical: string; + lineVerticalBold: string; + lineVerticalDouble: string; + lineVerticalDashed0: string; + lineVerticalDashed1: string; + lineVerticalDashed2: string; + lineVerticalDashed3: string; + lineVerticalDashed4: string; + lineVerticalDashed5: string; + lineVerticalDashed6: string; + lineVerticalDashed7: string; + lineVerticalDashed8: string; + lineVerticalDashed9: string; + lineVerticalDashed10: string; + lineVerticalDashed11: string; + lineDownLeft: string; + lineDownLeftArc: string; + lineDownBoldLeftBold: string; + lineDownBoldLeft: string; + lineDownLeftBold: string; + lineDownDoubleLeftDouble: string; + lineDownDoubleLeft: string; + lineDownLeftDouble: string; + lineDownRight: string; + lineDownRightArc: string; + lineDownBoldRightBold: string; + lineDownBoldRight: string; + lineDownRightBold: string; + lineDownDoubleRightDouble: string; + lineDownDoubleRight: string; + lineDownRightDouble: string; + lineUpLeft: string; + lineUpLeftArc: string; + lineUpBoldLeftBold: string; + lineUpBoldLeft: string; + lineUpLeftBold: string; + lineUpDoubleLeftDouble: string; + lineUpDoubleLeft: string; + lineUpLeftDouble: string; + lineUpRight: string; + lineUpRightArc: string; + lineUpBoldRightBold: string; + lineUpBoldRight: string; + lineUpRightBold: string; + lineUpDoubleRightDouble: string; + lineUpDoubleRight: string; + lineUpRightDouble: string; + lineUpDownLeft: string; + lineUpBoldDownBoldLeftBold: string; + lineUpBoldDownBoldLeft: string; + lineUpDownLeftBold: string; + lineUpBoldDownLeftBold: string; + lineUpDownBoldLeftBold: string; + lineUpDownBoldLeft: string; + lineUpBoldDownLeft: string; + lineUpDoubleDownDoubleLeftDouble: string; + lineUpDoubleDownDoubleLeft: string; + lineUpDownLeftDouble: string; + lineUpDownRight: string; + lineUpBoldDownBoldRightBold: string; + lineUpBoldDownBoldRight: string; + lineUpDownRightBold: string; + lineUpBoldDownRightBold: string; + lineUpDownBoldRightBold: string; + lineUpDownBoldRight: string; + lineUpBoldDownRight: string; + lineUpDoubleDownDoubleRightDouble: string; + lineUpDoubleDownDoubleRight: string; + lineUpDownRightDouble: string; + lineDownLeftRight: string; + lineDownBoldLeftBoldRightBold: string; + lineDownLeftBoldRightBold: string; + lineDownBoldLeftRight: string; + lineDownBoldLeftBoldRight: string; + lineDownBoldLeftRightBold: string; + lineDownLeftRightBold: string; + lineDownLeftBoldRight: string; + lineDownDoubleLeftDoubleRightDouble: string; + lineDownDoubleLeftRight: string; + lineDownLeftDoubleRightDouble: string; + lineUpLeftRight: string; + lineUpBoldLeftBoldRightBold: string; + lineUpLeftBoldRightBold: string; + lineUpBoldLeftRight: string; + lineUpBoldLeftBoldRight: string; + lineUpBoldLeftRightBold: string; + lineUpLeftRightBold: string; + lineUpLeftBoldRight: string; + lineUpDoubleLeftDoubleRightDouble: string; + lineUpDoubleLeftRight: string; + lineUpLeftDoubleRightDouble: string; + lineUpDownLeftRight: string; + lineUpBoldDownBoldLeftBoldRightBold: string; + lineUpDownBoldLeftBoldRightBold: string; + lineUpBoldDownLeftBoldRightBold: string; + lineUpBoldDownBoldLeftRightBold: string; + lineUpBoldDownBoldLeftBoldRight: string; + lineUpBoldDownLeftRight: string; + lineUpDownBoldLeftRight: string; + lineUpDownLeftBoldRight: string; + lineUpDownLeftRightBold: string; + lineUpBoldDownBoldLeftRight: string; + lineUpDownLeftBoldRightBold: string; + lineUpBoldDownLeftBoldRight: string; + lineUpBoldDownLeftRightBold: string; + lineUpDownBoldLeftBoldRight: string; + lineUpDownBoldLeftRightBold: string; + lineUpDoubleDownDoubleLeftDoubleRightDouble: string; + lineUpDoubleDownDoubleLeftRight: string; + lineUpDownLeftDoubleRightDouble: string; + lineCross: string; + lineBackslash: string; + lineSlash: string; +}; +export declare const fallbackSymbols: Record; +declare const figures: { + tick: string; + info: string; + warning: string; + cross: string; + squareSmall: string; + squareSmallFilled: string; + circle: string; + circleFilled: string; + circleDotted: string; + circleDouble: string; + circleCircle: string; + circleCross: string; + circlePipe: string; + radioOn: string; + radioOff: string; + checkboxOn: string; + checkboxOff: string; + checkboxCircleOn: string; + checkboxCircleOff: string; + pointer: string; + triangleUpOutline: string; + triangleLeft: string; + triangleRight: string; + lozenge: string; + lozengeOutline: string; + hamburger: string; + smiley: string; + mustache: string; + star: string; + play: string; + nodejs: string; + oneSeventh: string; + oneNinth: string; + oneTenth: string; + circleQuestionMark: string; + questionMarkPrefix: string; + square: string; + squareDarkShade: string; + squareMediumShade: string; + squareLightShade: string; + squareTop: string; + squareBottom: string; + squareLeft: string; + squareRight: string; + squareCenter: string; + bullet: string; + dot: string; + ellipsis: string; + pointerSmall: string; + triangleUp: string; + triangleUpSmall: string; + triangleDown: string; + triangleDownSmall: string; + triangleLeftSmall: string; + triangleRightSmall: string; + home: string; + heart: string; + musicNote: string; + musicNoteBeamed: string; + arrowUp: string; + arrowDown: string; + arrowLeft: string; + arrowRight: string; + arrowLeftRight: string; + arrowUpDown: string; + almostEqual: string; + notEqual: string; + lessOrEqual: string; + greaterOrEqual: string; + identical: string; + infinity: string; + subscriptZero: string; + subscriptOne: string; + subscriptTwo: string; + subscriptThree: string; + subscriptFour: string; + subscriptFive: string; + subscriptSix: string; + subscriptSeven: string; + subscriptEight: string; + subscriptNine: string; + oneHalf: string; + oneThird: string; + oneQuarter: string; + oneFifth: string; + oneSixth: string; + oneEighth: string; + twoThirds: string; + twoFifths: string; + threeQuarters: string; + threeFifths: string; + threeEighths: string; + fourFifths: string; + fiveSixths: string; + fiveEighths: string; + sevenEighths: string; + line: string; + lineBold: string; + lineDouble: string; + lineDashed0: string; + lineDashed1: string; + lineDashed2: string; + lineDashed3: string; + lineDashed4: string; + lineDashed5: string; + lineDashed6: string; + lineDashed7: string; + lineDashed8: string; + lineDashed9: string; + lineDashed10: string; + lineDashed11: string; + lineDashed12: string; + lineDashed13: string; + lineDashed14: string; + lineDashed15: string; + lineVertical: string; + lineVerticalBold: string; + lineVerticalDouble: string; + lineVerticalDashed0: string; + lineVerticalDashed1: string; + lineVerticalDashed2: string; + lineVerticalDashed3: string; + lineVerticalDashed4: string; + lineVerticalDashed5: string; + lineVerticalDashed6: string; + lineVerticalDashed7: string; + lineVerticalDashed8: string; + lineVerticalDashed9: string; + lineVerticalDashed10: string; + lineVerticalDashed11: string; + lineDownLeft: string; + lineDownLeftArc: string; + lineDownBoldLeftBold: string; + lineDownBoldLeft: string; + lineDownLeftBold: string; + lineDownDoubleLeftDouble: string; + lineDownDoubleLeft: string; + lineDownLeftDouble: string; + lineDownRight: string; + lineDownRightArc: string; + lineDownBoldRightBold: string; + lineDownBoldRight: string; + lineDownRightBold: string; + lineDownDoubleRightDouble: string; + lineDownDoubleRight: string; + lineDownRightDouble: string; + lineUpLeft: string; + lineUpLeftArc: string; + lineUpBoldLeftBold: string; + lineUpBoldLeft: string; + lineUpLeftBold: string; + lineUpDoubleLeftDouble: string; + lineUpDoubleLeft: string; + lineUpLeftDouble: string; + lineUpRight: string; + lineUpRightArc: string; + lineUpBoldRightBold: string; + lineUpBoldRight: string; + lineUpRightBold: string; + lineUpDoubleRightDouble: string; + lineUpDoubleRight: string; + lineUpRightDouble: string; + lineUpDownLeft: string; + lineUpBoldDownBoldLeftBold: string; + lineUpBoldDownBoldLeft: string; + lineUpDownLeftBold: string; + lineUpBoldDownLeftBold: string; + lineUpDownBoldLeftBold: string; + lineUpDownBoldLeft: string; + lineUpBoldDownLeft: string; + lineUpDoubleDownDoubleLeftDouble: string; + lineUpDoubleDownDoubleLeft: string; + lineUpDownLeftDouble: string; + lineUpDownRight: string; + lineUpBoldDownBoldRightBold: string; + lineUpBoldDownBoldRight: string; + lineUpDownRightBold: string; + lineUpBoldDownRightBold: string; + lineUpDownBoldRightBold: string; + lineUpDownBoldRight: string; + lineUpBoldDownRight: string; + lineUpDoubleDownDoubleRightDouble: string; + lineUpDoubleDownDoubleRight: string; + lineUpDownRightDouble: string; + lineDownLeftRight: string; + lineDownBoldLeftBoldRightBold: string; + lineDownLeftBoldRightBold: string; + lineDownBoldLeftRight: string; + lineDownBoldLeftBoldRight: string; + lineDownBoldLeftRightBold: string; + lineDownLeftRightBold: string; + lineDownLeftBoldRight: string; + lineDownDoubleLeftDoubleRightDouble: string; + lineDownDoubleLeftRight: string; + lineDownLeftDoubleRightDouble: string; + lineUpLeftRight: string; + lineUpBoldLeftBoldRightBold: string; + lineUpLeftBoldRightBold: string; + lineUpBoldLeftRight: string; + lineUpBoldLeftBoldRight: string; + lineUpBoldLeftRightBold: string; + lineUpLeftRightBold: string; + lineUpLeftBoldRight: string; + lineUpDoubleLeftDoubleRightDouble: string; + lineUpDoubleLeftRight: string; + lineUpLeftDoubleRightDouble: string; + lineUpDownLeftRight: string; + lineUpBoldDownBoldLeftBoldRightBold: string; + lineUpDownBoldLeftBoldRightBold: string; + lineUpBoldDownLeftBoldRightBold: string; + lineUpBoldDownBoldLeftRightBold: string; + lineUpBoldDownBoldLeftBoldRight: string; + lineUpBoldDownLeftRight: string; + lineUpDownBoldLeftRight: string; + lineUpDownLeftBoldRight: string; + lineUpDownLeftRightBold: string; + lineUpBoldDownBoldLeftRight: string; + lineUpDownLeftBoldRightBold: string; + lineUpBoldDownLeftBoldRight: string; + lineUpBoldDownLeftRightBold: string; + lineUpDownBoldLeftBoldRight: string; + lineUpDownBoldLeftRightBold: string; + lineUpDoubleDownDoubleLeftDoubleRightDouble: string; + lineUpDoubleDownDoubleLeftRight: string; + lineUpDownLeftDoubleRightDouble: string; + lineCross: string; + lineBackslash: string; + lineSlash: string; +} | Record; +export default figures; +export declare const replaceSymbols: (string: string, { useFallback }?: { + useFallback?: boolean | undefined; +}) => string; diff --git a/node_modules/@inquirer/figures/dist/commonjs/index.js b/node_modules/@inquirer/figures/dist/commonjs/index.js new file mode 100644 index 0000000000000000000000000000000000000000..5316b1729a63586fe9dd0568b3c2ab84c9903676 --- /dev/null +++ b/node_modules/@inquirer/figures/dist/commonjs/index.js @@ -0,0 +1,316 @@ +"use strict"; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.replaceSymbols = exports.fallbackSymbols = exports.mainSymbols = void 0; +// process.env dot-notation access prints: +// Property 'TERM' comes from an index signature, so it must be accessed with ['TERM'].ts(4111) +/* eslint dot-notation: ["off"] */ +const node_process_1 = __importDefault(require("node:process")); +// Ported from is-unicode-supported +function isUnicodeSupported() { + if (node_process_1.default.platform !== 'win32') { + return node_process_1.default.env['TERM'] !== 'linux'; // Linux console (kernel) + } + return (Boolean(node_process_1.default.env['WT_SESSION']) || // Windows Terminal + Boolean(node_process_1.default.env['TERMINUS_SUBLIME']) || // Terminus (<0.2.27) + node_process_1.default.env['ConEmuTask'] === '{cmd::Cmder}' || // ConEmu and cmder + node_process_1.default.env['TERM_PROGRAM'] === 'Terminus-Sublime' || + node_process_1.default.env['TERM_PROGRAM'] === 'vscode' || + node_process_1.default.env['TERM'] === 'xterm-256color' || + node_process_1.default.env['TERM'] === 'alacritty' || + node_process_1.default.env['TERMINAL_EMULATOR'] === 'JetBrains-JediTerm'); +} +// Ported from figures +const common = { + circleQuestionMark: '(?)', + questionMarkPrefix: '(?)', + square: '█', + squareDarkShade: '▓', + squareMediumShade: '▒', + squareLightShade: '░', + squareTop: '▀', + squareBottom: '▄', + squareLeft: '▌', + squareRight: '▐', + squareCenter: '■', + bullet: '●', + dot: '․', + ellipsis: '…', + pointerSmall: '›', + triangleUp: '▲', + triangleUpSmall: '▴', + triangleDown: '▼', + triangleDownSmall: '▾', + triangleLeftSmall: '◂', + triangleRightSmall: '▸', + home: '⌂', + heart: '♥', + musicNote: '♪', + musicNoteBeamed: '♫', + arrowUp: '↑', + arrowDown: '↓', + arrowLeft: '←', + arrowRight: '→', + arrowLeftRight: '↔', + arrowUpDown: '↕', + almostEqual: '≈', + notEqual: '≠', + lessOrEqual: '≤', + greaterOrEqual: '≥', + identical: '≡', + infinity: '∞', + subscriptZero: '₀', + subscriptOne: '₁', + subscriptTwo: '₂', + subscriptThree: '₃', + subscriptFour: '₄', + subscriptFive: '₅', + subscriptSix: '₆', + subscriptSeven: '₇', + subscriptEight: '₈', + subscriptNine: '₉', + oneHalf: '½', + oneThird: '⅓', + oneQuarter: '¼', + oneFifth: '⅕', + oneSixth: '⅙', + oneEighth: '⅛', + twoThirds: '⅔', + twoFifths: '⅖', + threeQuarters: '¾', + threeFifths: '⅗', + threeEighths: '⅜', + fourFifths: '⅘', + fiveSixths: '⅚', + fiveEighths: '⅝', + sevenEighths: '⅞', + line: '─', + lineBold: '━', + lineDouble: '═', + lineDashed0: '┄', + lineDashed1: '┅', + lineDashed2: '┈', + lineDashed3: '┉', + lineDashed4: '╌', + lineDashed5: '╍', + lineDashed6: '╴', + lineDashed7: '╶', + lineDashed8: '╸', + lineDashed9: '╺', + lineDashed10: '╼', + lineDashed11: '╾', + lineDashed12: '−', + lineDashed13: '–', + lineDashed14: '‐', + lineDashed15: '⁃', + lineVertical: '│', + lineVerticalBold: '┃', + lineVerticalDouble: '║', + lineVerticalDashed0: '┆', + lineVerticalDashed1: '┇', + lineVerticalDashed2: '┊', + lineVerticalDashed3: '┋', + lineVerticalDashed4: '╎', + lineVerticalDashed5: '╏', + lineVerticalDashed6: '╵', + lineVerticalDashed7: '╷', + lineVerticalDashed8: '╹', + lineVerticalDashed9: '╻', + lineVerticalDashed10: '╽', + lineVerticalDashed11: '╿', + lineDownLeft: '┐', + lineDownLeftArc: '╮', + lineDownBoldLeftBold: '┓', + lineDownBoldLeft: '┒', + lineDownLeftBold: '┑', + lineDownDoubleLeftDouble: '╗', + lineDownDoubleLeft: '╖', + lineDownLeftDouble: '╕', + lineDownRight: '┌', + lineDownRightArc: '╭', + lineDownBoldRightBold: '┏', + lineDownBoldRight: '┎', + lineDownRightBold: '┍', + lineDownDoubleRightDouble: '╔', + lineDownDoubleRight: '╓', + lineDownRightDouble: '╒', + lineUpLeft: '┘', + lineUpLeftArc: '╯', + lineUpBoldLeftBold: '┛', + lineUpBoldLeft: '┚', + lineUpLeftBold: '┙', + lineUpDoubleLeftDouble: '╝', + lineUpDoubleLeft: '╜', + lineUpLeftDouble: '╛', + lineUpRight: '└', + lineUpRightArc: '╰', + lineUpBoldRightBold: '┗', + lineUpBoldRight: '┖', + lineUpRightBold: '┕', + lineUpDoubleRightDouble: '╚', + lineUpDoubleRight: '╙', + lineUpRightDouble: '╘', + lineUpDownLeft: '┤', + lineUpBoldDownBoldLeftBold: '┫', + lineUpBoldDownBoldLeft: '┨', + lineUpDownLeftBold: '┥', + lineUpBoldDownLeftBold: '┩', + lineUpDownBoldLeftBold: '┪', + lineUpDownBoldLeft: '┧', + lineUpBoldDownLeft: '┦', + lineUpDoubleDownDoubleLeftDouble: '╣', + lineUpDoubleDownDoubleLeft: '╢', + lineUpDownLeftDouble: '╡', + lineUpDownRight: '├', + lineUpBoldDownBoldRightBold: '┣', + lineUpBoldDownBoldRight: '┠', + lineUpDownRightBold: '┝', + lineUpBoldDownRightBold: '┡', + lineUpDownBoldRightBold: '┢', + lineUpDownBoldRight: '┟', + lineUpBoldDownRight: '┞', + lineUpDoubleDownDoubleRightDouble: '╠', + lineUpDoubleDownDoubleRight: '╟', + lineUpDownRightDouble: '╞', + lineDownLeftRight: '┬', + lineDownBoldLeftBoldRightBold: '┳', + lineDownLeftBoldRightBold: '┯', + lineDownBoldLeftRight: '┰', + lineDownBoldLeftBoldRight: '┱', + lineDownBoldLeftRightBold: '┲', + lineDownLeftRightBold: '┮', + lineDownLeftBoldRight: '┭', + lineDownDoubleLeftDoubleRightDouble: '╦', + lineDownDoubleLeftRight: '╥', + lineDownLeftDoubleRightDouble: '╤', + lineUpLeftRight: '┴', + lineUpBoldLeftBoldRightBold: '┻', + lineUpLeftBoldRightBold: '┷', + lineUpBoldLeftRight: '┸', + lineUpBoldLeftBoldRight: '┹', + lineUpBoldLeftRightBold: '┺', + lineUpLeftRightBold: '┶', + lineUpLeftBoldRight: '┵', + lineUpDoubleLeftDoubleRightDouble: '╩', + lineUpDoubleLeftRight: '╨', + lineUpLeftDoubleRightDouble: '╧', + lineUpDownLeftRight: '┼', + lineUpBoldDownBoldLeftBoldRightBold: '╋', + lineUpDownBoldLeftBoldRightBold: '╈', + lineUpBoldDownLeftBoldRightBold: '╇', + lineUpBoldDownBoldLeftRightBold: '╊', + lineUpBoldDownBoldLeftBoldRight: '╉', + lineUpBoldDownLeftRight: '╀', + lineUpDownBoldLeftRight: '╁', + lineUpDownLeftBoldRight: '┽', + lineUpDownLeftRightBold: '┾', + lineUpBoldDownBoldLeftRight: '╂', + lineUpDownLeftBoldRightBold: '┿', + lineUpBoldDownLeftBoldRight: '╃', + lineUpBoldDownLeftRightBold: '╄', + lineUpDownBoldLeftBoldRight: '╅', + lineUpDownBoldLeftRightBold: '╆', + lineUpDoubleDownDoubleLeftDoubleRightDouble: '╬', + lineUpDoubleDownDoubleLeftRight: '╫', + lineUpDownLeftDoubleRightDouble: '╪', + lineCross: '╳', + lineBackslash: '╲', + lineSlash: '╱', +}; +const specialMainSymbols = { + tick: '✔', + info: 'ℹ', + warning: '⚠', + cross: '✘', + squareSmall: '◻', + squareSmallFilled: '◼', + circle: '◯', + circleFilled: '◉', + circleDotted: '◌', + circleDouble: '◎', + circleCircle: 'ⓞ', + circleCross: 'ⓧ', + circlePipe: 'Ⓘ', + radioOn: '◉', + radioOff: '◯', + checkboxOn: '☒', + checkboxOff: '☐', + checkboxCircleOn: 'ⓧ', + checkboxCircleOff: 'Ⓘ', + pointer: '❯', + triangleUpOutline: '△', + triangleLeft: '◀', + triangleRight: '▶', + lozenge: '◆', + lozengeOutline: '◇', + hamburger: '☰', + smiley: '㋡', + mustache: '෴', + star: '★', + play: '▶', + nodejs: '⬢', + oneSeventh: '⅐', + oneNinth: '⅑', + oneTenth: '⅒', +}; +const specialFallbackSymbols = { + tick: '√', + info: 'i', + warning: '‼', + cross: '×', + squareSmall: '□', + squareSmallFilled: '■', + circle: '( )', + circleFilled: '(*)', + circleDotted: '( )', + circleDouble: '( )', + circleCircle: '(○)', + circleCross: '(×)', + circlePipe: '(│)', + radioOn: '(*)', + radioOff: '( )', + checkboxOn: '[×]', + checkboxOff: '[ ]', + checkboxCircleOn: '(×)', + checkboxCircleOff: '( )', + pointer: '>', + triangleUpOutline: '∆', + triangleLeft: '◄', + triangleRight: '►', + lozenge: '♦', + lozengeOutline: '◊', + hamburger: '≡', + smiley: '☺', + mustache: '┌─┐', + star: '✶', + play: '►', + nodejs: '♦', + oneSeventh: '1/7', + oneNinth: '1/9', + oneTenth: '1/10', +}; +exports.mainSymbols = { ...common, ...specialMainSymbols }; +exports.fallbackSymbols = { + ...common, + ...specialFallbackSymbols, +}; +const shouldUseMain = isUnicodeSupported(); +const figures = shouldUseMain ? exports.mainSymbols : exports.fallbackSymbols; +exports.default = figures; +const replacements = Object.entries(specialMainSymbols); +// On terminals which do not support Unicode symbols, substitute them to other symbols +const replaceSymbols = (string, { useFallback = !shouldUseMain } = {}) => { + if (useFallback) { + for (const [key, mainSymbol] of replacements) { + const fallbackSymbol = exports.fallbackSymbols[key]; + if (!fallbackSymbol) { + throw new Error(`Unable to find fallback for ${key}`); + } + string = string.replaceAll(mainSymbol, fallbackSymbol); + } + } + return string; +}; +exports.replaceSymbols = replaceSymbols; diff --git a/node_modules/@inquirer/figures/dist/commonjs/package.json b/node_modules/@inquirer/figures/dist/commonjs/package.json new file mode 100644 index 0000000000000000000000000000000000000000..5bbefffbabee392d1855491b84dc0a716b6a3bf2 --- /dev/null +++ b/node_modules/@inquirer/figures/dist/commonjs/package.json @@ -0,0 +1,3 @@ +{ + "type": "commonjs" +} diff --git a/node_modules/@inquirer/figures/dist/esm/index.d.ts b/node_modules/@inquirer/figures/dist/esm/index.d.ts new file mode 100644 index 0000000000000000000000000000000000000000..f8202e508b5f7c560c1c0ae5ad16bf4ecc93b877 --- /dev/null +++ b/node_modules/@inquirer/figures/dist/esm/index.d.ts @@ -0,0 +1,465 @@ +export declare const mainSymbols: { + tick: string; + info: string; + warning: string; + cross: string; + squareSmall: string; + squareSmallFilled: string; + circle: string; + circleFilled: string; + circleDotted: string; + circleDouble: string; + circleCircle: string; + circleCross: string; + circlePipe: string; + radioOn: string; + radioOff: string; + checkboxOn: string; + checkboxOff: string; + checkboxCircleOn: string; + checkboxCircleOff: string; + pointer: string; + triangleUpOutline: string; + triangleLeft: string; + triangleRight: string; + lozenge: string; + lozengeOutline: string; + hamburger: string; + smiley: string; + mustache: string; + star: string; + play: string; + nodejs: string; + oneSeventh: string; + oneNinth: string; + oneTenth: string; + circleQuestionMark: string; + questionMarkPrefix: string; + square: string; + squareDarkShade: string; + squareMediumShade: string; + squareLightShade: string; + squareTop: string; + squareBottom: string; + squareLeft: string; + squareRight: string; + squareCenter: string; + bullet: string; + dot: string; + ellipsis: string; + pointerSmall: string; + triangleUp: string; + triangleUpSmall: string; + triangleDown: string; + triangleDownSmall: string; + triangleLeftSmall: string; + triangleRightSmall: string; + home: string; + heart: string; + musicNote: string; + musicNoteBeamed: string; + arrowUp: string; + arrowDown: string; + arrowLeft: string; + arrowRight: string; + arrowLeftRight: string; + arrowUpDown: string; + almostEqual: string; + notEqual: string; + lessOrEqual: string; + greaterOrEqual: string; + identical: string; + infinity: string; + subscriptZero: string; + subscriptOne: string; + subscriptTwo: string; + subscriptThree: string; + subscriptFour: string; + subscriptFive: string; + subscriptSix: string; + subscriptSeven: string; + subscriptEight: string; + subscriptNine: string; + oneHalf: string; + oneThird: string; + oneQuarter: string; + oneFifth: string; + oneSixth: string; + oneEighth: string; + twoThirds: string; + twoFifths: string; + threeQuarters: string; + threeFifths: string; + threeEighths: string; + fourFifths: string; + fiveSixths: string; + fiveEighths: string; + sevenEighths: string; + line: string; + lineBold: string; + lineDouble: string; + lineDashed0: string; + lineDashed1: string; + lineDashed2: string; + lineDashed3: string; + lineDashed4: string; + lineDashed5: string; + lineDashed6: string; + lineDashed7: string; + lineDashed8: string; + lineDashed9: string; + lineDashed10: string; + lineDashed11: string; + lineDashed12: string; + lineDashed13: string; + lineDashed14: string; + lineDashed15: string; + lineVertical: string; + lineVerticalBold: string; + lineVerticalDouble: string; + lineVerticalDashed0: string; + lineVerticalDashed1: string; + lineVerticalDashed2: string; + lineVerticalDashed3: string; + lineVerticalDashed4: string; + lineVerticalDashed5: string; + lineVerticalDashed6: string; + lineVerticalDashed7: string; + lineVerticalDashed8: string; + lineVerticalDashed9: string; + lineVerticalDashed10: string; + lineVerticalDashed11: string; + lineDownLeft: string; + lineDownLeftArc: string; + lineDownBoldLeftBold: string; + lineDownBoldLeft: string; + lineDownLeftBold: string; + lineDownDoubleLeftDouble: string; + lineDownDoubleLeft: string; + lineDownLeftDouble: string; + lineDownRight: string; + lineDownRightArc: string; + lineDownBoldRightBold: string; + lineDownBoldRight: string; + lineDownRightBold: string; + lineDownDoubleRightDouble: string; + lineDownDoubleRight: string; + lineDownRightDouble: string; + lineUpLeft: string; + lineUpLeftArc: string; + lineUpBoldLeftBold: string; + lineUpBoldLeft: string; + lineUpLeftBold: string; + lineUpDoubleLeftDouble: string; + lineUpDoubleLeft: string; + lineUpLeftDouble: string; + lineUpRight: string; + lineUpRightArc: string; + lineUpBoldRightBold: string; + lineUpBoldRight: string; + lineUpRightBold: string; + lineUpDoubleRightDouble: string; + lineUpDoubleRight: string; + lineUpRightDouble: string; + lineUpDownLeft: string; + lineUpBoldDownBoldLeftBold: string; + lineUpBoldDownBoldLeft: string; + lineUpDownLeftBold: string; + lineUpBoldDownLeftBold: string; + lineUpDownBoldLeftBold: string; + lineUpDownBoldLeft: string; + lineUpBoldDownLeft: string; + lineUpDoubleDownDoubleLeftDouble: string; + lineUpDoubleDownDoubleLeft: string; + lineUpDownLeftDouble: string; + lineUpDownRight: string; + lineUpBoldDownBoldRightBold: string; + lineUpBoldDownBoldRight: string; + lineUpDownRightBold: string; + lineUpBoldDownRightBold: string; + lineUpDownBoldRightBold: string; + lineUpDownBoldRight: string; + lineUpBoldDownRight: string; + lineUpDoubleDownDoubleRightDouble: string; + lineUpDoubleDownDoubleRight: string; + lineUpDownRightDouble: string; + lineDownLeftRight: string; + lineDownBoldLeftBoldRightBold: string; + lineDownLeftBoldRightBold: string; + lineDownBoldLeftRight: string; + lineDownBoldLeftBoldRight: string; + lineDownBoldLeftRightBold: string; + lineDownLeftRightBold: string; + lineDownLeftBoldRight: string; + lineDownDoubleLeftDoubleRightDouble: string; + lineDownDoubleLeftRight: string; + lineDownLeftDoubleRightDouble: string; + lineUpLeftRight: string; + lineUpBoldLeftBoldRightBold: string; + lineUpLeftBoldRightBold: string; + lineUpBoldLeftRight: string; + lineUpBoldLeftBoldRight: string; + lineUpBoldLeftRightBold: string; + lineUpLeftRightBold: string; + lineUpLeftBoldRight: string; + lineUpDoubleLeftDoubleRightDouble: string; + lineUpDoubleLeftRight: string; + lineUpLeftDoubleRightDouble: string; + lineUpDownLeftRight: string; + lineUpBoldDownBoldLeftBoldRightBold: string; + lineUpDownBoldLeftBoldRightBold: string; + lineUpBoldDownLeftBoldRightBold: string; + lineUpBoldDownBoldLeftRightBold: string; + lineUpBoldDownBoldLeftBoldRight: string; + lineUpBoldDownLeftRight: string; + lineUpDownBoldLeftRight: string; + lineUpDownLeftBoldRight: string; + lineUpDownLeftRightBold: string; + lineUpBoldDownBoldLeftRight: string; + lineUpDownLeftBoldRightBold: string; + lineUpBoldDownLeftBoldRight: string; + lineUpBoldDownLeftRightBold: string; + lineUpDownBoldLeftBoldRight: string; + lineUpDownBoldLeftRightBold: string; + lineUpDoubleDownDoubleLeftDoubleRightDouble: string; + lineUpDoubleDownDoubleLeftRight: string; + lineUpDownLeftDoubleRightDouble: string; + lineCross: string; + lineBackslash: string; + lineSlash: string; +}; +export declare const fallbackSymbols: Record; +declare const figures: { + tick: string; + info: string; + warning: string; + cross: string; + squareSmall: string; + squareSmallFilled: string; + circle: string; + circleFilled: string; + circleDotted: string; + circleDouble: string; + circleCircle: string; + circleCross: string; + circlePipe: string; + radioOn: string; + radioOff: string; + checkboxOn: string; + checkboxOff: string; + checkboxCircleOn: string; + checkboxCircleOff: string; + pointer: string; + triangleUpOutline: string; + triangleLeft: string; + triangleRight: string; + lozenge: string; + lozengeOutline: string; + hamburger: string; + smiley: string; + mustache: string; + star: string; + play: string; + nodejs: string; + oneSeventh: string; + oneNinth: string; + oneTenth: string; + circleQuestionMark: string; + questionMarkPrefix: string; + square: string; + squareDarkShade: string; + squareMediumShade: string; + squareLightShade: string; + squareTop: string; + squareBottom: string; + squareLeft: string; + squareRight: string; + squareCenter: string; + bullet: string; + dot: string; + ellipsis: string; + pointerSmall: string; + triangleUp: string; + triangleUpSmall: string; + triangleDown: string; + triangleDownSmall: string; + triangleLeftSmall: string; + triangleRightSmall: string; + home: string; + heart: string; + musicNote: string; + musicNoteBeamed: string; + arrowUp: string; + arrowDown: string; + arrowLeft: string; + arrowRight: string; + arrowLeftRight: string; + arrowUpDown: string; + almostEqual: string; + notEqual: string; + lessOrEqual: string; + greaterOrEqual: string; + identical: string; + infinity: string; + subscriptZero: string; + subscriptOne: string; + subscriptTwo: string; + subscriptThree: string; + subscriptFour: string; + subscriptFive: string; + subscriptSix: string; + subscriptSeven: string; + subscriptEight: string; + subscriptNine: string; + oneHalf: string; + oneThird: string; + oneQuarter: string; + oneFifth: string; + oneSixth: string; + oneEighth: string; + twoThirds: string; + twoFifths: string; + threeQuarters: string; + threeFifths: string; + threeEighths: string; + fourFifths: string; + fiveSixths: string; + fiveEighths: string; + sevenEighths: string; + line: string; + lineBold: string; + lineDouble: string; + lineDashed0: string; + lineDashed1: string; + lineDashed2: string; + lineDashed3: string; + lineDashed4: string; + lineDashed5: string; + lineDashed6: string; + lineDashed7: string; + lineDashed8: string; + lineDashed9: string; + lineDashed10: string; + lineDashed11: string; + lineDashed12: string; + lineDashed13: string; + lineDashed14: string; + lineDashed15: string; + lineVertical: string; + lineVerticalBold: string; + lineVerticalDouble: string; + lineVerticalDashed0: string; + lineVerticalDashed1: string; + lineVerticalDashed2: string; + lineVerticalDashed3: string; + lineVerticalDashed4: string; + lineVerticalDashed5: string; + lineVerticalDashed6: string; + lineVerticalDashed7: string; + lineVerticalDashed8: string; + lineVerticalDashed9: string; + lineVerticalDashed10: string; + lineVerticalDashed11: string; + lineDownLeft: string; + lineDownLeftArc: string; + lineDownBoldLeftBold: string; + lineDownBoldLeft: string; + lineDownLeftBold: string; + lineDownDoubleLeftDouble: string; + lineDownDoubleLeft: string; + lineDownLeftDouble: string; + lineDownRight: string; + lineDownRightArc: string; + lineDownBoldRightBold: string; + lineDownBoldRight: string; + lineDownRightBold: string; + lineDownDoubleRightDouble: string; + lineDownDoubleRight: string; + lineDownRightDouble: string; + lineUpLeft: string; + lineUpLeftArc: string; + lineUpBoldLeftBold: string; + lineUpBoldLeft: string; + lineUpLeftBold: string; + lineUpDoubleLeftDouble: string; + lineUpDoubleLeft: string; + lineUpLeftDouble: string; + lineUpRight: string; + lineUpRightArc: string; + lineUpBoldRightBold: string; + lineUpBoldRight: string; + lineUpRightBold: string; + lineUpDoubleRightDouble: string; + lineUpDoubleRight: string; + lineUpRightDouble: string; + lineUpDownLeft: string; + lineUpBoldDownBoldLeftBold: string; + lineUpBoldDownBoldLeft: string; + lineUpDownLeftBold: string; + lineUpBoldDownLeftBold: string; + lineUpDownBoldLeftBold: string; + lineUpDownBoldLeft: string; + lineUpBoldDownLeft: string; + lineUpDoubleDownDoubleLeftDouble: string; + lineUpDoubleDownDoubleLeft: string; + lineUpDownLeftDouble: string; + lineUpDownRight: string; + lineUpBoldDownBoldRightBold: string; + lineUpBoldDownBoldRight: string; + lineUpDownRightBold: string; + lineUpBoldDownRightBold: string; + lineUpDownBoldRightBold: string; + lineUpDownBoldRight: string; + lineUpBoldDownRight: string; + lineUpDoubleDownDoubleRightDouble: string; + lineUpDoubleDownDoubleRight: string; + lineUpDownRightDouble: string; + lineDownLeftRight: string; + lineDownBoldLeftBoldRightBold: string; + lineDownLeftBoldRightBold: string; + lineDownBoldLeftRight: string; + lineDownBoldLeftBoldRight: string; + lineDownBoldLeftRightBold: string; + lineDownLeftRightBold: string; + lineDownLeftBoldRight: string; + lineDownDoubleLeftDoubleRightDouble: string; + lineDownDoubleLeftRight: string; + lineDownLeftDoubleRightDouble: string; + lineUpLeftRight: string; + lineUpBoldLeftBoldRightBold: string; + lineUpLeftBoldRightBold: string; + lineUpBoldLeftRight: string; + lineUpBoldLeftBoldRight: string; + lineUpBoldLeftRightBold: string; + lineUpLeftRightBold: string; + lineUpLeftBoldRight: string; + lineUpDoubleLeftDoubleRightDouble: string; + lineUpDoubleLeftRight: string; + lineUpLeftDoubleRightDouble: string; + lineUpDownLeftRight: string; + lineUpBoldDownBoldLeftBoldRightBold: string; + lineUpDownBoldLeftBoldRightBold: string; + lineUpBoldDownLeftBoldRightBold: string; + lineUpBoldDownBoldLeftRightBold: string; + lineUpBoldDownBoldLeftBoldRight: string; + lineUpBoldDownLeftRight: string; + lineUpDownBoldLeftRight: string; + lineUpDownLeftBoldRight: string; + lineUpDownLeftRightBold: string; + lineUpBoldDownBoldLeftRight: string; + lineUpDownLeftBoldRightBold: string; + lineUpBoldDownLeftBoldRight: string; + lineUpBoldDownLeftRightBold: string; + lineUpDownBoldLeftBoldRight: string; + lineUpDownBoldLeftRightBold: string; + lineUpDoubleDownDoubleLeftDoubleRightDouble: string; + lineUpDoubleDownDoubleLeftRight: string; + lineUpDownLeftDoubleRightDouble: string; + lineCross: string; + lineBackslash: string; + lineSlash: string; +} | Record; +export default figures; +export declare const replaceSymbols: (string: string, { useFallback }?: { + useFallback?: boolean | undefined; +}) => string; diff --git a/node_modules/@inquirer/figures/dist/esm/index.js b/node_modules/@inquirer/figures/dist/esm/index.js new file mode 100644 index 0000000000000000000000000000000000000000..d43b15e630fa12ec082806563fd405bc687ef012 --- /dev/null +++ b/node_modules/@inquirer/figures/dist/esm/index.js @@ -0,0 +1,309 @@ +// process.env dot-notation access prints: +// Property 'TERM' comes from an index signature, so it must be accessed with ['TERM'].ts(4111) +/* eslint dot-notation: ["off"] */ +import process from 'node:process'; +// Ported from is-unicode-supported +function isUnicodeSupported() { + if (process.platform !== 'win32') { + return process.env['TERM'] !== 'linux'; // Linux console (kernel) + } + return (Boolean(process.env['WT_SESSION']) || // Windows Terminal + Boolean(process.env['TERMINUS_SUBLIME']) || // Terminus (<0.2.27) + process.env['ConEmuTask'] === '{cmd::Cmder}' || // ConEmu and cmder + process.env['TERM_PROGRAM'] === 'Terminus-Sublime' || + process.env['TERM_PROGRAM'] === 'vscode' || + process.env['TERM'] === 'xterm-256color' || + process.env['TERM'] === 'alacritty' || + process.env['TERMINAL_EMULATOR'] === 'JetBrains-JediTerm'); +} +// Ported from figures +const common = { + circleQuestionMark: '(?)', + questionMarkPrefix: '(?)', + square: '█', + squareDarkShade: '▓', + squareMediumShade: '▒', + squareLightShade: '░', + squareTop: '▀', + squareBottom: '▄', + squareLeft: '▌', + squareRight: '▐', + squareCenter: '■', + bullet: '●', + dot: '․', + ellipsis: '…', + pointerSmall: '›', + triangleUp: '▲', + triangleUpSmall: '▴', + triangleDown: '▼', + triangleDownSmall: '▾', + triangleLeftSmall: '◂', + triangleRightSmall: '▸', + home: '⌂', + heart: '♥', + musicNote: '♪', + musicNoteBeamed: '♫', + arrowUp: '↑', + arrowDown: '↓', + arrowLeft: '←', + arrowRight: '→', + arrowLeftRight: '↔', + arrowUpDown: '↕', + almostEqual: '≈', + notEqual: '≠', + lessOrEqual: '≤', + greaterOrEqual: '≥', + identical: '≡', + infinity: '∞', + subscriptZero: '₀', + subscriptOne: '₁', + subscriptTwo: '₂', + subscriptThree: '₃', + subscriptFour: '₄', + subscriptFive: '₅', + subscriptSix: '₆', + subscriptSeven: '₇', + subscriptEight: '₈', + subscriptNine: '₉', + oneHalf: '½', + oneThird: '⅓', + oneQuarter: '¼', + oneFifth: '⅕', + oneSixth: '⅙', + oneEighth: '⅛', + twoThirds: '⅔', + twoFifths: '⅖', + threeQuarters: '¾', + threeFifths: '⅗', + threeEighths: '⅜', + fourFifths: '⅘', + fiveSixths: '⅚', + fiveEighths: '⅝', + sevenEighths: '⅞', + line: '─', + lineBold: '━', + lineDouble: '═', + lineDashed0: '┄', + lineDashed1: '┅', + lineDashed2: '┈', + lineDashed3: '┉', + lineDashed4: '╌', + lineDashed5: '╍', + lineDashed6: '╴', + lineDashed7: '╶', + lineDashed8: '╸', + lineDashed9: '╺', + lineDashed10: '╼', + lineDashed11: '╾', + lineDashed12: '−', + lineDashed13: '–', + lineDashed14: '‐', + lineDashed15: '⁃', + lineVertical: '│', + lineVerticalBold: '┃', + lineVerticalDouble: '║', + lineVerticalDashed0: '┆', + lineVerticalDashed1: '┇', + lineVerticalDashed2: '┊', + lineVerticalDashed3: '┋', + lineVerticalDashed4: '╎', + lineVerticalDashed5: '╏', + lineVerticalDashed6: '╵', + lineVerticalDashed7: '╷', + lineVerticalDashed8: '╹', + lineVerticalDashed9: '╻', + lineVerticalDashed10: '╽', + lineVerticalDashed11: '╿', + lineDownLeft: '┐', + lineDownLeftArc: '╮', + lineDownBoldLeftBold: '┓', + lineDownBoldLeft: '┒', + lineDownLeftBold: '┑', + lineDownDoubleLeftDouble: '╗', + lineDownDoubleLeft: '╖', + lineDownLeftDouble: '╕', + lineDownRight: '┌', + lineDownRightArc: '╭', + lineDownBoldRightBold: '┏', + lineDownBoldRight: '┎', + lineDownRightBold: '┍', + lineDownDoubleRightDouble: '╔', + lineDownDoubleRight: '╓', + lineDownRightDouble: '╒', + lineUpLeft: '┘', + lineUpLeftArc: '╯', + lineUpBoldLeftBold: '┛', + lineUpBoldLeft: '┚', + lineUpLeftBold: '┙', + lineUpDoubleLeftDouble: '╝', + lineUpDoubleLeft: '╜', + lineUpLeftDouble: '╛', + lineUpRight: '└', + lineUpRightArc: '╰', + lineUpBoldRightBold: '┗', + lineUpBoldRight: '┖', + lineUpRightBold: '┕', + lineUpDoubleRightDouble: '╚', + lineUpDoubleRight: '╙', + lineUpRightDouble: '╘', + lineUpDownLeft: '┤', + lineUpBoldDownBoldLeftBold: '┫', + lineUpBoldDownBoldLeft: '┨', + lineUpDownLeftBold: '┥', + lineUpBoldDownLeftBold: '┩', + lineUpDownBoldLeftBold: '┪', + lineUpDownBoldLeft: '┧', + lineUpBoldDownLeft: '┦', + lineUpDoubleDownDoubleLeftDouble: '╣', + lineUpDoubleDownDoubleLeft: '╢', + lineUpDownLeftDouble: '╡', + lineUpDownRight: '├', + lineUpBoldDownBoldRightBold: '┣', + lineUpBoldDownBoldRight: '┠', + lineUpDownRightBold: '┝', + lineUpBoldDownRightBold: '┡', + lineUpDownBoldRightBold: '┢', + lineUpDownBoldRight: '┟', + lineUpBoldDownRight: '┞', + lineUpDoubleDownDoubleRightDouble: '╠', + lineUpDoubleDownDoubleRight: '╟', + lineUpDownRightDouble: '╞', + lineDownLeftRight: '┬', + lineDownBoldLeftBoldRightBold: '┳', + lineDownLeftBoldRightBold: '┯', + lineDownBoldLeftRight: '┰', + lineDownBoldLeftBoldRight: '┱', + lineDownBoldLeftRightBold: '┲', + lineDownLeftRightBold: '┮', + lineDownLeftBoldRight: '┭', + lineDownDoubleLeftDoubleRightDouble: '╦', + lineDownDoubleLeftRight: '╥', + lineDownLeftDoubleRightDouble: '╤', + lineUpLeftRight: '┴', + lineUpBoldLeftBoldRightBold: '┻', + lineUpLeftBoldRightBold: '┷', + lineUpBoldLeftRight: '┸', + lineUpBoldLeftBoldRight: '┹', + lineUpBoldLeftRightBold: '┺', + lineUpLeftRightBold: '┶', + lineUpLeftBoldRight: '┵', + lineUpDoubleLeftDoubleRightDouble: '╩', + lineUpDoubleLeftRight: '╨', + lineUpLeftDoubleRightDouble: '╧', + lineUpDownLeftRight: '┼', + lineUpBoldDownBoldLeftBoldRightBold: '╋', + lineUpDownBoldLeftBoldRightBold: '╈', + lineUpBoldDownLeftBoldRightBold: '╇', + lineUpBoldDownBoldLeftRightBold: '╊', + lineUpBoldDownBoldLeftBoldRight: '╉', + lineUpBoldDownLeftRight: '╀', + lineUpDownBoldLeftRight: '╁', + lineUpDownLeftBoldRight: '┽', + lineUpDownLeftRightBold: '┾', + lineUpBoldDownBoldLeftRight: '╂', + lineUpDownLeftBoldRightBold: '┿', + lineUpBoldDownLeftBoldRight: '╃', + lineUpBoldDownLeftRightBold: '╄', + lineUpDownBoldLeftBoldRight: '╅', + lineUpDownBoldLeftRightBold: '╆', + lineUpDoubleDownDoubleLeftDoubleRightDouble: '╬', + lineUpDoubleDownDoubleLeftRight: '╫', + lineUpDownLeftDoubleRightDouble: '╪', + lineCross: '╳', + lineBackslash: '╲', + lineSlash: '╱', +}; +const specialMainSymbols = { + tick: '✔', + info: 'ℹ', + warning: '⚠', + cross: '✘', + squareSmall: '◻', + squareSmallFilled: '◼', + circle: '◯', + circleFilled: '◉', + circleDotted: '◌', + circleDouble: '◎', + circleCircle: 'ⓞ', + circleCross: 'ⓧ', + circlePipe: 'Ⓘ', + radioOn: '◉', + radioOff: '◯', + checkboxOn: '☒', + checkboxOff: '☐', + checkboxCircleOn: 'ⓧ', + checkboxCircleOff: 'Ⓘ', + pointer: '❯', + triangleUpOutline: '△', + triangleLeft: '◀', + triangleRight: '▶', + lozenge: '◆', + lozengeOutline: '◇', + hamburger: '☰', + smiley: '㋡', + mustache: '෴', + star: '★', + play: '▶', + nodejs: '⬢', + oneSeventh: '⅐', + oneNinth: '⅑', + oneTenth: '⅒', +}; +const specialFallbackSymbols = { + tick: '√', + info: 'i', + warning: '‼', + cross: '×', + squareSmall: '□', + squareSmallFilled: '■', + circle: '( )', + circleFilled: '(*)', + circleDotted: '( )', + circleDouble: '( )', + circleCircle: '(○)', + circleCross: '(×)', + circlePipe: '(│)', + radioOn: '(*)', + radioOff: '( )', + checkboxOn: '[×]', + checkboxOff: '[ ]', + checkboxCircleOn: '(×)', + checkboxCircleOff: '( )', + pointer: '>', + triangleUpOutline: '∆', + triangleLeft: '◄', + triangleRight: '►', + lozenge: '♦', + lozengeOutline: '◊', + hamburger: '≡', + smiley: '☺', + mustache: '┌─┐', + star: '✶', + play: '►', + nodejs: '♦', + oneSeventh: '1/7', + oneNinth: '1/9', + oneTenth: '1/10', +}; +export const mainSymbols = { ...common, ...specialMainSymbols }; +export const fallbackSymbols = { + ...common, + ...specialFallbackSymbols, +}; +const shouldUseMain = isUnicodeSupported(); +const figures = shouldUseMain ? mainSymbols : fallbackSymbols; +export default figures; +const replacements = Object.entries(specialMainSymbols); +// On terminals which do not support Unicode symbols, substitute them to other symbols +export const replaceSymbols = (string, { useFallback = !shouldUseMain } = {}) => { + if (useFallback) { + for (const [key, mainSymbol] of replacements) { + const fallbackSymbol = fallbackSymbols[key]; + if (!fallbackSymbol) { + throw new Error(`Unable to find fallback for ${key}`); + } + string = string.replaceAll(mainSymbol, fallbackSymbol); + } + } + return string; +}; diff --git a/node_modules/@inquirer/figures/dist/esm/package.json b/node_modules/@inquirer/figures/dist/esm/package.json new file mode 100644 index 0000000000000000000000000000000000000000..3dbc1ca591c0557e35b6004aeba250e6a70b56e3 --- /dev/null +++ b/node_modules/@inquirer/figures/dist/esm/package.json @@ -0,0 +1,3 @@ +{ + "type": "module" +} diff --git a/node_modules/@inquirer/figures/package.json b/node_modules/@inquirer/figures/package.json new file mode 100644 index 0000000000000000000000000000000000000000..928d97bb3f2b4f4f10ca2249922525ee0d504ef7 --- /dev/null +++ b/node_modules/@inquirer/figures/package.json @@ -0,0 +1,95 @@ +{ + "name": "@inquirer/figures", + "version": "1.0.11", + "description": "Vendored version of figures, for CJS compatibility", + "keywords": [ + "answer", + "answers", + "ask", + "base", + "cli", + "command", + "command-line", + "confirm", + "enquirer", + "generate", + "generator", + "hyper", + "input", + "inquire", + "inquirer", + "interface", + "iterm", + "javascript", + "menu", + "node", + "nodejs", + "prompt", + "promptly", + "prompts", + "question", + "readline", + "scaffold", + "scaffolder", + "scaffolding", + "stdin", + "stdout", + "terminal", + "tty", + "ui", + "yeoman", + "yo", + "zsh", + "types", + "typescript" + ], + "repository": { + "type": "git", + "url": "https://github.com/SBoudrias/Inquirer.js.git" + }, + "license": "MIT", + "author": "Simon Boudrias ", + "sideEffects": false, + "type": "module", + "exports": { + "./package.json": "./package.json", + ".": { + "import": { + "types": "./dist/esm/index.d.ts", + "default": "./dist/esm/index.js" + }, + "require": { + "types": "./dist/commonjs/index.d.ts", + "default": "./dist/commonjs/index.js" + } + } + }, + "main": "./dist/commonjs/index.js", + "module": "./dist/esm/index.js", + "types": "./dist/commonjs/index.d.ts", + "files": [ + "dist" + ], + "scripts": { + "attw": "attw --pack", + "tsc": "tshy" + }, + "devDependencies": { + "@arethetypeswrong/cli": "^0.17.4", + "@repo/tsconfig": "workspace:*", + "tshy": "^3.0.2" + }, + "engines": { + "node": ">=18" + }, + "tshy": { + "exclude": [ + "src/**/*.test.ts" + ], + "exports": { + "./package.json": "./package.json", + ".": "./src/index.ts" + } + }, + "gitHead": "79a0b3e7446b4a3de09445bf2f4031e4190b6382" +} diff --git a/node_modules/@inquirer/type/LICENSE b/node_modules/@inquirer/type/LICENSE new file mode 100644 index 0000000000000000000000000000000000000000..f7186988726152b8dfb1bbafe940a712da142e3e --- /dev/null +++ b/node_modules/@inquirer/type/LICENSE @@ -0,0 +1,22 @@ +Copyright (c) 2025 Simon Boudrias + +Permission is hereby granted, free of charge, to any person +obtaining a copy of this software and associated documentation +files (the "Software"), to deal in the Software without +restriction, including without limitation the rights to use, +copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. diff --git a/node_modules/@inquirer/type/dist/commonjs/index.d.ts b/node_modules/@inquirer/type/dist/commonjs/index.d.ts new file mode 100644 index 0000000000000000000000000000000000000000..611714bd893bb6ceb9591ae90b25b98e3fb6c8ba --- /dev/null +++ b/node_modules/@inquirer/type/dist/commonjs/index.d.ts @@ -0,0 +1,2 @@ +export * from './inquirer.ts'; +export * from './utils.ts'; diff --git a/node_modules/@inquirer/type/dist/commonjs/index.js b/node_modules/@inquirer/type/dist/commonjs/index.js new file mode 100644 index 0000000000000000000000000000000000000000..556c9b8ea80d54dc0ae9d28b82f4cbd3ddc5abb1 --- /dev/null +++ b/node_modules/@inquirer/type/dist/commonjs/index.js @@ -0,0 +1,18 @@ +"use strict"; +var __createBinding = (this && this.__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 __exportStar = (this && this.__exportStar) || function(m, exports) { + for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p); +}; +Object.defineProperty(exports, "__esModule", { value: true }); +__exportStar(require("./inquirer.js"), exports); +__exportStar(require("./utils.js"), exports); diff --git a/node_modules/@inquirer/type/dist/commonjs/inquirer.d.ts b/node_modules/@inquirer/type/dist/commonjs/inquirer.d.ts new file mode 100644 index 0000000000000000000000000000000000000000..c1633eaf62847af1cf4d65f6b1be3791fc1cc647 --- /dev/null +++ b/node_modules/@inquirer/type/dist/commonjs/inquirer.d.ts @@ -0,0 +1,38 @@ +import { Duplex } from 'node:stream'; +/** + * `InquirerReadline` is a re-implementation of `readline.Interface` from Node.js. + * We're reimplementing it because of 3 reasons: + * 1. The `readline.Interface` API is not complete; it's missing for example `clearLine`. + * 2. The input/output streams are not generics, meaning they're inexact. + * 3. Since ReadLine isn't built-in Typescript Global NodeJS type, it'd force us to ship `@types/node` as a dependency to all users. + */ +export type InquirerReadline = { + output: Duplex & { + mute: () => void; + unmute: () => void; + }; + input: NodeJS.ReadableStream; + clearLine: (dir: 0 | 1 | -1) => void; + getCursorPos: () => { + rows: number; + cols: number; + }; + setPrompt: (prompt: string) => void; + line: string; + write: (data: string) => void; + on: (event: string, listener: (...args: unknown[]) => void) => void; + removeListener: (event: string, listener: (...args: unknown[]) => void) => void; + pause: () => void; + resume: () => void; + close: () => void; +}; +export type Context = { + input?: NodeJS.ReadableStream; + output?: NodeJS.WritableStream; + clearPromptOnDone?: boolean; + signal?: AbortSignal; +}; +export type Prompt = (config: Config, context?: Context) => Promise & { + /** @deprecated pass an AbortSignal in the context options instead. See {@link https://github.com/SBoudrias/Inquirer.js#canceling-prompt} */ + cancel: () => void; +}; diff --git a/node_modules/@inquirer/type/dist/commonjs/inquirer.js b/node_modules/@inquirer/type/dist/commonjs/inquirer.js new file mode 100644 index 0000000000000000000000000000000000000000..c8ad2e549bdc6801e0d1c80b0308d4b9bd4985ce --- /dev/null +++ b/node_modules/@inquirer/type/dist/commonjs/inquirer.js @@ -0,0 +1,2 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); diff --git a/node_modules/@inquirer/type/dist/commonjs/package.json b/node_modules/@inquirer/type/dist/commonjs/package.json new file mode 100644 index 0000000000000000000000000000000000000000..5bbefffbabee392d1855491b84dc0a716b6a3bf2 --- /dev/null +++ b/node_modules/@inquirer/type/dist/commonjs/package.json @@ -0,0 +1,3 @@ +{ + "type": "commonjs" +} diff --git a/node_modules/@inquirer/type/dist/commonjs/utils.d.ts b/node_modules/@inquirer/type/dist/commonjs/utils.d.ts new file mode 100644 index 0000000000000000000000000000000000000000..c37eb73af13648aa19eb0d77df8e93bb4e9af944 --- /dev/null +++ b/node_modules/@inquirer/type/dist/commonjs/utils.d.ts @@ -0,0 +1,29 @@ +type Key = string | number | symbol; +export type Prettify = { + [K in keyof T]: T[K]; +} & {}; +export type PartialDeep = T extends object ? { + [P in keyof T]?: PartialDeep; +} : T; +export type LiteralUnion = T | (F & {}); +export type KeyUnion = LiteralUnion>; +export type DistributiveMerge = A extends any ? Prettify & B> : never; +export type UnionToIntersection = (T extends any ? (input: T) => void : never) extends (input: infer Intersection) => void ? Intersection : never; +/** + * @hidden + */ +type __Pick = { + [P in K]: O[P]; +} & {}; +/** + * @hidden + */ +export type _Pick = __Pick; +/** + * Extract out of `O` the fields of key `K` + * @param O to extract from + * @param K to chose fields + * @returns [[Object]] + */ +export type Pick = O extends unknown ? _Pick : never; +export {}; diff --git a/node_modules/@inquirer/type/dist/commonjs/utils.js b/node_modules/@inquirer/type/dist/commonjs/utils.js new file mode 100644 index 0000000000000000000000000000000000000000..2b5963b5c00dfe43a5bba0a895ee5c07a9129f09 --- /dev/null +++ b/node_modules/@inquirer/type/dist/commonjs/utils.js @@ -0,0 +1,3 @@ +"use strict"; +/* eslint-disable @typescript-eslint/no-explicit-any */ +Object.defineProperty(exports, "__esModule", { value: true }); diff --git a/node_modules/@inquirer/type/dist/esm/index.d.ts b/node_modules/@inquirer/type/dist/esm/index.d.ts new file mode 100644 index 0000000000000000000000000000000000000000..611714bd893bb6ceb9591ae90b25b98e3fb6c8ba --- /dev/null +++ b/node_modules/@inquirer/type/dist/esm/index.d.ts @@ -0,0 +1,2 @@ +export * from './inquirer.ts'; +export * from './utils.ts'; diff --git a/node_modules/@inquirer/type/dist/esm/index.js b/node_modules/@inquirer/type/dist/esm/index.js new file mode 100644 index 0000000000000000000000000000000000000000..e5adf2cebe00efd432da5dbc3597d467a5e21176 --- /dev/null +++ b/node_modules/@inquirer/type/dist/esm/index.js @@ -0,0 +1,2 @@ +export * from "./inquirer.js"; +export * from "./utils.js"; diff --git a/node_modules/@inquirer/type/dist/esm/inquirer.d.ts b/node_modules/@inquirer/type/dist/esm/inquirer.d.ts new file mode 100644 index 0000000000000000000000000000000000000000..c1633eaf62847af1cf4d65f6b1be3791fc1cc647 --- /dev/null +++ b/node_modules/@inquirer/type/dist/esm/inquirer.d.ts @@ -0,0 +1,38 @@ +import { Duplex } from 'node:stream'; +/** + * `InquirerReadline` is a re-implementation of `readline.Interface` from Node.js. + * We're reimplementing it because of 3 reasons: + * 1. The `readline.Interface` API is not complete; it's missing for example `clearLine`. + * 2. The input/output streams are not generics, meaning they're inexact. + * 3. Since ReadLine isn't built-in Typescript Global NodeJS type, it'd force us to ship `@types/node` as a dependency to all users. + */ +export type InquirerReadline = { + output: Duplex & { + mute: () => void; + unmute: () => void; + }; + input: NodeJS.ReadableStream; + clearLine: (dir: 0 | 1 | -1) => void; + getCursorPos: () => { + rows: number; + cols: number; + }; + setPrompt: (prompt: string) => void; + line: string; + write: (data: string) => void; + on: (event: string, listener: (...args: unknown[]) => void) => void; + removeListener: (event: string, listener: (...args: unknown[]) => void) => void; + pause: () => void; + resume: () => void; + close: () => void; +}; +export type Context = { + input?: NodeJS.ReadableStream; + output?: NodeJS.WritableStream; + clearPromptOnDone?: boolean; + signal?: AbortSignal; +}; +export type Prompt = (config: Config, context?: Context) => Promise & { + /** @deprecated pass an AbortSignal in the context options instead. See {@link https://github.com/SBoudrias/Inquirer.js#canceling-prompt} */ + cancel: () => void; +}; diff --git a/node_modules/@inquirer/type/dist/esm/inquirer.js b/node_modules/@inquirer/type/dist/esm/inquirer.js new file mode 100644 index 0000000000000000000000000000000000000000..cb0ff5c3b541f646105198ee23ac0fc3d805023e --- /dev/null +++ b/node_modules/@inquirer/type/dist/esm/inquirer.js @@ -0,0 +1 @@ +export {}; diff --git a/node_modules/@inquirer/type/dist/esm/package.json b/node_modules/@inquirer/type/dist/esm/package.json new file mode 100644 index 0000000000000000000000000000000000000000..3dbc1ca591c0557e35b6004aeba250e6a70b56e3 --- /dev/null +++ b/node_modules/@inquirer/type/dist/esm/package.json @@ -0,0 +1,3 @@ +{ + "type": "module" +} diff --git a/node_modules/@inquirer/type/dist/esm/utils.d.ts b/node_modules/@inquirer/type/dist/esm/utils.d.ts new file mode 100644 index 0000000000000000000000000000000000000000..c37eb73af13648aa19eb0d77df8e93bb4e9af944 --- /dev/null +++ b/node_modules/@inquirer/type/dist/esm/utils.d.ts @@ -0,0 +1,29 @@ +type Key = string | number | symbol; +export type Prettify = { + [K in keyof T]: T[K]; +} & {}; +export type PartialDeep = T extends object ? { + [P in keyof T]?: PartialDeep; +} : T; +export type LiteralUnion = T | (F & {}); +export type KeyUnion = LiteralUnion>; +export type DistributiveMerge = A extends any ? Prettify & B> : never; +export type UnionToIntersection = (T extends any ? (input: T) => void : never) extends (input: infer Intersection) => void ? Intersection : never; +/** + * @hidden + */ +type __Pick = { + [P in K]: O[P]; +} & {}; +/** + * @hidden + */ +export type _Pick = __Pick; +/** + * Extract out of `O` the fields of key `K` + * @param O to extract from + * @param K to chose fields + * @returns [[Object]] + */ +export type Pick = O extends unknown ? _Pick : never; +export {}; diff --git a/node_modules/@inquirer/type/dist/esm/utils.js b/node_modules/@inquirer/type/dist/esm/utils.js new file mode 100644 index 0000000000000000000000000000000000000000..79413320c6e7f7f1a92966521f381ae5aa345c38 --- /dev/null +++ b/node_modules/@inquirer/type/dist/esm/utils.js @@ -0,0 +1,2 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ +export {}; diff --git a/node_modules/@inquirer/type/package.json b/node_modules/@inquirer/type/package.json new file mode 100644 index 0000000000000000000000000000000000000000..a081a2740a53dafd4c1f63ebdef8e0dc721f3853 --- /dev/null +++ b/node_modules/@inquirer/type/package.json @@ -0,0 +1,103 @@ +{ + "name": "@inquirer/type", + "version": "3.0.6", + "description": "Inquirer core TS types", + "keywords": [ + "answer", + "answers", + "ask", + "base", + "cli", + "command", + "command-line", + "confirm", + "enquirer", + "generate", + "generator", + "hyper", + "input", + "inquire", + "inquirer", + "interface", + "iterm", + "javascript", + "menu", + "node", + "nodejs", + "prompt", + "promptly", + "prompts", + "question", + "readline", + "scaffold", + "scaffolder", + "scaffolding", + "stdin", + "stdout", + "terminal", + "tty", + "ui", + "yeoman", + "yo", + "zsh", + "types", + "typescript" + ], + "repository": { + "type": "git", + "url": "https://github.com/SBoudrias/Inquirer.js.git" + }, + "license": "MIT", + "author": "Simon Boudrias ", + "sideEffects": false, + "type": "module", + "exports": { + "./package.json": "./package.json", + ".": { + "import": { + "types": "./dist/esm/index.d.ts", + "default": "./dist/esm/index.js" + }, + "require": { + "types": "./dist/commonjs/index.d.ts", + "default": "./dist/commonjs/index.js" + } + } + }, + "main": "./dist/commonjs/index.js", + "module": "./dist/esm/index.js", + "types": "./dist/commonjs/index.d.ts", + "files": [ + "dist" + ], + "scripts": { + "attw": "attw --pack", + "tsc": "tshy" + }, + "devDependencies": { + "@arethetypeswrong/cli": "^0.17.4", + "@repo/tsconfig": "workspace:*", + "tshy": "^3.0.2" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + }, + "engines": { + "node": ">=18" + }, + "tshy": { + "exclude": [ + "src/**/*.test.ts" + ], + "exports": { + "./package.json": "./package.json", + ".": "./src/index.ts" + } + }, + "gitHead": "d367155a8d64d8b3e93f9c763adccf708aedc8a8" +} diff --git a/node_modules/@mswjs/interceptors/ClientRequest/package.json b/node_modules/@mswjs/interceptors/ClientRequest/package.json new file mode 100644 index 0000000000000000000000000000000000000000..4ee863900b8d67f320b4675f3d9666ee10d61262 --- /dev/null +++ b/node_modules/@mswjs/interceptors/ClientRequest/package.json @@ -0,0 +1,6 @@ +{ + "main": "../lib/node/interceptors/ClientRequest/index.js", + "module": "../lib/node/interceptors/ClientRequest/index.mjs", + "browser": null, + "types": "../lib/node/interceptors/ClientRequest/index.d.ts" +} diff --git a/node_modules/@mswjs/interceptors/LICENSE.md b/node_modules/@mswjs/interceptors/LICENSE.md new file mode 100644 index 0000000000000000000000000000000000000000..e5c461e5fd63682eba93307cade8b073c7782489 --- /dev/null +++ b/node_modules/@mswjs/interceptors/LICENSE.md @@ -0,0 +1,9 @@ +MIT License + +Copyright (c) 2018–present Artem Zakharchenko + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/node_modules/@mswjs/interceptors/README.md b/node_modules/@mswjs/interceptors/README.md new file mode 100644 index 0000000000000000000000000000000000000000..42b0f228a85498cf7d9663d9d3a4840338ce460f --- /dev/null +++ b/node_modules/@mswjs/interceptors/README.md @@ -0,0 +1,623 @@ +[![Latest version](https://img.shields.io/npm/v/@mswjs/interceptors.svg)](https://www.npmjs.com/package/@mswjs/interceptors) + +# `@mswjs/interceptors` + +Low-level network interception library. + +This library supports intercepting the following protocols: + +- HTTP (via the `http` module, `XMLHttpRequest`, or `globalThis.fetch`); +- [WebSocket](#websocket-interception) (the `WebSocket` class in Undici and in the browser). + +## Motivation + +While there are a lot of network mocking libraries, they tend to use request interception as an implementation detail, giving you a high-level API that includes request matching, timeouts, recording, and so forth. + +This library is a barebones implementation that provides as little abstraction as possible to execute arbitrary logic upon any request. It's primarily designed as an underlying component for high-level API mocking solutions such as [Mock Service Worker](https://github.com/mswjs/msw). + +### How is this library different? + +A traditional API mocking implementation in Node.js looks roughly like this: + +```js +import http from 'node:http' + +// Store the original request function. +const originalHttpRequest = http.request + +// Override the request function entirely. +http.request = function (...args) { + // Decide if the outgoing request matches a predicate. + if (predicate(args)) { + // If it does, never create a request, respond to it + // using the mocked response from this blackbox. + return coerceToResponse.bind(this, mock) + } + + // Otherwise, construct the original request + // and perform it as-is. + return originalHttpRequest(...args) +} +``` + +The core philosophy of Interceptors is to _run as much of the underlying network code as possible_. Strange for a network mocking library, isn't it? Turns out, respecting the system's integrity and executing more of the network code leads to more resilient tests and also helps to uncover bugs in the code that would otherwise go unnoticed. + +Interceptors heavily rely on _class extension_ instead of function and module overrides. By extending the native network code, it can surgically insert the interception and mocking pieces only where necessary, leaving the rest of the system intact. + +```js +class XMLHttpRequestProxy extends XMLHttpRequest { + async send() { + // Call the request listeners and see if any of them + // returns a mocked response for this request. + const mockedResponse = await waitForRequestListeners({ request }) + + // If there is a mocked response, use it. This actually + // transitions the XMLHttpRequest instance into the correct + // response state (below is a simplified illustration). + if (mockedResponse) { + // Handle the response headers. + this.request.status = mockedResponse.status + this.request.statusText = mockedResponse.statusText + this.request.responseUrl = mockedResponse.url + this.readyState = 2 + this.trigger('readystatechange') + + // Start streaming the response body. + this.trigger('loadstart') + this.readyState = 3 + this.trigger('readystatechange') + await streamResponseBody(mockedResponse) + + // Finish the response. + this.trigger('load') + this.trigger('loadend') + this.readyState = 4 + return + } + + // Otherwise, perform the original "XMLHttpRequest.prototype.send" call. + return super.send(...args) + } +} +``` + +> The request interception algorithms differ dramatically based on the request API. Interceptors acommodate for them all, bringing the intercepted requests to a common ground—the Fetch API `Request` instance. The same applies for responses, where a Fetch API `Response` instance is translated to the appropriate response format. + +This library aims to provide _full specification compliance_ with the APIs and protocols it extends. + +## What this library does + +This library extends the following native modules: + +- `http.get`/`http.request` +- `https.get`/`https.request` +- `XMLHttpRequest` +- `fetch` +- `WebSocket` + +Once extended, it intercepts and normalizes all requests to the Fetch API `Request` instances. This way, no matter the request source (`http.ClientRequest`, `XMLHttpRequest`, `window.Request`, etc), you always get a specification-compliant request instance to work with. + +You can respond to the intercepted HTTP request by constructing a Fetch API Response instance. Instead of designing custom abstractions, this library respects the Fetch API specification and takes the responsibility to coerce a single response declaration to the appropriate response formats based on the request-issuing modules (like `http.OutgoingMessage` to respond to `http.ClientRequest`, or updating `XMLHttpRequest` response-related properties). + +## What this library doesn't do + +- Does **not** provide any request matching logic; +- Does **not** handle requests by default. + +## Getting started + +```bash +npm install @mswjs/interceptors +``` + +## Interceptors + +To use this library you need to choose one or multiple interceptors to apply. There are different interceptors exported by this library to spy on respective request-issuing modules: + +- `ClientRequestInterceptor` to spy on `http.ClientRequest` (`http.get`/`http.request`); +- `XMLHttpRequestInterceptor` to spy on `XMLHttpRequest`; +- `FetchInterceptor` to spy on `fetch`. + +Use an interceptor by constructing it and attaching request/response listeners: + +```js +import { ClientRequestInterceptor } from '@mswjs/interceptors/ClientRequest' + +const interceptor = new ClientRequestInterceptor() + +// Enable the interception of requests. +interceptor.apply() + +// Listen to any "http.ClientRequest" being dispatched, +// and log its method and full URL. +interceptor.on('request', ({ request, requestId }) => { + console.log(request.method, request.url) +}) + +// Listen to any responses sent to "http.ClientRequest". +// Note that this listener is read-only and cannot affect responses. +interceptor.on( + 'response', + ({ response, isMockedResponse, request, requestId }) => { + console.log('response to %s %s was:', request.method, request.url, response) + } +) +``` + +All HTTP request interceptors implement the same events: + +- `request`, emitted whenever a request has been dispatched; +- `response`, emitted whenever any request receives a response. + +### Using multiple interceptors + +You can combine multiple interceptors to capture requests from different request-issuing modules at once. + +```js +import { BatchInterceptor } from '@mswjs/interceptors' +import { ClientRequestInterceptor } from '@mswjs/interceptors/ClientRequest' +import { XMLHttpRequestInterceptor } from '@mswjs/interceptors/XMLHttpRequest' + +const interceptor = new BatchInterceptor({ + name: 'my-interceptor', + interceptors: [ + new ClientRequestInterceptor(), + new XMLHttpRequestInterceptor(), + ], +}) + +interceptor.apply() + +// This "request" listener will be called on both +// "http.ClientRequest" and "XMLHttpRequest" being dispatched. +interceptor.on('request', listener) +``` + +> Note that you can use [pre-defined presets](#presets) that cover all the request sources for a given environment type. + +## Presets + +When using [`BatchInterceptor`](#batchinterceptor), you can provide a pre-defined preset to its "interceptors" option to capture all request for that environment. + +### Node.js preset + +This preset combines `ClientRequestInterceptor`, `XMLHttpRequestInterceptor` and is meant to be used in Node.js. + +```js +import { BatchInterceptor } from '@mswjs/interceptors' +import nodeInterceptors from '@mswjs/interceptors/presets/node' + +const interceptor = new BatchInterceptor({ + name: 'my-interceptor', + interceptors: nodeInterceptors, +}) + +interceptor.apply() + +interceptor.on('request', listener) +``` + +### Browser preset + +This preset combines `XMLHttpRequestInterceptor` and `FetchInterceptor` and is meant to be used in a browser. + +```js +import { BatchInterceptor } from '@mswjs/interceptors' +import browserInterceptors from '@mswjs/interceptors/presets/browser' + +const interceptor = new BatchInterceptor({ + name: 'my-interceptor', + interceptors: browserInterceptors, +}) + +interceptor.on('request', listener) +``` + +## Introspecting requests + +All HTTP request interceptors emit a "request" event. In the listener to this event, they expose a `request` reference, which is a [Fetch API Request](https://developer.mozilla.org/en-US/docs/Web/API/Request) instance. + +> There are many ways to describe a request in Node.js but this library coerces different request definitions to a single specification-compliant `Request` instance to make the handling consistent. + +```js +interceptor.on('request', ({ request, requestId, controller }) => { + console.log(request.method, request.url) +}) +``` + +Since the exposed `request` instance implements the Fetch API specification, you can operate with it just as you do with the regular browser request. For example, this is how you would read the request body as JSON: + +```js +interceptor.on('request', async ({ request, requestId }) => { + const json = await request.clone().json() +}) +``` + +> **Do not forget to clone the request before reading its body!** + +## Modifying requests + +Request representations are readonly. You can, however, mutate the intercepted request's headers in the "request" listener: + +```js +interceptor.on('request', ({ request }) => { + request.headers.set('X-My-Header', 'true') +}) +``` + +> This restriction is done so that the library wouldn't have to unnecessarily synchronize the actual request instance and its Fetch API request representation. As of now, this library is not meant to be used as a full-scale proxy. + +## Mocking responses + +Although this library can be used purely for request introspection purposes, you can also affect request resolution by responding to any intercepted request within the "request" event. + +Access the `controller` object from the request event listener arguments and call its `controller.respondWith()` method, providing it with a mocked `Response` instance: + +```js +interceptor.on('request', ({ request, controller }) => { + controller.respondWith( + new Response( + JSON.stringify({ + firstName: 'John', + lastName: 'Maverick', + }), + { + status: 201, + statusText: 'Created', + headers: { + 'Content-Type': 'application/json', + }, + } + ) + ) +}) +``` + +> We use Fetch API `Response` class as the middle-ground for mocked response definition. This library then coerces the response instance to the appropriate response format (e.g. to `http.OutgoingMessage` in the case of `http.ClientRequest`). + +**The `Response` class is built-in in since Node.js 18. Use a Fetch API-compatible polyfill, like `node-fetch`, for older versions of Node.js.`** + +Note that a single request _can only be handled once_. You may want to introduce conditional logic, like routing, in your request listener but it's generally advised to use a higher-level library like [Mock Service Worker](https://github.com/mswjs/msw) that does request matching for you. + +Requests must be responded to within the same tick as the request listener. This means you cannot respond to a request using `setTimeout`, as this will delegate the callback to the next tick. If you wish to introduce asynchronous side-effects in the listener, consider making it an `async` function, awaiting any side-effects you need. + +```js +// Respond to all requests with a 500 response +// delayed by 500ms. +interceptor.on('request', async ({ controller }) => { + await sleep(500) + controller.respondWith(new Response(null, { status: 500 })) +}) +``` + +### Mocking response errors + +You can provide an instance of `Response.error()` to error the pending request. + +```js +interceptor.on('request', ({ request, controller }) => { + controller.respondWith(Response.error()) +}) +``` + +This will automatically translate to the appropriate request error based on the request client that issued the request. **Use this method to produce a generic network error**. + +> Note that the standard `Response.error()` API does not accept an error message. + +## Mocking errors + +Use the `controller.errorWith()` method to error the request. + +```js +interceptor.on('request', ({ request, controller }) => { + controller.errorWith(new Error('reason')) +}) +``` + +Unlike responding with `Response.error()`, you can provide an exact error reason to use to `.errorWith()`. **Use this method to error the request**. + +> Note that it is up to the request client to respect your custom error. Some clients, like `ClientRequest` will use the provided error message, while others, like `fetch`, will produce a generic `TypeError: failed to fetch` responses. Interceptors will try to preserve the original error in the `cause` property of such generic errors. + +## Observing responses + +You can use the "response" event to transparently observe any incoming responses in your Node.js process. + +```js +interceptor.on( + 'response', + ({ response, isMockedResponse, request, requestId }) => { + // react to the incoming response... + } +) +``` + +> Note that the `isMockedResponse` property will only be set to `true` if you resolved this request in the "request" event listener using the `controller.respondWith()` method and providing a mocked `Response` instance. + +## Error handling + +By default, all unhandled exceptions thrown within the `request` listener are coerced to 500 error responses, emulating those exceptions occurring on the actual server. You can listen to the exceptions by adding the `unhandledException` listener to the interceptor: + +```js +interceptor.on( + 'unhandledException', + ({ error, request, requestId, controller }) => { + console.log(error) + } +) +``` + +To opt out from the default coercion of unhandled exceptions to server responses, you need to either: + +1. Respond to the request with [a mocked response](#mocking-responses) (including error responses); +1. Propagate the error up by throwing it explicitly in the `unhandledException` listener. + +Here's an example of propagating the unhandled exception up: + +```js +interceptor.on('unhandledException', ({ error }) => { + // Now, any unhandled exception will NOT be coerced to a 500 error response, + // and instead will be thrown during the process execution as-is. + throw error +}) +``` + +## WebSocket interception + +You can intercept a WebSocket communication using the `WebSocketInterceptor` class. + +> [!IMPORTANT] +> This library only supports intercepting WebSocket connections created using the global WHATWG `WebSocket` class. Third-party transports, such as HTTP/XHR polling, are not supported by design due to their contrived nature. + +```js +import { WebSocketInterceptor } from '@mswjs/interceptors/WebSocket' + +const interceptor = new WebSocketInterceptor() +``` + +Unlike the HTTP-based interceptors that share the same `request`/`response` events, the WebSocket interceptor only emits the `connection` event and let's you handle the incoming/outgoing events in its listener. + +### Important defaults + +1. Intercepted WebSocket connections are _not opened_. To open the actual WebSocket connection, call [`server.connect()`](#connect) in the interceptor. +1. Once connected to the actual server, the outgoing client events are _forwarded to that server by default_. If you wish to prevent a client message from reaching the server, call `event.preventDefault()` for that client message event. +1. Once connected to the actual server, the incoming server events are _forwarded to the client by default_. If you wish to prevent a server message from reaching the client, call `event.preventDefault()` for the server message event. +1. Once connected to the actual server, the `close` event received from that server is _forwarded to the client by default_. If you wish to prevent that, call `event.preventDefault()` for that close event of the server. + +### WebSocket connection + +Whenever a WebSocket instance is constructed, the `connection` event is emitted on the WebSocket interceptor. + +```js +intereceptor.on('connection', ({ client }) => { + console.log(client.url) +}) +``` + +The `connection` event exposes the following arguments: + +| Name | Type | Description | +| -------- | --------------------------------------------------------- | ----------------------------------------------------------------------------------- | +| `client` | [`WebSocketClientConnection`](#websocketclientconnection) | An object representing a connected WebSocket client instance. | +| `server` | [`WebSocketServerConnection`](#websocketserverconnection) | An object representing the original WebSocket server connection. | +| `info` | `object` | Additional WebSocket connection information (like the original client `protocols`). | + +### `WebSocketClientConnection` + +#### `.addEventListener(type, listener)` + +- `type`, `string` +- `listener`, `EventListener` + +Adds an event listener to the given event type of the WebSocket client. + +```ts +interface WebSocketServerConnectionEventMap { + // Dispatched when the WebSocket client sends data. + message: (this: WebSocket, event: MessageEvent) => void + + // Dispatched when the WebSocket client is closed. + close: (this: WebSocket, event: CloseEvent) => void +} +``` + +```js +client.addEventListener('message', (event) => { + console.log('outgoing:', event.data) +}) +``` + +#### `.removeEventListener(type, listener)` + +- `type`, `string` +- `listener`, `EventListener` + +Removes the listener for the given event type. + +#### `.send(data)` + +- `data`, `string | Blob | ArrayBuffer` + +Sends the data to the intercepted WebSocket client. + +```js +client.send('text') +client.send(new Blob(['blob'])) +client.send(new TextEncoder().encode('array buffer')) +``` + +#### `.close(code, reason)` + +- `code`, close [status code](https://www.rfc-editor.org/rfc/rfc6455#section-7.4.1). +- `reason`, [close reason](https://www.rfc-editor.org/rfc/rfc6455#section-7.1.6). + +Closes the client connection. Unlike the regular `WebSocket.prototype.close()`, the `client.close()` method can accept a non-configurable status codes, such as 1001, 1003, etc. + +```js +// Gracefully close the connection with the +// intercepted WebSocket client. +client.close() +``` + +```js +// Terminate the connection by emulating +// the server unable to process the received data. +client.close(1003) +``` + +### `WebSocketServerConnection` + +#### `.connect()` + +Establishes the connection to the original WebSocket server. Connection cannot be awaited. Any data sent via `server.send()` while connecting is buffered and flushed once the connection is open. + +#### `.addEventListener(type, listener)` + +- `type`, `string` +- `listener`, `EventListener` + +Adds an event listener to the given event type of the WebSocket server. + +```ts +interface WebSocketServerConnectionEventMap { + // Dispatched when the server connection is open. + open: (this: WebSocket, event: Event) => void + + // Dispatched when the server sends data to the client. + message: (this: WebSocket, event: MessageEvent) => void + + // Dispatched when the server connection closes. + close: (this: WebSocket, event: CloseEvent) => void +} +``` + +```js +server.addEventListener('message', (event) => { + console.log('incoming:', event.data) +}) +``` + +#### `.removeEventListener(type, listener)` + +- `type`, `string` +- `listener`, `EventListener` + +Removes the listener for the given event type. + +#### `.send(data)` + +- `data`, `string | Blob | ArrayBuffer` + +Sends the data to the original WebSocket server. Useful in a combination with the client-sent events forwarding: + +```js +client.addEventListener('message', (event) => { + server.send(event.data) +}) +``` + +#### `.close()` + +Closes the connection with the original WebSocket server. Unlike `client.close()`, closing the server connection does not accept any arguments and always asumes a graceful closure. Sending data via `server.send()` after the connection has been closed will have no effect. + +## API + +### `Interceptor` + +A generic class implemented by all interceptors. You do not interact with this class directly. + +```ts +class Interceptor { + // Applies the interceptor, enabling the interception of requests + // in the current process. + apply(): void + + // Listens to the public interceptor events. + // For HTTP requests, these are "request' and "response" events. + on(event, listener): void + + // Cleans up any side-effects introduced by the interceptor + // and disables the interception of requests. + dispose(): void +} +``` + +**For public consumption, use [interceptors](#interceptors) instead**. + +### `BatchInterceptor` + +Applies multiple request interceptors at the same time. + +```js +import { BatchInterceptor } from '@mswjs/interceptors' +import nodeInterceptors from '@mswjs/interceptors/presets/node' + +const interceptor = new BatchInterceptor({ + name: 'my-interceptor', + interceptors: nodeInterceptors, +}) + +interceptor.apply() + +interceptor.on('request', ({ request, requestId }) => { + // Inspect the intercepted "request". + // Optionally, return a mocked response. +}) +``` + +> Using the `/presets/node` interceptors preset is the recommended way to ensure all requests get intercepted, regardless of their origin. + +### `RemoteHttpInterceptor` + +Enables request interception in the current process while delegating the response resolution logic to the _parent process_. **Requires the current process to be a child process**. Requires the parent process to establish a resolver by calling the `createRemoteResolver` function. + +```js +// child.js +import { RemoteHttpInterceptor } from '@mswjs/interceptors/RemoteHttpInterceptor' +import { ClientRequestInterceptor } from '@mswjs/interceptors/ClientRequest' + +const interceptor = new RemoteHttpInterceptor({ + // Alternatively, you can use presets. + interceptors: [new ClientRequestInterceptor()], +}) + +interceptor.apply() + +process.on('disconnect', () => { + interceptor.dispose() +}) +``` + +You can still listen to and handle any requests in the child process via the `request` event listener. Keep in mind that a single request can only be responded to once. + +### `RemoteHttpResolver` + +Resolves an intercepted request in the given child `process`. Requires for that child process to enable request interception by calling the `createRemoteInterceptor` function. + +```js +// parent.js +import { spawn } from 'child_process' +import { RemoteHttpResolver } from '@mswjs/interceptors/RemoteHttpInterceptor' + +const appProcess = spawn('node', ['app.js'], { + stdio: ['inherit', 'inherit', 'inherit', 'ipc'], +}) + +const resolver = new RemoteHttpResolver({ + process: appProcess, +}) + +resolver.on('request', ({ request, requestId }) => { + // Optionally, return a mocked response + // for a request that occurred in the "appProcess". +}) + +resolver.apply() +``` + +## Special mention + +The following libraries were used as an inspiration to write this low-level API: + +- [`node`](https://github.com/nodejs/node) +- [`nock`](https://github.com/nock/nock) +- [`mock-xmlhttprequest`](https://github.com/berniegp/mock-xmlhttprequest) diff --git a/node_modules/@mswjs/interceptors/RemoteHttpInterceptor/package.json b/node_modules/@mswjs/interceptors/RemoteHttpInterceptor/package.json new file mode 100644 index 0000000000000000000000000000000000000000..bc5d53aaffbbd17864028ec47062a66a0191a3c3 --- /dev/null +++ b/node_modules/@mswjs/interceptors/RemoteHttpInterceptor/package.json @@ -0,0 +1,6 @@ +{ + "main": "../lib/node/RemoteHttpInterceptor.js", + "module": "../lib/node/RemoteHttpInterceptor.mjs", + "browser": null, + "types": "../lib/node/RemoteHttpInterceptor.d.ts" +} diff --git a/node_modules/@mswjs/interceptors/WebSocket/package.json b/node_modules/@mswjs/interceptors/WebSocket/package.json new file mode 100644 index 0000000000000000000000000000000000000000..52dfef27bdab307504d8c85d5e789dfa00207656 --- /dev/null +++ b/node_modules/@mswjs/interceptors/WebSocket/package.json @@ -0,0 +1,5 @@ +{ + "main": "../lib/browser/interceptors/WebSocket/index.js", + "module": "../lib/browser/interceptors/WebSocket/index.mjs", + "types": "../lib/browser/interceptors/WebSocket/index.d.ts" +} diff --git a/node_modules/@mswjs/interceptors/XMLHttpRequest/package.json b/node_modules/@mswjs/interceptors/XMLHttpRequest/package.json new file mode 100644 index 0000000000000000000000000000000000000000..8830bae0e2f893df8e80629f10503719451f23e2 --- /dev/null +++ b/node_modules/@mswjs/interceptors/XMLHttpRequest/package.json @@ -0,0 +1,6 @@ +{ + "main": "../lib/node/interceptors/XMLHttpRequest/index.js", + "module": "../lib/node/interceptors/XMLHttpRequest/index.mjs", + "browser": "../lib/browser/interceptors/XMLHttpRequest/index.js", + "types": "../lib/node/interceptors/XMLHttpRequest/index.d.ts" +} diff --git a/node_modules/@mswjs/interceptors/fetch/package.json b/node_modules/@mswjs/interceptors/fetch/package.json new file mode 100644 index 0000000000000000000000000000000000000000..5e5dac857354660542b403210ae36e059a5478df --- /dev/null +++ b/node_modules/@mswjs/interceptors/fetch/package.json @@ -0,0 +1,6 @@ +{ + "main": "../lib/node/interceptors/fetch/index.js", + "module": "../lib/node/interceptors/fetch/index.mjs", + "browser": "../lib/browser/interceptors/fetch/index.js", + "types": "../lib/node/interceptors/fetch/index.d.ts" +} diff --git a/node_modules/@mswjs/interceptors/lib/browser/Interceptor-af98b768.d.ts b/node_modules/@mswjs/interceptors/lib/browser/Interceptor-af98b768.d.ts new file mode 100644 index 0000000000000000000000000000000000000000..257c42dde00d3a3d9e1cc073f6f7481c62186c2c --- /dev/null +++ b/node_modules/@mswjs/interceptors/lib/browser/Interceptor-af98b768.d.ts @@ -0,0 +1,63 @@ +import { Logger } from '@open-draft/logger'; +import { Emitter, Listener } from 'strict-event-emitter'; + +type InterceptorEventMap = Record; +type InterceptorSubscription = () => void; +/** + * Request header name to detect when a single request + * is being handled by nested interceptors (XHR -> ClientRequest). + * Obscure by design to prevent collisions with user-defined headers. + * Ideally, come up with the Interceptor-level mechanism for this. + * @see https://github.com/mswjs/interceptors/issues/378 + */ +declare const INTERNAL_REQUEST_ID_HEADER_NAME = "x-interceptors-internal-request-id"; +declare function getGlobalSymbol(symbol: Symbol): V | undefined; +declare function deleteGlobalSymbol(symbol: Symbol): void; +declare enum InterceptorReadyState { + INACTIVE = "INACTIVE", + APPLYING = "APPLYING", + APPLIED = "APPLIED", + DISPOSING = "DISPOSING", + DISPOSED = "DISPOSED" +} +type ExtractEventNames> = Events extends Record ? EventName : never; +declare class Interceptor { + private readonly symbol; + protected emitter: Emitter; + protected subscriptions: Array; + protected logger: Logger; + readyState: InterceptorReadyState; + constructor(symbol: symbol); + /** + * Determine if this interceptor can be applied + * in the current environment. + */ + protected checkEnvironment(): boolean; + /** + * Apply this interceptor to the current process. + * Returns an already running interceptor instance if it's present. + */ + apply(): void; + /** + * Setup the module augments and stubs necessary for this interceptor. + * This method is not run if there's a running interceptor instance + * to prevent instantiating an interceptor multiple times. + */ + protected setup(): void; + /** + * Listen to the interceptor's public events. + */ + on>(event: EventName, listener: Listener): this; + once>(event: EventName, listener: Listener): this; + off>(event: EventName, listener: Listener): this; + removeAllListeners>(event?: EventName): this; + /** + * Disposes of any side-effects this interceptor has introduced. + */ + dispose(): void; + private getInstance; + private setInstance; + private clearInstance; +} + +export { ExtractEventNames as E, Interceptor as I, InterceptorEventMap as a, InterceptorSubscription as b, INTERNAL_REQUEST_ID_HEADER_NAME as c, deleteGlobalSymbol as d, InterceptorReadyState as e, getGlobalSymbol as g }; diff --git a/node_modules/@mswjs/interceptors/lib/browser/chunk-5UK33FSU.mjs b/node_modules/@mswjs/interceptors/lib/browser/chunk-5UK33FSU.mjs new file mode 100644 index 0000000000000000000000000000000000000000..73f3289ca9d471f0f2e767bd926d8c27375a4209 --- /dev/null +++ b/node_modules/@mswjs/interceptors/lib/browser/chunk-5UK33FSU.mjs @@ -0,0 +1,83 @@ +// src/glossary.ts +var IS_PATCHED_MODULE = Symbol("isPatchedModule"); + +// src/utils/fetchUtils.ts +var _FetchResponse = class extends Response { + static isConfigurableStatusCode(status) { + return status >= 200 && status <= 599; + } + static isRedirectResponse(status) { + return _FetchResponse.STATUS_CODES_WITH_REDIRECT.includes(status); + } + /** + * Returns a boolean indicating whether the given response status + * code represents a response that can have a body. + */ + static isResponseWithBody(status) { + return !_FetchResponse.STATUS_CODES_WITHOUT_BODY.includes(status); + } + static setUrl(url, response) { + if (!url) { + return; + } + if (response.url != "") { + return; + } + Object.defineProperty(response, "url", { + value: url, + enumerable: true, + configurable: true, + writable: false + }); + } + /** + * Parses the given raw HTTP headers into a Fetch API `Headers` instance. + */ + static parseRawHeaders(rawHeaders) { + const headers = new Headers(); + for (let line = 0; line < rawHeaders.length; line += 2) { + headers.append(rawHeaders[line], rawHeaders[line + 1]); + } + return headers; + } + constructor(body, init = {}) { + var _a; + const status = (_a = init.status) != null ? _a : 200; + const safeStatus = _FetchResponse.isConfigurableStatusCode(status) ? status : 200; + const finalBody = _FetchResponse.isResponseWithBody(status) ? body : null; + super(finalBody, { + ...init, + status: safeStatus + }); + if (status !== safeStatus) { + const stateSymbol = Object.getOwnPropertySymbols(this).find( + (symbol) => symbol.description === "state" + ); + if (stateSymbol) { + const state = Reflect.get(this, stateSymbol); + Reflect.set(state, "status", status); + } else { + Object.defineProperty(this, "status", { + value: status, + enumerable: true, + configurable: true, + writable: false + }); + } + } + _FetchResponse.setUrl(init.url, this); + } +}; +var FetchResponse = _FetchResponse; +/** + * Response status codes for responses that cannot have body. + * @see https://fetch.spec.whatwg.org/#statuses + */ +FetchResponse.STATUS_CODES_WITHOUT_BODY = [101, 103, 204, 205, 304]; +FetchResponse.STATUS_CODES_WITH_REDIRECT = [301, 302, 303, 307, 308]; + +export { + IS_PATCHED_MODULE, + FetchResponse +}; +//# sourceMappingURL=chunk-5UK33FSU.mjs.map \ No newline at end of file diff --git a/node_modules/@mswjs/interceptors/lib/browser/chunk-5UK33FSU.mjs.map b/node_modules/@mswjs/interceptors/lib/browser/chunk-5UK33FSU.mjs.map new file mode 100644 index 0000000000000000000000000000000000000000..df0c20792cba1a67a25bef18ba2a7e80c8c2aa41 --- /dev/null +++ b/node_modules/@mswjs/interceptors/lib/browser/chunk-5UK33FSU.mjs.map @@ -0,0 +1 @@ +{"version":3,"sources":["../../src/glossary.ts","../../src/utils/fetchUtils.ts"],"sourcesContent":["import type { RequestController } from './RequestController'\n\nexport const IS_PATCHED_MODULE: unique symbol = Symbol('isPatchedModule')\n\n/**\n * @note Export `RequestController` as a type only.\n * It's never meant to be created in the userland.\n */\nexport type { RequestController }\n\nexport type RequestCredentials = 'omit' | 'include' | 'same-origin'\n\nexport type HttpRequestEventMap = {\n request: [\n args: {\n request: Request\n requestId: string\n controller: RequestController\n }\n ]\n response: [\n args: {\n response: Response\n isMockedResponse: boolean\n request: Request\n requestId: string\n }\n ]\n unhandledException: [\n args: {\n error: unknown\n request: Request\n requestId: string\n controller: RequestController\n }\n ]\n}\n","export interface FetchResponseInit extends ResponseInit {\n url?: string\n}\n\nexport class FetchResponse extends Response {\n /**\n * Response status codes for responses that cannot have body.\n * @see https://fetch.spec.whatwg.org/#statuses\n */\n static readonly STATUS_CODES_WITHOUT_BODY = [101, 103, 204, 205, 304]\n\n static readonly STATUS_CODES_WITH_REDIRECT = [301, 302, 303, 307, 308]\n\n static isConfigurableStatusCode(status: number): boolean {\n return status >= 200 && status <= 599\n }\n\n static isRedirectResponse(status: number): boolean {\n return FetchResponse.STATUS_CODES_WITH_REDIRECT.includes(status)\n }\n\n /**\n * Returns a boolean indicating whether the given response status\n * code represents a response that can have a body.\n */\n static isResponseWithBody(status: number): boolean {\n return !FetchResponse.STATUS_CODES_WITHOUT_BODY.includes(status)\n }\n\n static setUrl(url: string | undefined, response: Response): void {\n if (!url) {\n return\n }\n\n if (response.url != '') {\n return\n }\n\n Object.defineProperty(response, 'url', {\n value: url,\n enumerable: true,\n configurable: true,\n writable: false,\n })\n }\n\n /**\n * Parses the given raw HTTP headers into a Fetch API `Headers` instance.\n */\n static parseRawHeaders(rawHeaders: Array): Headers {\n const headers = new Headers()\n for (let line = 0; line < rawHeaders.length; line += 2) {\n headers.append(rawHeaders[line], rawHeaders[line + 1])\n }\n return headers\n }\n\n constructor(body?: BodyInit | null, init: FetchResponseInit = {}) {\n const status = init.status ?? 200\n const safeStatus = FetchResponse.isConfigurableStatusCode(status)\n ? status\n : 200\n const finalBody = FetchResponse.isResponseWithBody(status) ? body : null\n\n super(finalBody, {\n ...init,\n status: safeStatus,\n })\n\n if (status !== safeStatus) {\n /**\n * @note Undici keeps an internal \"Symbol(state)\" that holds\n * the actual value of response status. Update that in Node.js.\n */\n const stateSymbol = Object.getOwnPropertySymbols(this).find(\n (symbol) => symbol.description === 'state'\n )\n if (stateSymbol) {\n const state = Reflect.get(this, stateSymbol) as object\n Reflect.set(state, 'status', status)\n } else {\n Object.defineProperty(this, 'status', {\n value: status,\n enumerable: true,\n configurable: true,\n writable: false,\n })\n }\n }\n\n FetchResponse.setUrl(init.url, this)\n }\n}\n"],"mappings":";AAEO,IAAM,oBAAmC,OAAO,iBAAiB;;;ACEjE,IAAM,iBAAN,cAA4B,SAAS;AAAA,EAS1C,OAAO,yBAAyB,QAAyB;AACvD,WAAO,UAAU,OAAO,UAAU;AAAA,EACpC;AAAA,EAEA,OAAO,mBAAmB,QAAyB;AACjD,WAAO,eAAc,2BAA2B,SAAS,MAAM;AAAA,EACjE;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,OAAO,mBAAmB,QAAyB;AACjD,WAAO,CAAC,eAAc,0BAA0B,SAAS,MAAM;AAAA,EACjE;AAAA,EAEA,OAAO,OAAO,KAAyB,UAA0B;AAC/D,QAAI,CAAC,KAAK;AACR;AAAA,IACF;AAEA,QAAI,SAAS,OAAO,IAAI;AACtB;AAAA,IACF;AAEA,WAAO,eAAe,UAAU,OAAO;AAAA,MACrC,OAAO;AAAA,MACP,YAAY;AAAA,MACZ,cAAc;AAAA,MACd,UAAU;AAAA,IACZ,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA,EAKA,OAAO,gBAAgB,YAAoC;AACzD,UAAM,UAAU,IAAI,QAAQ;AAC5B,aAAS,OAAO,GAAG,OAAO,WAAW,QAAQ,QAAQ,GAAG;AACtD,cAAQ,OAAO,WAAW,IAAI,GAAG,WAAW,OAAO,CAAC,CAAC;AAAA,IACvD;AACA,WAAO;AAAA,EACT;AAAA,EAEA,YAAY,MAAwB,OAA0B,CAAC,GAAG;AAzDpE;AA0DI,UAAM,UAAS,UAAK,WAAL,YAAe;AAC9B,UAAM,aAAa,eAAc,yBAAyB,MAAM,IAC5D,SACA;AACJ,UAAM,YAAY,eAAc,mBAAmB,MAAM,IAAI,OAAO;AAEpE,UAAM,WAAW;AAAA,MACf,GAAG;AAAA,MACH,QAAQ;AAAA,IACV,CAAC;AAED,QAAI,WAAW,YAAY;AAKzB,YAAM,cAAc,OAAO,sBAAsB,IAAI,EAAE;AAAA,QACrD,CAAC,WAAW,OAAO,gBAAgB;AAAA,MACrC;AACA,UAAI,aAAa;AACf,cAAM,QAAQ,QAAQ,IAAI,MAAM,WAAW;AAC3C,gBAAQ,IAAI,OAAO,UAAU,MAAM;AAAA,MACrC,OAAO;AACL,eAAO,eAAe,MAAM,UAAU;AAAA,UACpC,OAAO;AAAA,UACP,YAAY;AAAA,UACZ,cAAc;AAAA,UACd,UAAU;AAAA,QACZ,CAAC;AAAA,MACH;AAAA,IACF;AAEA,mBAAc,OAAO,KAAK,KAAK,IAAI;AAAA,EACrC;AACF;AAxFO,IAAM,gBAAN;AAAA;AAAA;AAAA;AAAA;AAAM,cAKK,4BAA4B,CAAC,KAAK,KAAK,KAAK,KAAK,GAAG;AALzD,cAOK,6BAA6B,CAAC,KAAK,KAAK,KAAK,KAAK,GAAG;","names":[]} \ No newline at end of file diff --git a/node_modules/@mswjs/interceptors/lib/browser/chunk-6HYIRFX2.mjs b/node_modules/@mswjs/interceptors/lib/browser/chunk-6HYIRFX2.mjs new file mode 100644 index 0000000000000000000000000000000000000000..05b6c33cb2dec03c23115c9c1de440c0a0a10277 --- /dev/null +++ b/node_modules/@mswjs/interceptors/lib/browser/chunk-6HYIRFX2.mjs @@ -0,0 +1,22 @@ +// src/utils/bufferUtils.ts +var encoder = new TextEncoder(); +function encodeBuffer(text) { + return encoder.encode(text); +} +function decodeBuffer(buffer, encoding) { + const decoder = new TextDecoder(encoding); + return decoder.decode(buffer); +} +function toArrayBuffer(array) { + return array.buffer.slice( + array.byteOffset, + array.byteOffset + array.byteLength + ); +} + +export { + encodeBuffer, + decodeBuffer, + toArrayBuffer +}; +//# sourceMappingURL=chunk-6HYIRFX2.mjs.map \ No newline at end of file diff --git a/node_modules/@mswjs/interceptors/lib/browser/chunk-6HYIRFX2.mjs.map b/node_modules/@mswjs/interceptors/lib/browser/chunk-6HYIRFX2.mjs.map new file mode 100644 index 0000000000000000000000000000000000000000..6f27915c41e396fe4b28381b580d8fc7fdffbb3b --- /dev/null +++ b/node_modules/@mswjs/interceptors/lib/browser/chunk-6HYIRFX2.mjs.map @@ -0,0 +1 @@ +{"version":3,"sources":["../../src/utils/bufferUtils.ts"],"sourcesContent":["const encoder = new TextEncoder()\n\nexport function encodeBuffer(text: string): Uint8Array {\n return encoder.encode(text)\n}\n\nexport function decodeBuffer(buffer: ArrayBuffer, encoding?: string): string {\n const decoder = new TextDecoder(encoding)\n return decoder.decode(buffer)\n}\n\n/**\n * Create an `ArrayBuffer` from the given `Uint8Array`.\n * Takes the byte offset into account to produce the right buffer\n * in the case when the buffer is bigger than the data view.\n */\nexport function toArrayBuffer(array: Uint8Array): ArrayBuffer {\n return array.buffer.slice(\n array.byteOffset,\n array.byteOffset + array.byteLength\n )\n}\n"],"mappings":";AAAA,IAAM,UAAU,IAAI,YAAY;AAEzB,SAAS,aAAa,MAA0B;AACrD,SAAO,QAAQ,OAAO,IAAI;AAC5B;AAEO,SAAS,aAAa,QAAqB,UAA2B;AAC3E,QAAM,UAAU,IAAI,YAAY,QAAQ;AACxC,SAAO,QAAQ,OAAO,MAAM;AAC9B;AAOO,SAAS,cAAc,OAAgC;AAC5D,SAAO,MAAM,OAAO;AAAA,IAClB,MAAM;AAAA,IACN,MAAM,aAAa,MAAM;AAAA,EAC3B;AACF;","names":[]} \ No newline at end of file diff --git a/node_modules/@mswjs/interceptors/lib/browser/chunk-BC2BLJQN.js b/node_modules/@mswjs/interceptors/lib/browser/chunk-BC2BLJQN.js new file mode 100644 index 0000000000000000000000000000000000000000..dfa8d168b7a5fb7aebbeaefe0a1147f5246a9318 --- /dev/null +++ b/node_modules/@mswjs/interceptors/lib/browser/chunk-BC2BLJQN.js @@ -0,0 +1,83 @@ +"use strict";Object.defineProperty(exports, "__esModule", {value: true});// src/glossary.ts +var IS_PATCHED_MODULE = Symbol("isPatchedModule"); + +// src/utils/fetchUtils.ts +var _FetchResponse = class extends Response { + static isConfigurableStatusCode(status) { + return status >= 200 && status <= 599; + } + static isRedirectResponse(status) { + return _FetchResponse.STATUS_CODES_WITH_REDIRECT.includes(status); + } + /** + * Returns a boolean indicating whether the given response status + * code represents a response that can have a body. + */ + static isResponseWithBody(status) { + return !_FetchResponse.STATUS_CODES_WITHOUT_BODY.includes(status); + } + static setUrl(url, response) { + if (!url) { + return; + } + if (response.url != "") { + return; + } + Object.defineProperty(response, "url", { + value: url, + enumerable: true, + configurable: true, + writable: false + }); + } + /** + * Parses the given raw HTTP headers into a Fetch API `Headers` instance. + */ + static parseRawHeaders(rawHeaders) { + const headers = new Headers(); + for (let line = 0; line < rawHeaders.length; line += 2) { + headers.append(rawHeaders[line], rawHeaders[line + 1]); + } + return headers; + } + constructor(body, init = {}) { + var _a; + const status = (_a = init.status) != null ? _a : 200; + const safeStatus = _FetchResponse.isConfigurableStatusCode(status) ? status : 200; + const finalBody = _FetchResponse.isResponseWithBody(status) ? body : null; + super(finalBody, { + ...init, + status: safeStatus + }); + if (status !== safeStatus) { + const stateSymbol = Object.getOwnPropertySymbols(this).find( + (symbol) => symbol.description === "state" + ); + if (stateSymbol) { + const state = Reflect.get(this, stateSymbol); + Reflect.set(state, "status", status); + } else { + Object.defineProperty(this, "status", { + value: status, + enumerable: true, + configurable: true, + writable: false + }); + } + } + _FetchResponse.setUrl(init.url, this); + } +}; +var FetchResponse = _FetchResponse; +/** + * Response status codes for responses that cannot have body. + * @see https://fetch.spec.whatwg.org/#statuses + */ +FetchResponse.STATUS_CODES_WITHOUT_BODY = [101, 103, 204, 205, 304]; +FetchResponse.STATUS_CODES_WITH_REDIRECT = [301, 302, 303, 307, 308]; + + + + +exports.IS_PATCHED_MODULE = IS_PATCHED_MODULE; exports.FetchResponse = FetchResponse; +//# sourceMappingURL=chunk-BC2BLJQN.js.map \ No newline at end of file diff --git a/node_modules/@mswjs/interceptors/lib/browser/chunk-BC2BLJQN.js.map b/node_modules/@mswjs/interceptors/lib/browser/chunk-BC2BLJQN.js.map new file mode 100644 index 0000000000000000000000000000000000000000..5fbb9c76b8f37c0ace3a61e11d65d00342462380 --- /dev/null +++ b/node_modules/@mswjs/interceptors/lib/browser/chunk-BC2BLJQN.js.map @@ -0,0 +1 @@ +{"version":3,"sources":["../../src/glossary.ts","../../src/utils/fetchUtils.ts"],"names":[],"mappings":";AAEO,IAAM,oBAAmC,OAAO,iBAAiB;;;ACEjE,IAAM,iBAAN,cAA4B,SAAS;AAAA,EAS1C,OAAO,yBAAyB,QAAyB;AACvD,WAAO,UAAU,OAAO,UAAU;AAAA,EACpC;AAAA,EAEA,OAAO,mBAAmB,QAAyB;AACjD,WAAO,eAAc,2BAA2B,SAAS,MAAM;AAAA,EACjE;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,OAAO,mBAAmB,QAAyB;AACjD,WAAO,CAAC,eAAc,0BAA0B,SAAS,MAAM;AAAA,EACjE;AAAA,EAEA,OAAO,OAAO,KAAyB,UAA0B;AAC/D,QAAI,CAAC,KAAK;AACR;AAAA,IACF;AAEA,QAAI,SAAS,OAAO,IAAI;AACtB;AAAA,IACF;AAEA,WAAO,eAAe,UAAU,OAAO;AAAA,MACrC,OAAO;AAAA,MACP,YAAY;AAAA,MACZ,cAAc;AAAA,MACd,UAAU;AAAA,IACZ,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA,EAKA,OAAO,gBAAgB,YAAoC;AACzD,UAAM,UAAU,IAAI,QAAQ;AAC5B,aAAS,OAAO,GAAG,OAAO,WAAW,QAAQ,QAAQ,GAAG;AACtD,cAAQ,OAAO,WAAW,IAAI,GAAG,WAAW,OAAO,CAAC,CAAC;AAAA,IACvD;AACA,WAAO;AAAA,EACT;AAAA,EAEA,YAAY,MAAwB,OAA0B,CAAC,GAAG;AAzDpE;AA0DI,UAAM,UAAS,UAAK,WAAL,YAAe;AAC9B,UAAM,aAAa,eAAc,yBAAyB,MAAM,IAC5D,SACA;AACJ,UAAM,YAAY,eAAc,mBAAmB,MAAM,IAAI,OAAO;AAEpE,UAAM,WAAW;AAAA,MACf,GAAG;AAAA,MACH,QAAQ;AAAA,IACV,CAAC;AAED,QAAI,WAAW,YAAY;AAKzB,YAAM,cAAc,OAAO,sBAAsB,IAAI,EAAE;AAAA,QACrD,CAAC,WAAW,OAAO,gBAAgB;AAAA,MACrC;AACA,UAAI,aAAa;AACf,cAAM,QAAQ,QAAQ,IAAI,MAAM,WAAW;AAC3C,gBAAQ,IAAI,OAAO,UAAU,MAAM;AAAA,MACrC,OAAO;AACL,eAAO,eAAe,MAAM,UAAU;AAAA,UACpC,OAAO;AAAA,UACP,YAAY;AAAA,UACZ,cAAc;AAAA,UACd,UAAU;AAAA,QACZ,CAAC;AAAA,MACH;AAAA,IACF;AAEA,mBAAc,OAAO,KAAK,KAAK,IAAI;AAAA,EACrC;AACF;AAxFO,IAAM,gBAAN;AAAA;AAAA;AAAA;AAAA;AAAM,cAKK,4BAA4B,CAAC,KAAK,KAAK,KAAK,KAAK,GAAG;AALzD,cAOK,6BAA6B,CAAC,KAAK,KAAK,KAAK,KAAK,GAAG","sourcesContent":["import type { RequestController } from './RequestController'\n\nexport const IS_PATCHED_MODULE: unique symbol = Symbol('isPatchedModule')\n\n/**\n * @note Export `RequestController` as a type only.\n * It's never meant to be created in the userland.\n */\nexport type { RequestController }\n\nexport type RequestCredentials = 'omit' | 'include' | 'same-origin'\n\nexport type HttpRequestEventMap = {\n request: [\n args: {\n request: Request\n requestId: string\n controller: RequestController\n }\n ]\n response: [\n args: {\n response: Response\n isMockedResponse: boolean\n request: Request\n requestId: string\n }\n ]\n unhandledException: [\n args: {\n error: unknown\n request: Request\n requestId: string\n controller: RequestController\n }\n ]\n}\n","export interface FetchResponseInit extends ResponseInit {\n url?: string\n}\n\nexport class FetchResponse extends Response {\n /**\n * Response status codes for responses that cannot have body.\n * @see https://fetch.spec.whatwg.org/#statuses\n */\n static readonly STATUS_CODES_WITHOUT_BODY = [101, 103, 204, 205, 304]\n\n static readonly STATUS_CODES_WITH_REDIRECT = [301, 302, 303, 307, 308]\n\n static isConfigurableStatusCode(status: number): boolean {\n return status >= 200 && status <= 599\n }\n\n static isRedirectResponse(status: number): boolean {\n return FetchResponse.STATUS_CODES_WITH_REDIRECT.includes(status)\n }\n\n /**\n * Returns a boolean indicating whether the given response status\n * code represents a response that can have a body.\n */\n static isResponseWithBody(status: number): boolean {\n return !FetchResponse.STATUS_CODES_WITHOUT_BODY.includes(status)\n }\n\n static setUrl(url: string | undefined, response: Response): void {\n if (!url) {\n return\n }\n\n if (response.url != '') {\n return\n }\n\n Object.defineProperty(response, 'url', {\n value: url,\n enumerable: true,\n configurable: true,\n writable: false,\n })\n }\n\n /**\n * Parses the given raw HTTP headers into a Fetch API `Headers` instance.\n */\n static parseRawHeaders(rawHeaders: Array): Headers {\n const headers = new Headers()\n for (let line = 0; line < rawHeaders.length; line += 2) {\n headers.append(rawHeaders[line], rawHeaders[line + 1])\n }\n return headers\n }\n\n constructor(body?: BodyInit | null, init: FetchResponseInit = {}) {\n const status = init.status ?? 200\n const safeStatus = FetchResponse.isConfigurableStatusCode(status)\n ? status\n : 200\n const finalBody = FetchResponse.isResponseWithBody(status) ? body : null\n\n super(finalBody, {\n ...init,\n status: safeStatus,\n })\n\n if (status !== safeStatus) {\n /**\n * @note Undici keeps an internal \"Symbol(state)\" that holds\n * the actual value of response status. Update that in Node.js.\n */\n const stateSymbol = Object.getOwnPropertySymbols(this).find(\n (symbol) => symbol.description === 'state'\n )\n if (stateSymbol) {\n const state = Reflect.get(this, stateSymbol) as object\n Reflect.set(state, 'status', status)\n } else {\n Object.defineProperty(this, 'status', {\n value: status,\n enumerable: true,\n configurable: true,\n writable: false,\n })\n }\n }\n\n FetchResponse.setUrl(init.url, this)\n }\n}\n"]} \ No newline at end of file diff --git a/node_modules/@mswjs/interceptors/lib/browser/chunk-DODHRDV6.mjs b/node_modules/@mswjs/interceptors/lib/browser/chunk-DODHRDV6.mjs new file mode 100644 index 0000000000000000000000000000000000000000..42d1cced71825d62bf90f928bd7b17f813d91d45 --- /dev/null +++ b/node_modules/@mswjs/interceptors/lib/browser/chunk-DODHRDV6.mjs @@ -0,0 +1,844 @@ +import { + decodeBuffer, + encodeBuffer, + toArrayBuffer +} from "./chunk-6HYIRFX2.mjs"; +import { + RequestController, + handleRequest +} from "./chunk-H5O73WD2.mjs"; +import { + FetchResponse, + IS_PATCHED_MODULE +} from "./chunk-5UK33FSU.mjs"; +import { + hasConfigurableGlobal +} from "./chunk-TX5GBTFY.mjs"; +import { + INTERNAL_REQUEST_ID_HEADER_NAME, + Interceptor, + createRequestId +} from "./chunk-QED3Q6Z2.mjs"; + +// src/interceptors/XMLHttpRequest/index.ts +import { invariant as invariant2 } from "outvariant"; + +// src/interceptors/XMLHttpRequest/XMLHttpRequestController.ts +import { invariant } from "outvariant"; +import { isNodeProcess } from "is-node-process"; + +// src/interceptors/XMLHttpRequest/utils/concatArrayBuffer.ts +function concatArrayBuffer(left, right) { + const result = new Uint8Array(left.byteLength + right.byteLength); + result.set(left, 0); + result.set(right, left.byteLength); + return result; +} + +// src/interceptors/XMLHttpRequest/polyfills/EventPolyfill.ts +var EventPolyfill = class { + constructor(type, options) { + this.NONE = 0; + this.CAPTURING_PHASE = 1; + this.AT_TARGET = 2; + this.BUBBLING_PHASE = 3; + this.type = ""; + this.srcElement = null; + this.currentTarget = null; + this.eventPhase = 0; + this.isTrusted = true; + this.composed = false; + this.cancelable = true; + this.defaultPrevented = false; + this.bubbles = true; + this.lengthComputable = true; + this.loaded = 0; + this.total = 0; + this.cancelBubble = false; + this.returnValue = true; + this.type = type; + this.target = (options == null ? void 0 : options.target) || null; + this.currentTarget = (options == null ? void 0 : options.currentTarget) || null; + this.timeStamp = Date.now(); + } + composedPath() { + return []; + } + initEvent(type, bubbles, cancelable) { + this.type = type; + this.bubbles = !!bubbles; + this.cancelable = !!cancelable; + } + preventDefault() { + this.defaultPrevented = true; + } + stopPropagation() { + } + stopImmediatePropagation() { + } +}; + +// src/interceptors/XMLHttpRequest/polyfills/ProgressEventPolyfill.ts +var ProgressEventPolyfill = class extends EventPolyfill { + constructor(type, init) { + super(type); + this.lengthComputable = (init == null ? void 0 : init.lengthComputable) || false; + this.composed = (init == null ? void 0 : init.composed) || false; + this.loaded = (init == null ? void 0 : init.loaded) || 0; + this.total = (init == null ? void 0 : init.total) || 0; + } +}; + +// src/interceptors/XMLHttpRequest/utils/createEvent.ts +var SUPPORTS_PROGRESS_EVENT = typeof ProgressEvent !== "undefined"; +function createEvent(target, type, init) { + const progressEvents = [ + "error", + "progress", + "loadstart", + "loadend", + "load", + "timeout", + "abort" + ]; + const ProgressEventClass = SUPPORTS_PROGRESS_EVENT ? ProgressEvent : ProgressEventPolyfill; + const event = progressEvents.includes(type) ? new ProgressEventClass(type, { + lengthComputable: true, + loaded: (init == null ? void 0 : init.loaded) || 0, + total: (init == null ? void 0 : init.total) || 0 + }) : new EventPolyfill(type, { + target, + currentTarget: target + }); + return event; +} + +// src/utils/findPropertySource.ts +function findPropertySource(target, propertyName) { + if (!(propertyName in target)) { + return null; + } + const hasProperty = Object.prototype.hasOwnProperty.call(target, propertyName); + if (hasProperty) { + return target; + } + const prototype = Reflect.getPrototypeOf(target); + return prototype ? findPropertySource(prototype, propertyName) : null; +} + +// src/utils/createProxy.ts +function createProxy(target, options) { + const proxy = new Proxy(target, optionsToProxyHandler(options)); + return proxy; +} +function optionsToProxyHandler(options) { + const { constructorCall, methodCall, getProperty, setProperty } = options; + const handler = {}; + if (typeof constructorCall !== "undefined") { + handler.construct = function(target, args, newTarget) { + const next = Reflect.construct.bind(null, target, args, newTarget); + return constructorCall.call(newTarget, args, next); + }; + } + handler.set = function(target, propertyName, nextValue) { + const next = () => { + const propertySource = findPropertySource(target, propertyName) || target; + const ownDescriptors = Reflect.getOwnPropertyDescriptor( + propertySource, + propertyName + ); + if (typeof (ownDescriptors == null ? void 0 : ownDescriptors.set) !== "undefined") { + ownDescriptors.set.apply(target, [nextValue]); + return true; + } + return Reflect.defineProperty(propertySource, propertyName, { + writable: true, + enumerable: true, + configurable: true, + value: nextValue + }); + }; + if (typeof setProperty !== "undefined") { + return setProperty.call(target, [propertyName, nextValue], next); + } + return next(); + }; + handler.get = function(target, propertyName, receiver) { + const next = () => target[propertyName]; + const value = typeof getProperty !== "undefined" ? getProperty.call(target, [propertyName, receiver], next) : next(); + if (typeof value === "function") { + return (...args) => { + const next2 = value.bind(target, ...args); + if (typeof methodCall !== "undefined") { + return methodCall.call(target, [propertyName, args], next2); + } + return next2(); + }; + } + return value; + }; + return handler; +} + +// src/interceptors/XMLHttpRequest/utils/isDomParserSupportedType.ts +function isDomParserSupportedType(type) { + const supportedTypes = [ + "application/xhtml+xml", + "application/xml", + "image/svg+xml", + "text/html", + "text/xml" + ]; + return supportedTypes.some((supportedType) => { + return type.startsWith(supportedType); + }); +} + +// src/utils/parseJson.ts +function parseJson(data) { + try { + const json = JSON.parse(data); + return json; + } catch (_) { + return null; + } +} + +// src/interceptors/XMLHttpRequest/utils/createResponse.ts +function createResponse(request, body) { + const responseBodyOrNull = FetchResponse.isResponseWithBody(request.status) ? body : null; + return new FetchResponse(responseBodyOrNull, { + url: request.responseURL, + status: request.status, + statusText: request.statusText, + headers: createHeadersFromXMLHttpReqestHeaders( + request.getAllResponseHeaders() + ) + }); +} +function createHeadersFromXMLHttpReqestHeaders(headersString) { + const headers = new Headers(); + const lines = headersString.split(/[\r\n]+/); + for (const line of lines) { + if (line.trim() === "") { + continue; + } + const [name, ...parts] = line.split(": "); + const value = parts.join(": "); + headers.append(name, value); + } + return headers; +} + +// src/interceptors/XMLHttpRequest/utils/getBodyByteLength.ts +async function getBodyByteLength(input) { + const explicitContentLength = input.headers.get("content-length"); + if (explicitContentLength != null && explicitContentLength !== "") { + return Number(explicitContentLength); + } + const buffer = await input.arrayBuffer(); + return buffer.byteLength; +} + +// src/interceptors/XMLHttpRequest/XMLHttpRequestController.ts +var kIsRequestHandled = Symbol("kIsRequestHandled"); +var IS_NODE = isNodeProcess(); +var kFetchRequest = Symbol("kFetchRequest"); +var XMLHttpRequestController = class { + constructor(initialRequest, logger) { + this.initialRequest = initialRequest; + this.logger = logger; + this.method = "GET"; + this.url = null; + this[kIsRequestHandled] = false; + this.events = /* @__PURE__ */ new Map(); + this.uploadEvents = /* @__PURE__ */ new Map(); + this.requestId = createRequestId(); + this.requestHeaders = new Headers(); + this.responseBuffer = new Uint8Array(); + this.request = createProxy(initialRequest, { + setProperty: ([propertyName, nextValue], invoke) => { + switch (propertyName) { + case "ontimeout": { + const eventName = propertyName.slice( + 2 + ); + this.request.addEventListener(eventName, nextValue); + return invoke(); + } + default: { + return invoke(); + } + } + }, + methodCall: ([methodName, args], invoke) => { + var _a; + switch (methodName) { + case "open": { + const [method, url] = args; + if (typeof url === "undefined") { + this.method = "GET"; + this.url = toAbsoluteUrl(method); + } else { + this.method = method; + this.url = toAbsoluteUrl(url); + } + this.logger = this.logger.extend(`${this.method} ${this.url.href}`); + this.logger.info("open", this.method, this.url.href); + return invoke(); + } + case "addEventListener": { + const [eventName, listener] = args; + this.registerEvent(eventName, listener); + this.logger.info("addEventListener", eventName, listener); + return invoke(); + } + case "setRequestHeader": { + const [name, value] = args; + this.requestHeaders.set(name, value); + this.logger.info("setRequestHeader", name, value); + return invoke(); + } + case "send": { + const [body] = args; + this.request.addEventListener("load", () => { + if (typeof this.onResponse !== "undefined") { + const fetchResponse = createResponse( + this.request, + /** + * The `response` property is the right way to read + * the ambiguous response body, as the request's "responseType" may differ. + * @see https://xhr.spec.whatwg.org/#the-response-attribute + */ + this.request.response + ); + this.onResponse.call(this, { + response: fetchResponse, + isMockedResponse: this[kIsRequestHandled], + request: fetchRequest, + requestId: this.requestId + }); + } + }); + const requestBody = typeof body === "string" ? encodeBuffer(body) : body; + const fetchRequest = this.toFetchApiRequest(requestBody); + this[kFetchRequest] = fetchRequest.clone(); + const onceRequestSettled = ((_a = this.onRequest) == null ? void 0 : _a.call(this, { + request: fetchRequest, + requestId: this.requestId + })) || Promise.resolve(); + onceRequestSettled.finally(() => { + if (!this[kIsRequestHandled]) { + this.logger.info( + "request callback settled but request has not been handled (readystate %d), performing as-is...", + this.request.readyState + ); + if (IS_NODE) { + this.request.setRequestHeader( + INTERNAL_REQUEST_ID_HEADER_NAME, + this.requestId + ); + } + return invoke(); + } + }); + break; + } + default: { + return invoke(); + } + } + } + }); + define( + this.request, + "upload", + createProxy(this.request.upload, { + setProperty: ([propertyName, nextValue], invoke) => { + switch (propertyName) { + case "onloadstart": + case "onprogress": + case "onaboart": + case "onerror": + case "onload": + case "ontimeout": + case "onloadend": { + const eventName = propertyName.slice( + 2 + ); + this.registerUploadEvent(eventName, nextValue); + } + } + return invoke(); + }, + methodCall: ([methodName, args], invoke) => { + switch (methodName) { + case "addEventListener": { + const [eventName, listener] = args; + this.registerUploadEvent(eventName, listener); + this.logger.info("upload.addEventListener", eventName, listener); + return invoke(); + } + } + } + }) + ); + } + registerEvent(eventName, listener) { + const prevEvents = this.events.get(eventName) || []; + const nextEvents = prevEvents.concat(listener); + this.events.set(eventName, nextEvents); + this.logger.info('registered event "%s"', eventName, listener); + } + registerUploadEvent(eventName, listener) { + const prevEvents = this.uploadEvents.get(eventName) || []; + const nextEvents = prevEvents.concat(listener); + this.uploadEvents.set(eventName, nextEvents); + this.logger.info('registered upload event "%s"', eventName, listener); + } + /** + * Responds to the current request with the given + * Fetch API `Response` instance. + */ + async respondWith(response) { + this[kIsRequestHandled] = true; + if (this[kFetchRequest]) { + const totalRequestBodyLength = await getBodyByteLength( + this[kFetchRequest] + ); + this.trigger("loadstart", this.request.upload, { + loaded: 0, + total: totalRequestBodyLength + }); + this.trigger("progress", this.request.upload, { + loaded: totalRequestBodyLength, + total: totalRequestBodyLength + }); + this.trigger("load", this.request.upload, { + loaded: totalRequestBodyLength, + total: totalRequestBodyLength + }); + this.trigger("loadend", this.request.upload, { + loaded: totalRequestBodyLength, + total: totalRequestBodyLength + }); + } + this.logger.info( + "responding with a mocked response: %d %s", + response.status, + response.statusText + ); + define(this.request, "status", response.status); + define(this.request, "statusText", response.statusText); + define(this.request, "responseURL", this.url.href); + this.request.getResponseHeader = new Proxy(this.request.getResponseHeader, { + apply: (_, __, args) => { + this.logger.info("getResponseHeader", args[0]); + if (this.request.readyState < this.request.HEADERS_RECEIVED) { + this.logger.info("headers not received yet, returning null"); + return null; + } + const headerValue = response.headers.get(args[0]); + this.logger.info( + 'resolved response header "%s" to', + args[0], + headerValue + ); + return headerValue; + } + }); + this.request.getAllResponseHeaders = new Proxy( + this.request.getAllResponseHeaders, + { + apply: () => { + this.logger.info("getAllResponseHeaders"); + if (this.request.readyState < this.request.HEADERS_RECEIVED) { + this.logger.info("headers not received yet, returning empty string"); + return ""; + } + const headersList = Array.from(response.headers.entries()); + const allHeaders = headersList.map(([headerName, headerValue]) => { + return `${headerName}: ${headerValue}`; + }).join("\r\n"); + this.logger.info("resolved all response headers to", allHeaders); + return allHeaders; + } + } + ); + Object.defineProperties(this.request, { + response: { + enumerable: true, + configurable: false, + get: () => this.response + }, + responseText: { + enumerable: true, + configurable: false, + get: () => this.responseText + }, + responseXML: { + enumerable: true, + configurable: false, + get: () => this.responseXML + } + }); + const totalResponseBodyLength = await getBodyByteLength(response.clone()); + this.logger.info("calculated response body length", totalResponseBodyLength); + this.trigger("loadstart", this.request, { + loaded: 0, + total: totalResponseBodyLength + }); + this.setReadyState(this.request.HEADERS_RECEIVED); + this.setReadyState(this.request.LOADING); + const finalizeResponse = () => { + this.logger.info("finalizing the mocked response..."); + this.setReadyState(this.request.DONE); + this.trigger("load", this.request, { + loaded: this.responseBuffer.byteLength, + total: totalResponseBodyLength + }); + this.trigger("loadend", this.request, { + loaded: this.responseBuffer.byteLength, + total: totalResponseBodyLength + }); + }; + if (response.body) { + this.logger.info("mocked response has body, streaming..."); + const reader = response.body.getReader(); + const readNextResponseBodyChunk = async () => { + const { value, done } = await reader.read(); + if (done) { + this.logger.info("response body stream done!"); + finalizeResponse(); + return; + } + if (value) { + this.logger.info("read response body chunk:", value); + this.responseBuffer = concatArrayBuffer(this.responseBuffer, value); + this.trigger("progress", this.request, { + loaded: this.responseBuffer.byteLength, + total: totalResponseBodyLength + }); + } + readNextResponseBodyChunk(); + }; + readNextResponseBodyChunk(); + } else { + finalizeResponse(); + } + } + responseBufferToText() { + return decodeBuffer(this.responseBuffer); + } + get response() { + this.logger.info( + "getResponse (responseType: %s)", + this.request.responseType + ); + if (this.request.readyState !== this.request.DONE) { + return null; + } + switch (this.request.responseType) { + case "json": { + const responseJson = parseJson(this.responseBufferToText()); + this.logger.info("resolved response JSON", responseJson); + return responseJson; + } + case "arraybuffer": { + const arrayBuffer = toArrayBuffer(this.responseBuffer); + this.logger.info("resolved response ArrayBuffer", arrayBuffer); + return arrayBuffer; + } + case "blob": { + const mimeType = this.request.getResponseHeader("Content-Type") || "text/plain"; + const responseBlob = new Blob([this.responseBufferToText()], { + type: mimeType + }); + this.logger.info( + "resolved response Blob (mime type: %s)", + responseBlob, + mimeType + ); + return responseBlob; + } + default: { + const responseText = this.responseBufferToText(); + this.logger.info( + 'resolving "%s" response type as text', + this.request.responseType, + responseText + ); + return responseText; + } + } + } + get responseText() { + invariant( + this.request.responseType === "" || this.request.responseType === "text", + "InvalidStateError: The object is in invalid state." + ); + if (this.request.readyState !== this.request.LOADING && this.request.readyState !== this.request.DONE) { + return ""; + } + const responseText = this.responseBufferToText(); + this.logger.info('getResponseText: "%s"', responseText); + return responseText; + } + get responseXML() { + invariant( + this.request.responseType === "" || this.request.responseType === "document", + "InvalidStateError: The object is in invalid state." + ); + if (this.request.readyState !== this.request.DONE) { + return null; + } + const contentType = this.request.getResponseHeader("Content-Type") || ""; + if (typeof DOMParser === "undefined") { + console.warn( + "Cannot retrieve XMLHttpRequest response body as XML: DOMParser is not defined. You are likely using an environment that is not browser or does not polyfill browser globals correctly." + ); + return null; + } + if (isDomParserSupportedType(contentType)) { + return new DOMParser().parseFromString( + this.responseBufferToText(), + contentType + ); + } + return null; + } + errorWith(error) { + this[kIsRequestHandled] = true; + this.logger.info("responding with an error"); + this.setReadyState(this.request.DONE); + this.trigger("error", this.request); + this.trigger("loadend", this.request); + } + /** + * Transitions this request's `readyState` to the given one. + */ + setReadyState(nextReadyState) { + this.logger.info( + "setReadyState: %d -> %d", + this.request.readyState, + nextReadyState + ); + if (this.request.readyState === nextReadyState) { + this.logger.info("ready state identical, skipping transition..."); + return; + } + define(this.request, "readyState", nextReadyState); + this.logger.info("set readyState to: %d", nextReadyState); + if (nextReadyState !== this.request.UNSENT) { + this.logger.info('triggerring "readystatechange" event...'); + this.trigger("readystatechange", this.request); + } + } + /** + * Triggers given event on the `XMLHttpRequest` instance. + */ + trigger(eventName, target, options) { + const callback = target[`on${eventName}`]; + const event = createEvent(target, eventName, options); + this.logger.info('trigger "%s"', eventName, options || ""); + if (typeof callback === "function") { + this.logger.info('found a direct "%s" callback, calling...', eventName); + callback.call(target, event); + } + const events = target instanceof XMLHttpRequestUpload ? this.uploadEvents : this.events; + for (const [registeredEventName, listeners] of events) { + if (registeredEventName === eventName) { + this.logger.info( + 'found %d listener(s) for "%s" event, calling...', + listeners.length, + eventName + ); + listeners.forEach((listener) => listener.call(target, event)); + } + } + } + /** + * Converts this `XMLHttpRequest` instance into a Fetch API `Request` instance. + */ + toFetchApiRequest(body) { + this.logger.info("converting request to a Fetch API Request..."); + const resolvedBody = body instanceof Document ? body.documentElement.innerText : body; + const fetchRequest = new Request(this.url.href, { + method: this.method, + headers: this.requestHeaders, + /** + * @see https://xhr.spec.whatwg.org/#cross-origin-credentials + */ + credentials: this.request.withCredentials ? "include" : "same-origin", + body: ["GET", "HEAD"].includes(this.method.toUpperCase()) ? null : resolvedBody + }); + const proxyHeaders = createProxy(fetchRequest.headers, { + methodCall: ([methodName, args], invoke) => { + switch (methodName) { + case "append": + case "set": { + const [headerName, headerValue] = args; + this.request.setRequestHeader(headerName, headerValue); + break; + } + case "delete": { + const [headerName] = args; + console.warn( + `XMLHttpRequest: Cannot remove a "${headerName}" header from the Fetch API representation of the "${fetchRequest.method} ${fetchRequest.url}" request. XMLHttpRequest headers cannot be removed.` + ); + break; + } + } + return invoke(); + } + }); + define(fetchRequest, "headers", proxyHeaders); + this.logger.info("converted request to a Fetch API Request!", fetchRequest); + return fetchRequest; + } +}; +kIsRequestHandled, kFetchRequest; +function toAbsoluteUrl(url) { + if (typeof location === "undefined") { + return new URL(url); + } + return new URL(url.toString(), location.href); +} +function define(target, property, value) { + Reflect.defineProperty(target, property, { + // Ensure writable properties to allow redefining readonly properties. + writable: true, + enumerable: true, + value + }); +} + +// src/interceptors/XMLHttpRequest/XMLHttpRequestProxy.ts +function createXMLHttpRequestProxy({ + emitter, + logger +}) { + const XMLHttpRequestProxy = new Proxy(globalThis.XMLHttpRequest, { + construct(target, args, newTarget) { + logger.info("constructed new XMLHttpRequest"); + const originalRequest = Reflect.construct( + target, + args, + newTarget + ); + const prototypeDescriptors = Object.getOwnPropertyDescriptors( + target.prototype + ); + for (const propertyName in prototypeDescriptors) { + Reflect.defineProperty( + originalRequest, + propertyName, + prototypeDescriptors[propertyName] + ); + } + const xhrRequestController = new XMLHttpRequestController( + originalRequest, + logger + ); + xhrRequestController.onRequest = async function({ request, requestId }) { + const controller = new RequestController(request); + this.logger.info("awaiting mocked response..."); + this.logger.info( + 'emitting the "request" event for %s listener(s)...', + emitter.listenerCount("request") + ); + const isRequestHandled = await handleRequest({ + request, + requestId, + controller, + emitter, + onResponse: async (response) => { + await this.respondWith(response); + }, + onRequestError: () => { + this.errorWith(new TypeError("Network error")); + }, + onError: (error) => { + this.logger.info("request errored!", { error }); + if (error instanceof Error) { + this.errorWith(error); + } + } + }); + if (!isRequestHandled) { + this.logger.info( + "no mocked response received, performing request as-is..." + ); + } + }; + xhrRequestController.onResponse = async function({ + response, + isMockedResponse, + request, + requestId + }) { + this.logger.info( + 'emitting the "response" event for %s listener(s)...', + emitter.listenerCount("response") + ); + emitter.emit("response", { + response, + isMockedResponse, + request, + requestId + }); + }; + return xhrRequestController.request; + } + }); + return XMLHttpRequestProxy; +} + +// src/interceptors/XMLHttpRequest/index.ts +var _XMLHttpRequestInterceptor = class extends Interceptor { + constructor() { + super(_XMLHttpRequestInterceptor.interceptorSymbol); + } + checkEnvironment() { + return hasConfigurableGlobal("XMLHttpRequest"); + } + setup() { + const logger = this.logger.extend("setup"); + logger.info('patching "XMLHttpRequest" module...'); + const PureXMLHttpRequest = globalThis.XMLHttpRequest; + invariant2( + !PureXMLHttpRequest[IS_PATCHED_MODULE], + 'Failed to patch the "XMLHttpRequest" module: already patched.' + ); + globalThis.XMLHttpRequest = createXMLHttpRequestProxy({ + emitter: this.emitter, + logger: this.logger + }); + logger.info( + 'native "XMLHttpRequest" module patched!', + globalThis.XMLHttpRequest.name + ); + Object.defineProperty(globalThis.XMLHttpRequest, IS_PATCHED_MODULE, { + enumerable: true, + configurable: true, + value: true + }); + this.subscriptions.push(() => { + Object.defineProperty(globalThis.XMLHttpRequest, IS_PATCHED_MODULE, { + value: void 0 + }); + globalThis.XMLHttpRequest = PureXMLHttpRequest; + logger.info( + 'native "XMLHttpRequest" module restored!', + globalThis.XMLHttpRequest.name + ); + }); + } +}; +var XMLHttpRequestInterceptor = _XMLHttpRequestInterceptor; +XMLHttpRequestInterceptor.interceptorSymbol = Symbol("xhr"); + +export { + XMLHttpRequestInterceptor +}; +//# sourceMappingURL=chunk-DODHRDV6.mjs.map \ No newline at end of file diff --git a/node_modules/@mswjs/interceptors/lib/browser/chunk-DODHRDV6.mjs.map b/node_modules/@mswjs/interceptors/lib/browser/chunk-DODHRDV6.mjs.map new file mode 100644 index 0000000000000000000000000000000000000000..085f069c1950839b00d35ae30608fbf1f37086ae --- /dev/null +++ b/node_modules/@mswjs/interceptors/lib/browser/chunk-DODHRDV6.mjs.map @@ -0,0 +1 @@ +{"version":3,"sources":["../../src/interceptors/XMLHttpRequest/index.ts","../../src/interceptors/XMLHttpRequest/XMLHttpRequestController.ts","../../src/interceptors/XMLHttpRequest/utils/concatArrayBuffer.ts","../../src/interceptors/XMLHttpRequest/polyfills/EventPolyfill.ts","../../src/interceptors/XMLHttpRequest/polyfills/ProgressEventPolyfill.ts","../../src/interceptors/XMLHttpRequest/utils/createEvent.ts","../../src/utils/findPropertySource.ts","../../src/utils/createProxy.ts","../../src/interceptors/XMLHttpRequest/utils/isDomParserSupportedType.ts","../../src/utils/parseJson.ts","../../src/interceptors/XMLHttpRequest/utils/createResponse.ts","../../src/interceptors/XMLHttpRequest/utils/getBodyByteLength.ts","../../src/interceptors/XMLHttpRequest/XMLHttpRequestProxy.ts"],"sourcesContent":["import { invariant } from 'outvariant'\nimport { Emitter } from 'strict-event-emitter'\nimport { HttpRequestEventMap, IS_PATCHED_MODULE } from '../../glossary'\nimport { Interceptor } from '../../Interceptor'\nimport { createXMLHttpRequestProxy } from './XMLHttpRequestProxy'\nimport { hasConfigurableGlobal } from '../../utils/hasConfigurableGlobal'\n\nexport type XMLHttpRequestEmitter = Emitter\n\nexport class XMLHttpRequestInterceptor extends Interceptor {\n static interceptorSymbol = Symbol('xhr')\n\n constructor() {\n super(XMLHttpRequestInterceptor.interceptorSymbol)\n }\n\n protected checkEnvironment() {\n return hasConfigurableGlobal('XMLHttpRequest')\n }\n\n protected setup() {\n const logger = this.logger.extend('setup')\n\n logger.info('patching \"XMLHttpRequest\" module...')\n\n const PureXMLHttpRequest = globalThis.XMLHttpRequest\n\n invariant(\n !(PureXMLHttpRequest as any)[IS_PATCHED_MODULE],\n 'Failed to patch the \"XMLHttpRequest\" module: already patched.'\n )\n\n globalThis.XMLHttpRequest = createXMLHttpRequestProxy({\n emitter: this.emitter,\n logger: this.logger,\n })\n\n logger.info(\n 'native \"XMLHttpRequest\" module patched!',\n globalThis.XMLHttpRequest.name\n )\n\n Object.defineProperty(globalThis.XMLHttpRequest, IS_PATCHED_MODULE, {\n enumerable: true,\n configurable: true,\n value: true,\n })\n\n this.subscriptions.push(() => {\n Object.defineProperty(globalThis.XMLHttpRequest, IS_PATCHED_MODULE, {\n value: undefined,\n })\n\n globalThis.XMLHttpRequest = PureXMLHttpRequest\n logger.info(\n 'native \"XMLHttpRequest\" module restored!',\n globalThis.XMLHttpRequest.name\n )\n })\n }\n}\n","import { invariant } from 'outvariant'\nimport { isNodeProcess } from 'is-node-process'\nimport type { Logger } from '@open-draft/logger'\nimport { concatArrayBuffer } from './utils/concatArrayBuffer'\nimport { createEvent } from './utils/createEvent'\nimport {\n decodeBuffer,\n encodeBuffer,\n toArrayBuffer,\n} from '../../utils/bufferUtils'\nimport { createProxy } from '../../utils/createProxy'\nimport { isDomParserSupportedType } from './utils/isDomParserSupportedType'\nimport { parseJson } from '../../utils/parseJson'\nimport { createResponse } from './utils/createResponse'\nimport { INTERNAL_REQUEST_ID_HEADER_NAME } from '../../Interceptor'\nimport { createRequestId } from '../../createRequestId'\nimport { getBodyByteLength } from './utils/getBodyByteLength'\n\nconst kIsRequestHandled = Symbol('kIsRequestHandled')\nconst IS_NODE = isNodeProcess()\nconst kFetchRequest = Symbol('kFetchRequest')\n\n/**\n * An `XMLHttpRequest` instance controller that allows us\n * to handle any given request instance (e.g. responding to it).\n */\nexport class XMLHttpRequestController {\n public request: XMLHttpRequest\n public requestId: string\n public onRequest?: (\n this: XMLHttpRequestController,\n args: {\n request: Request\n requestId: string\n }\n ) => Promise\n public onResponse?: (\n this: XMLHttpRequestController,\n args: {\n response: Response\n isMockedResponse: boolean\n request: Request\n requestId: string\n }\n ) => void;\n\n [kIsRequestHandled]: boolean;\n [kFetchRequest]?: Request\n private method: string = 'GET'\n private url: URL = null as any\n private requestHeaders: Headers\n private responseBuffer: Uint8Array\n private events: Map>\n private uploadEvents: Map<\n keyof XMLHttpRequestEventTargetEventMap,\n Array\n >\n\n constructor(readonly initialRequest: XMLHttpRequest, public logger: Logger) {\n this[kIsRequestHandled] = false\n\n this.events = new Map()\n this.uploadEvents = new Map()\n this.requestId = createRequestId()\n this.requestHeaders = new Headers()\n this.responseBuffer = new Uint8Array()\n\n this.request = createProxy(initialRequest, {\n setProperty: ([propertyName, nextValue], invoke) => {\n switch (propertyName) {\n case 'ontimeout': {\n const eventName = propertyName.slice(\n 2\n ) as keyof XMLHttpRequestEventTargetEventMap\n\n /**\n * @note Proxy callbacks to event listeners because JSDOM has trouble\n * translating these properties to callbacks. It seemed to be operating\n * on events exclusively.\n */\n this.request.addEventListener(eventName, nextValue as any)\n\n return invoke()\n }\n\n default: {\n return invoke()\n }\n }\n },\n methodCall: ([methodName, args], invoke) => {\n switch (methodName) {\n case 'open': {\n const [method, url] = args as [string, string | undefined]\n\n if (typeof url === 'undefined') {\n this.method = 'GET'\n this.url = toAbsoluteUrl(method)\n } else {\n this.method = method\n this.url = toAbsoluteUrl(url)\n }\n\n this.logger = this.logger.extend(`${this.method} ${this.url.href}`)\n this.logger.info('open', this.method, this.url.href)\n\n return invoke()\n }\n\n case 'addEventListener': {\n const [eventName, listener] = args as [\n keyof XMLHttpRequestEventTargetEventMap,\n Function\n ]\n\n this.registerEvent(eventName, listener)\n this.logger.info('addEventListener', eventName, listener)\n\n return invoke()\n }\n\n case 'setRequestHeader': {\n const [name, value] = args as [string, string]\n this.requestHeaders.set(name, value)\n\n this.logger.info('setRequestHeader', name, value)\n\n return invoke()\n }\n\n case 'send': {\n const [body] = args as [\n body?: XMLHttpRequestBodyInit | Document | null\n ]\n\n this.request.addEventListener('load', () => {\n if (typeof this.onResponse !== 'undefined') {\n // Create a Fetch API Response representation of whichever\n // response this XMLHttpRequest received. Note those may\n // be either a mocked and the original response.\n const fetchResponse = createResponse(\n this.request,\n /**\n * The `response` property is the right way to read\n * the ambiguous response body, as the request's \"responseType\" may differ.\n * @see https://xhr.spec.whatwg.org/#the-response-attribute\n */\n this.request.response\n )\n\n // Notify the consumer about the response.\n this.onResponse.call(this, {\n response: fetchResponse,\n isMockedResponse: this[kIsRequestHandled],\n request: fetchRequest,\n requestId: this.requestId!,\n })\n }\n })\n\n const requestBody =\n typeof body === 'string' ? encodeBuffer(body) : body\n\n // Delegate request handling to the consumer.\n const fetchRequest = this.toFetchApiRequest(requestBody)\n this[kFetchRequest] = fetchRequest.clone()\n\n const onceRequestSettled =\n this.onRequest?.call(this, {\n request: fetchRequest,\n requestId: this.requestId!,\n }) || Promise.resolve()\n\n onceRequestSettled.finally(() => {\n // If the consumer didn't handle the request (called `.respondWith()`) perform it as-is.\n if (!this[kIsRequestHandled]) {\n this.logger.info(\n 'request callback settled but request has not been handled (readystate %d), performing as-is...',\n this.request.readyState\n )\n\n /**\n * @note Set the intercepted request ID on the original request in Node.js\n * so that if it triggers any other interceptors, they don't attempt\n * to process it once again.\n *\n * For instance, XMLHttpRequest is often implemented via \"http.ClientRequest\"\n * and we don't want for both XHR and ClientRequest interceptors to\n * handle the same request at the same time (e.g. emit the \"response\" event twice).\n */\n if (IS_NODE) {\n this.request.setRequestHeader(\n INTERNAL_REQUEST_ID_HEADER_NAME,\n this.requestId!\n )\n }\n\n return invoke()\n }\n })\n\n break\n }\n\n default: {\n return invoke()\n }\n }\n },\n })\n\n /**\n * Proxy the `.upload` property to gather the event listeners/callbacks.\n */\n define(\n this.request,\n 'upload',\n createProxy(this.request.upload, {\n setProperty: ([propertyName, nextValue], invoke) => {\n switch (propertyName) {\n case 'onloadstart':\n case 'onprogress':\n case 'onaboart':\n case 'onerror':\n case 'onload':\n case 'ontimeout':\n case 'onloadend': {\n const eventName = propertyName.slice(\n 2\n ) as keyof XMLHttpRequestEventTargetEventMap\n\n this.registerUploadEvent(eventName, nextValue as Function)\n }\n }\n\n return invoke()\n },\n methodCall: ([methodName, args], invoke) => {\n switch (methodName) {\n case 'addEventListener': {\n const [eventName, listener] = args as [\n keyof XMLHttpRequestEventTargetEventMap,\n Function\n ]\n this.registerUploadEvent(eventName, listener)\n this.logger.info('upload.addEventListener', eventName, listener)\n\n return invoke()\n }\n }\n },\n })\n )\n }\n\n private registerEvent(\n eventName: keyof XMLHttpRequestEventTargetEventMap,\n listener: Function\n ): void {\n const prevEvents = this.events.get(eventName) || []\n const nextEvents = prevEvents.concat(listener)\n this.events.set(eventName, nextEvents)\n\n this.logger.info('registered event \"%s\"', eventName, listener)\n }\n\n private registerUploadEvent(\n eventName: keyof XMLHttpRequestEventTargetEventMap,\n listener: Function\n ): void {\n const prevEvents = this.uploadEvents.get(eventName) || []\n const nextEvents = prevEvents.concat(listener)\n this.uploadEvents.set(eventName, nextEvents)\n\n this.logger.info('registered upload event \"%s\"', eventName, listener)\n }\n\n /**\n * Responds to the current request with the given\n * Fetch API `Response` instance.\n */\n public async respondWith(response: Response): Promise {\n /**\n * @note Since `XMLHttpRequestController` delegates the handling of the responses\n * to the \"load\" event listener that doesn't distinguish between the mocked and original\n * responses, mark the request that had a mocked response with a corresponding symbol.\n *\n * Mark this request as having a mocked response immediately since\n * calculating request/response total body length is asynchronous.\n */\n this[kIsRequestHandled] = true\n\n /**\n * Dispatch request upload events for requests with a body.\n * @see https://github.com/mswjs/interceptors/issues/573\n */\n if (this[kFetchRequest]) {\n const totalRequestBodyLength = await getBodyByteLength(\n this[kFetchRequest]\n )\n\n this.trigger('loadstart', this.request.upload, {\n loaded: 0,\n total: totalRequestBodyLength,\n })\n this.trigger('progress', this.request.upload, {\n loaded: totalRequestBodyLength,\n total: totalRequestBodyLength,\n })\n this.trigger('load', this.request.upload, {\n loaded: totalRequestBodyLength,\n total: totalRequestBodyLength,\n })\n this.trigger('loadend', this.request.upload, {\n loaded: totalRequestBodyLength,\n total: totalRequestBodyLength,\n })\n }\n\n this.logger.info(\n 'responding with a mocked response: %d %s',\n response.status,\n response.statusText\n )\n\n define(this.request, 'status', response.status)\n define(this.request, 'statusText', response.statusText)\n define(this.request, 'responseURL', this.url.href)\n\n this.request.getResponseHeader = new Proxy(this.request.getResponseHeader, {\n apply: (_, __, args: [name: string]) => {\n this.logger.info('getResponseHeader', args[0])\n\n if (this.request.readyState < this.request.HEADERS_RECEIVED) {\n this.logger.info('headers not received yet, returning null')\n\n // Headers not received yet, nothing to return.\n return null\n }\n\n const headerValue = response.headers.get(args[0])\n this.logger.info(\n 'resolved response header \"%s\" to',\n args[0],\n headerValue\n )\n\n return headerValue\n },\n })\n\n this.request.getAllResponseHeaders = new Proxy(\n this.request.getAllResponseHeaders,\n {\n apply: () => {\n this.logger.info('getAllResponseHeaders')\n\n if (this.request.readyState < this.request.HEADERS_RECEIVED) {\n this.logger.info('headers not received yet, returning empty string')\n\n // Headers not received yet, nothing to return.\n return ''\n }\n\n const headersList = Array.from(response.headers.entries())\n const allHeaders = headersList\n .map(([headerName, headerValue]) => {\n return `${headerName}: ${headerValue}`\n })\n .join('\\r\\n')\n\n this.logger.info('resolved all response headers to', allHeaders)\n\n return allHeaders\n },\n }\n )\n\n // Update the response getters to resolve against the mocked response.\n Object.defineProperties(this.request, {\n response: {\n enumerable: true,\n configurable: false,\n get: () => this.response,\n },\n responseText: {\n enumerable: true,\n configurable: false,\n get: () => this.responseText,\n },\n responseXML: {\n enumerable: true,\n configurable: false,\n get: () => this.responseXML,\n },\n })\n\n const totalResponseBodyLength = await getBodyByteLength(response.clone())\n\n this.logger.info('calculated response body length', totalResponseBodyLength)\n\n this.trigger('loadstart', this.request, {\n loaded: 0,\n total: totalResponseBodyLength,\n })\n\n this.setReadyState(this.request.HEADERS_RECEIVED)\n this.setReadyState(this.request.LOADING)\n\n const finalizeResponse = () => {\n this.logger.info('finalizing the mocked response...')\n\n this.setReadyState(this.request.DONE)\n\n this.trigger('load', this.request, {\n loaded: this.responseBuffer.byteLength,\n total: totalResponseBodyLength,\n })\n\n this.trigger('loadend', this.request, {\n loaded: this.responseBuffer.byteLength,\n total: totalResponseBodyLength,\n })\n }\n\n if (response.body) {\n this.logger.info('mocked response has body, streaming...')\n\n const reader = response.body.getReader()\n\n const readNextResponseBodyChunk = async () => {\n const { value, done } = await reader.read()\n\n if (done) {\n this.logger.info('response body stream done!')\n finalizeResponse()\n return\n }\n\n if (value) {\n this.logger.info('read response body chunk:', value)\n this.responseBuffer = concatArrayBuffer(this.responseBuffer, value)\n\n this.trigger('progress', this.request, {\n loaded: this.responseBuffer.byteLength,\n total: totalResponseBodyLength,\n })\n }\n\n readNextResponseBodyChunk()\n }\n\n readNextResponseBodyChunk()\n } else {\n finalizeResponse()\n }\n }\n\n private responseBufferToText(): string {\n return decodeBuffer(this.responseBuffer)\n }\n\n get response(): unknown {\n this.logger.info(\n 'getResponse (responseType: %s)',\n this.request.responseType\n )\n\n if (this.request.readyState !== this.request.DONE) {\n return null\n }\n\n switch (this.request.responseType) {\n case 'json': {\n const responseJson = parseJson(this.responseBufferToText())\n this.logger.info('resolved response JSON', responseJson)\n\n return responseJson\n }\n\n case 'arraybuffer': {\n const arrayBuffer = toArrayBuffer(this.responseBuffer)\n this.logger.info('resolved response ArrayBuffer', arrayBuffer)\n\n return arrayBuffer\n }\n\n case 'blob': {\n const mimeType =\n this.request.getResponseHeader('Content-Type') || 'text/plain'\n const responseBlob = new Blob([this.responseBufferToText()], {\n type: mimeType,\n })\n\n this.logger.info(\n 'resolved response Blob (mime type: %s)',\n responseBlob,\n mimeType\n )\n\n return responseBlob\n }\n\n default: {\n const responseText = this.responseBufferToText()\n this.logger.info(\n 'resolving \"%s\" response type as text',\n this.request.responseType,\n responseText\n )\n\n return responseText\n }\n }\n }\n\n get responseText(): string {\n /**\n * Throw when trying to read the response body as text when the\n * \"responseType\" doesn't expect text. This just respects the spec better.\n * @see https://xhr.spec.whatwg.org/#the-responsetext-attribute\n */\n invariant(\n this.request.responseType === '' || this.request.responseType === 'text',\n 'InvalidStateError: The object is in invalid state.'\n )\n\n if (\n this.request.readyState !== this.request.LOADING &&\n this.request.readyState !== this.request.DONE\n ) {\n return ''\n }\n\n const responseText = this.responseBufferToText()\n this.logger.info('getResponseText: \"%s\"', responseText)\n\n return responseText\n }\n\n get responseXML(): Document | null {\n invariant(\n this.request.responseType === '' ||\n this.request.responseType === 'document',\n 'InvalidStateError: The object is in invalid state.'\n )\n\n if (this.request.readyState !== this.request.DONE) {\n return null\n }\n\n const contentType = this.request.getResponseHeader('Content-Type') || ''\n\n if (typeof DOMParser === 'undefined') {\n console.warn(\n 'Cannot retrieve XMLHttpRequest response body as XML: DOMParser is not defined. You are likely using an environment that is not browser or does not polyfill browser globals correctly.'\n )\n return null\n }\n\n if (isDomParserSupportedType(contentType)) {\n return new DOMParser().parseFromString(\n this.responseBufferToText(),\n contentType\n )\n }\n\n return null\n }\n\n public errorWith(error?: Error): void {\n /**\n * @note Mark this request as handled even if it received a mock error.\n * This prevents the controller from trying to perform this request as-is.\n */\n this[kIsRequestHandled] = true\n this.logger.info('responding with an error')\n\n this.setReadyState(this.request.DONE)\n this.trigger('error', this.request)\n this.trigger('loadend', this.request)\n }\n\n /**\n * Transitions this request's `readyState` to the given one.\n */\n private setReadyState(nextReadyState: number): void {\n this.logger.info(\n 'setReadyState: %d -> %d',\n this.request.readyState,\n nextReadyState\n )\n\n if (this.request.readyState === nextReadyState) {\n this.logger.info('ready state identical, skipping transition...')\n return\n }\n\n define(this.request, 'readyState', nextReadyState)\n\n this.logger.info('set readyState to: %d', nextReadyState)\n\n if (nextReadyState !== this.request.UNSENT) {\n this.logger.info('triggerring \"readystatechange\" event...')\n\n this.trigger('readystatechange', this.request)\n }\n }\n\n /**\n * Triggers given event on the `XMLHttpRequest` instance.\n */\n private trigger<\n EventName extends keyof (XMLHttpRequestEventTargetEventMap & {\n readystatechange: ProgressEvent\n })\n >(\n eventName: EventName,\n target: XMLHttpRequest | XMLHttpRequestUpload,\n options?: ProgressEventInit\n ): void {\n const callback = (target as XMLHttpRequest)[`on${eventName}`]\n const event = createEvent(target, eventName, options)\n\n this.logger.info('trigger \"%s\"', eventName, options || '')\n\n // Invoke direct callbacks.\n if (typeof callback === 'function') {\n this.logger.info('found a direct \"%s\" callback, calling...', eventName)\n callback.call(target as XMLHttpRequest, event)\n }\n\n // Invoke event listeners.\n const events =\n target instanceof XMLHttpRequestUpload ? this.uploadEvents : this.events\n\n for (const [registeredEventName, listeners] of events) {\n if (registeredEventName === eventName) {\n this.logger.info(\n 'found %d listener(s) for \"%s\" event, calling...',\n listeners.length,\n eventName\n )\n\n listeners.forEach((listener) => listener.call(target, event))\n }\n }\n }\n\n /**\n * Converts this `XMLHttpRequest` instance into a Fetch API `Request` instance.\n */\n private toFetchApiRequest(\n body: XMLHttpRequestBodyInit | Document | null | undefined\n ): Request {\n this.logger.info('converting request to a Fetch API Request...')\n\n // If the `Document` is used as the body of this XMLHttpRequest,\n // set its inner text as the Fetch API Request body.\n const resolvedBody =\n body instanceof Document ? body.documentElement.innerText : body\n\n const fetchRequest = new Request(this.url.href, {\n method: this.method,\n headers: this.requestHeaders,\n /**\n * @see https://xhr.spec.whatwg.org/#cross-origin-credentials\n */\n credentials: this.request.withCredentials ? 'include' : 'same-origin',\n body: ['GET', 'HEAD'].includes(this.method.toUpperCase())\n ? null\n : resolvedBody,\n })\n\n const proxyHeaders = createProxy(fetchRequest.headers, {\n methodCall: ([methodName, args], invoke) => {\n // Forward the latest state of the internal request headers\n // because the interceptor might have modified them\n // without responding to the request.\n switch (methodName) {\n case 'append':\n case 'set': {\n const [headerName, headerValue] = args as [string, string]\n this.request.setRequestHeader(headerName, headerValue)\n break\n }\n\n case 'delete': {\n const [headerName] = args as [string]\n console.warn(\n `XMLHttpRequest: Cannot remove a \"${headerName}\" header from the Fetch API representation of the \"${fetchRequest.method} ${fetchRequest.url}\" request. XMLHttpRequest headers cannot be removed.`\n )\n break\n }\n }\n\n return invoke()\n },\n })\n define(fetchRequest, 'headers', proxyHeaders)\n\n this.logger.info('converted request to a Fetch API Request!', fetchRequest)\n\n return fetchRequest\n }\n}\n\nfunction toAbsoluteUrl(url: string | URL): URL {\n /**\n * @note XMLHttpRequest interceptor may run in environments\n * that implement XMLHttpRequest but don't implement \"location\"\n * (for example, React Native). If that's the case, return the\n * input URL as-is (nothing to be relative to).\n * @see https://github.com/mswjs/msw/issues/1777\n */\n if (typeof location === 'undefined') {\n return new URL(url)\n }\n\n return new URL(url.toString(), location.href)\n}\n\nfunction define(\n target: object,\n property: string | symbol,\n value: unknown\n): void {\n Reflect.defineProperty(target, property, {\n // Ensure writable properties to allow redefining readonly properties.\n writable: true,\n enumerable: true,\n value,\n })\n}\n","/**\n * Concatenate two `Uint8Array` buffers.\n */\nexport function concatArrayBuffer(\n left: Uint8Array,\n right: Uint8Array\n): Uint8Array {\n const result = new Uint8Array(left.byteLength + right.byteLength)\n result.set(left, 0)\n result.set(right, left.byteLength)\n return result\n}\n","export class EventPolyfill implements Event {\n readonly NONE = 0\n readonly CAPTURING_PHASE = 1\n readonly AT_TARGET = 2\n readonly BUBBLING_PHASE = 3\n\n public type: string = ''\n public srcElement: EventTarget | null = null\n public target: EventTarget | null\n public currentTarget: EventTarget | null = null\n public eventPhase: number = 0\n public timeStamp: number\n public isTrusted: boolean = true\n public composed: boolean = false\n public cancelable: boolean = true\n public defaultPrevented: boolean = false\n public bubbles: boolean = true\n public lengthComputable: boolean = true\n public loaded: number = 0\n public total: number = 0\n\n cancelBubble: boolean = false\n returnValue: boolean = true\n\n constructor(\n type: string,\n options?: { target: EventTarget; currentTarget: EventTarget }\n ) {\n this.type = type\n this.target = options?.target || null\n this.currentTarget = options?.currentTarget || null\n this.timeStamp = Date.now()\n }\n\n public composedPath(): EventTarget[] {\n return []\n }\n\n public initEvent(type: string, bubbles?: boolean, cancelable?: boolean) {\n this.type = type\n this.bubbles = !!bubbles\n this.cancelable = !!cancelable\n }\n\n public preventDefault() {\n this.defaultPrevented = true\n }\n\n public stopPropagation() {}\n public stopImmediatePropagation() {}\n}\n","import { EventPolyfill } from './EventPolyfill'\n\nexport class ProgressEventPolyfill extends EventPolyfill {\n readonly lengthComputable: boolean\n readonly composed: boolean\n readonly loaded: number\n readonly total: number\n\n constructor(type: string, init?: ProgressEventInit) {\n super(type)\n\n this.lengthComputable = init?.lengthComputable || false\n this.composed = init?.composed || false\n this.loaded = init?.loaded || 0\n this.total = init?.total || 0\n }\n}\n","import { EventPolyfill } from '../polyfills/EventPolyfill'\nimport { ProgressEventPolyfill } from '../polyfills/ProgressEventPolyfill'\n\nconst SUPPORTS_PROGRESS_EVENT = typeof ProgressEvent !== 'undefined'\n\nexport function createEvent(\n target: XMLHttpRequest | XMLHttpRequestUpload,\n type: string,\n init?: ProgressEventInit\n): EventPolyfill | ProgressEvent {\n const progressEvents = [\n 'error',\n 'progress',\n 'loadstart',\n 'loadend',\n 'load',\n 'timeout',\n 'abort',\n ]\n\n /**\n * `ProgressEvent` is not supported in React Native.\n * @see https://github.com/mswjs/interceptors/issues/40\n */\n const ProgressEventClass = SUPPORTS_PROGRESS_EVENT\n ? ProgressEvent\n : ProgressEventPolyfill\n\n const event = progressEvents.includes(type)\n ? new ProgressEventClass(type, {\n lengthComputable: true,\n loaded: init?.loaded || 0,\n total: init?.total || 0,\n })\n : new EventPolyfill(type, {\n target,\n currentTarget: target,\n })\n\n return event\n}\n","/**\n * Returns the source object of the given property on the target object\n * (the target itself, any parent in its prototype, or null).\n */\nexport function findPropertySource(\n target: object,\n propertyName: string | symbol\n): object | null {\n if (!(propertyName in target)) {\n return null\n }\n\n const hasProperty = Object.prototype.hasOwnProperty.call(target, propertyName)\n if (hasProperty) {\n return target\n }\n\n const prototype = Reflect.getPrototypeOf(target)\n return prototype ? findPropertySource(prototype, propertyName) : null\n}\n","import { findPropertySource } from './findPropertySource'\n\nexport interface ProxyOptions> {\n constructorCall?(args: Array, next: NextFunction): Target\n\n methodCall?(\n this: Target,\n data: [methodName: F, args: Array],\n next: NextFunction\n ): void\n\n setProperty?(\n data: [propertyName: string | symbol, nextValue: unknown],\n next: NextFunction\n ): boolean\n\n getProperty?(\n data: [propertyName: string | symbol, receiver: Target],\n next: NextFunction\n ): void\n}\n\nexport type NextFunction = () => ReturnType\n\nexport function createProxy(\n target: Target,\n options: ProxyOptions\n): Target {\n const proxy = new Proxy(target, optionsToProxyHandler(options))\n\n return proxy\n}\n\nfunction optionsToProxyHandler>(\n options: ProxyOptions\n): ProxyHandler {\n const { constructorCall, methodCall, getProperty, setProperty } = options\n const handler: ProxyHandler = {}\n\n if (typeof constructorCall !== 'undefined') {\n handler.construct = function (target, args, newTarget) {\n const next = Reflect.construct.bind(null, target as any, args, newTarget)\n return constructorCall.call(newTarget, args, next)\n }\n }\n\n handler.set = function (target, propertyName, nextValue) {\n const next = () => {\n const propertySource = findPropertySource(target, propertyName) || target\n const ownDescriptors = Reflect.getOwnPropertyDescriptor(\n propertySource,\n propertyName\n )\n\n // Respect any custom setters present for this property.\n if (typeof ownDescriptors?.set !== 'undefined') {\n ownDescriptors.set.apply(target, [nextValue])\n return true\n }\n\n // Otherwise, set the property on the source.\n return Reflect.defineProperty(propertySource, propertyName, {\n writable: true,\n enumerable: true,\n configurable: true,\n value: nextValue,\n })\n }\n\n if (typeof setProperty !== 'undefined') {\n return setProperty.call(target, [propertyName, nextValue], next)\n }\n\n return next()\n }\n\n handler.get = function (target, propertyName, receiver) {\n /**\n * @note Using `Reflect.get()` here causes \"TypeError: Illegal invocation\".\n */\n const next = () => target[propertyName as any]\n\n const value =\n typeof getProperty !== 'undefined'\n ? getProperty.call(target, [propertyName, receiver], next)\n : next()\n\n if (typeof value === 'function') {\n return (...args: Array) => {\n const next = value.bind(target, ...args)\n\n if (typeof methodCall !== 'undefined') {\n return methodCall.call(target, [propertyName as any, args], next)\n }\n\n return next()\n }\n }\n\n return value\n }\n\n return handler\n}\n","export function isDomParserSupportedType(\n type: string\n): type is DOMParserSupportedType {\n const supportedTypes: Array = [\n 'application/xhtml+xml',\n 'application/xml',\n 'image/svg+xml',\n 'text/html',\n 'text/xml',\n ]\n return supportedTypes.some((supportedType) => {\n return type.startsWith(supportedType)\n })\n}\n","/**\n * Parses a given string into JSON.\n * Gracefully handles invalid JSON by returning `null`.\n */\nexport function parseJson(data: string): Record | null {\n try {\n const json = JSON.parse(data)\n return json\n } catch (_) {\n return null\n }\n}\n","import { FetchResponse } from '../../../utils/fetchUtils'\n\n/**\n * Creates a Fetch API `Response` instance from the given\n * `XMLHttpRequest` instance and a response body.\n */\nexport function createResponse(\n request: XMLHttpRequest,\n body: BodyInit | null\n): Response {\n /**\n * Handle XMLHttpRequest responses that must have null as the\n * response body when represented using Fetch API Response.\n * XMLHttpRequest response will always have an empty string\n * as the \"request.response\" in those cases, resulting in an error\n * when constructing a Response instance.\n * @see https://github.com/mswjs/interceptors/issues/379\n */\n const responseBodyOrNull = FetchResponse.isResponseWithBody(request.status)\n ? body\n : null\n\n return new FetchResponse(responseBodyOrNull, {\n url: request.responseURL,\n status: request.status,\n statusText: request.statusText,\n headers: createHeadersFromXMLHttpReqestHeaders(\n request.getAllResponseHeaders()\n ),\n })\n}\n\nfunction createHeadersFromXMLHttpReqestHeaders(headersString: string): Headers {\n const headers = new Headers()\n\n const lines = headersString.split(/[\\r\\n]+/)\n for (const line of lines) {\n if (line.trim() === '') {\n continue\n }\n\n const [name, ...parts] = line.split(': ')\n const value = parts.join(': ')\n\n headers.append(name, value)\n }\n\n return headers\n}\n","/**\n * Return a total byte length of the given request/response body.\n * If the `Content-Length` header is present, it will be used as the byte length.\n */\nexport async function getBodyByteLength(\n input: Request | Response\n): Promise {\n const explicitContentLength = input.headers.get('content-length')\n\n if (explicitContentLength != null && explicitContentLength !== '') {\n return Number(explicitContentLength)\n }\n\n const buffer = await input.arrayBuffer()\n return buffer.byteLength\n}\n","import type { Logger } from '@open-draft/logger'\nimport { XMLHttpRequestEmitter } from '.'\nimport { RequestController } from '../../RequestController'\nimport { XMLHttpRequestController } from './XMLHttpRequestController'\nimport { handleRequest } from '../../utils/handleRequest'\n\nexport interface XMLHttpRequestProxyOptions {\n emitter: XMLHttpRequestEmitter\n logger: Logger\n}\n\n/**\n * Create a proxied `XMLHttpRequest` class.\n * The proxied class establishes spies on certain methods,\n * allowing us to intercept requests and respond to them.\n */\nexport function createXMLHttpRequestProxy({\n emitter,\n logger,\n}: XMLHttpRequestProxyOptions) {\n const XMLHttpRequestProxy = new Proxy(globalThis.XMLHttpRequest, {\n construct(target, args, newTarget) {\n logger.info('constructed new XMLHttpRequest')\n\n const originalRequest = Reflect.construct(\n target,\n args,\n newTarget\n ) as XMLHttpRequest\n\n /**\n * @note Forward prototype descriptors onto the proxied object.\n * XMLHttpRequest is implemented in JSDOM in a way that assigns\n * a bunch of descriptors, like \"set responseType()\" on the prototype.\n * With this propagation, we make sure that those descriptors trigger\n * when the user operates with the proxied request instance.\n */\n const prototypeDescriptors = Object.getOwnPropertyDescriptors(\n target.prototype\n )\n for (const propertyName in prototypeDescriptors) {\n Reflect.defineProperty(\n originalRequest,\n propertyName,\n prototypeDescriptors[propertyName]\n )\n }\n\n const xhrRequestController = new XMLHttpRequestController(\n originalRequest,\n logger\n )\n\n xhrRequestController.onRequest = async function ({ request, requestId }) {\n const controller = new RequestController(request)\n\n this.logger.info('awaiting mocked response...')\n\n this.logger.info(\n 'emitting the \"request\" event for %s listener(s)...',\n emitter.listenerCount('request')\n )\n\n const isRequestHandled = await handleRequest({\n request,\n requestId,\n controller,\n emitter,\n onResponse: async (response) => {\n await this.respondWith(response)\n },\n onRequestError: () => {\n this.errorWith(new TypeError('Network error'))\n },\n onError: (error) => {\n this.logger.info('request errored!', { error })\n\n if (error instanceof Error) {\n this.errorWith(error)\n }\n },\n })\n\n if (!isRequestHandled) {\n this.logger.info(\n 'no mocked response received, performing request as-is...'\n )\n }\n }\n\n xhrRequestController.onResponse = async function ({\n response,\n isMockedResponse,\n request,\n requestId,\n }) {\n this.logger.info(\n 'emitting the \"response\" event for %s listener(s)...',\n emitter.listenerCount('response')\n )\n\n emitter.emit('response', {\n response,\n isMockedResponse,\n request,\n requestId,\n })\n }\n\n // Return the proxied request from the controller\n // so that the controller can react to the consumer's interactions\n // with this request (opening/sending/etc).\n return xhrRequestController.request\n },\n })\n\n return XMLHttpRequestProxy\n}\n"],"mappings":"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","names":["invariant","next","invariant"]} \ No newline at end of file diff --git a/node_modules/@mswjs/interceptors/lib/browser/chunk-FGSEOIC4.js b/node_modules/@mswjs/interceptors/lib/browser/chunk-FGSEOIC4.js new file mode 100644 index 0000000000000000000000000000000000000000..b95c747ba42036ed03f4260e6a695aac56b49bda --- /dev/null +++ b/node_modules/@mswjs/interceptors/lib/browser/chunk-FGSEOIC4.js @@ -0,0 +1,228 @@ +"use strict";Object.defineProperty(exports, "__esModule", {value: true});// src/RequestController.ts +var _outvariant = require('outvariant'); +var _deferredpromise = require('@open-draft/deferred-promise'); + +// src/InterceptorError.ts +var InterceptorError = class extends Error { + constructor(message) { + super(message); + this.name = "InterceptorError"; + Object.setPrototypeOf(this, InterceptorError.prototype); + } +}; + +// src/RequestController.ts +var kRequestHandled = Symbol("kRequestHandled"); +var kResponsePromise = Symbol("kResponsePromise"); +var RequestController = class { + constructor(request) { + this.request = request; + this[kRequestHandled] = false; + this[kResponsePromise] = new (0, _deferredpromise.DeferredPromise)(); + } + /** + * Respond to this request with the given `Response` instance. + * @example + * controller.respondWith(new Response()) + * controller.respondWith(Response.json({ id })) + * controller.respondWith(Response.error()) + */ + respondWith(response) { + _outvariant.invariant.as( + InterceptorError, + !this[kRequestHandled], + 'Failed to respond to the "%s %s" request: the "request" event has already been handled.', + this.request.method, + this.request.url + ); + this[kRequestHandled] = true; + this[kResponsePromise].resolve(response); + } + /** + * Error this request with the given error. + * @example + * controller.errorWith() + * controller.errorWith(new Error('Oops!')) + */ + errorWith(error) { + _outvariant.invariant.as( + InterceptorError, + !this[kRequestHandled], + 'Failed to error the "%s %s" request: the "request" event has already been handled.', + this.request.method, + this.request.url + ); + this[kRequestHandled] = true; + this[kResponsePromise].resolve(error); + } +}; +kResponsePromise, kRequestHandled; + +// src/utils/emitAsync.ts +async function emitAsync(emitter, eventName, ...data) { + const listners = emitter.listeners(eventName); + if (listners.length === 0) { + return; + } + for (const listener of listners) { + await listener.apply(emitter, data); + } +} + +// src/utils/handleRequest.ts + +var _until = require('@open-draft/until'); + +// src/utils/isPropertyAccessible.ts +function isPropertyAccessible(obj, key) { + try { + obj[key]; + return true; + } catch (e) { + return false; + } +} + +// src/utils/responseUtils.ts +function createServerErrorResponse(body) { + return new Response( + JSON.stringify( + body instanceof Error ? { + name: body.name, + message: body.message, + stack: body.stack + } : body + ), + { + status: 500, + statusText: "Unhandled Exception", + headers: { + "Content-Type": "application/json" + } + } + ); +} +function isResponseError(response) { + return isPropertyAccessible(response, "type") && response.type === "error"; +} + +// src/utils/isNodeLikeError.ts +function isNodeLikeError(error) { + if (error == null) { + return false; + } + if (!(error instanceof Error)) { + return false; + } + return "code" in error && "errno" in error; +} + +// src/utils/handleRequest.ts +async function handleRequest(options) { + const handleResponse = async (response) => { + if (response instanceof Error) { + options.onError(response); + } else if (isResponseError(response)) { + options.onRequestError(response); + } else { + await options.onResponse(response); + } + return true; + }; + const handleResponseError = async (error) => { + if (error instanceof InterceptorError) { + throw result.error; + } + if (isNodeLikeError(error)) { + options.onError(error); + return true; + } + if (error instanceof Response) { + return await handleResponse(error); + } + return false; + }; + options.emitter.once("request", ({ requestId: pendingRequestId }) => { + if (pendingRequestId !== options.requestId) { + return; + } + if (options.controller[kResponsePromise].state === "pending") { + options.controller[kResponsePromise].resolve(void 0); + } + }); + const requestAbortPromise = new (0, _deferredpromise.DeferredPromise)(); + if (options.request.signal) { + if (options.request.signal.aborted) { + requestAbortPromise.reject(options.request.signal.reason); + } else { + options.request.signal.addEventListener( + "abort", + () => { + requestAbortPromise.reject(options.request.signal.reason); + }, + { once: true } + ); + } + } + const result = await _until.until.call(void 0, async () => { + const requestListtenersPromise = emitAsync(options.emitter, "request", { + requestId: options.requestId, + request: options.request, + controller: options.controller + }); + await Promise.race([ + // Short-circuit the request handling promise if the request gets aborted. + requestAbortPromise, + requestListtenersPromise, + options.controller[kResponsePromise] + ]); + const mockedResponse = await options.controller[kResponsePromise]; + return mockedResponse; + }); + if (requestAbortPromise.state === "rejected") { + options.onError(requestAbortPromise.rejectionReason); + return true; + } + if (result.error) { + if (await handleResponseError(result.error)) { + return true; + } + if (options.emitter.listenerCount("unhandledException") > 0) { + const unhandledExceptionController = new RequestController( + options.request + ); + await emitAsync(options.emitter, "unhandledException", { + error: result.error, + request: options.request, + requestId: options.requestId, + controller: unhandledExceptionController + }).then(() => { + if (unhandledExceptionController[kResponsePromise].state === "pending") { + unhandledExceptionController[kResponsePromise].resolve(void 0); + } + }); + const nextResult = await _until.until.call(void 0, + () => unhandledExceptionController[kResponsePromise] + ); + if (nextResult.error) { + return handleResponseError(nextResult.error); + } + if (nextResult.data) { + return handleResponse(nextResult.data); + } + } + options.onResponse(createServerErrorResponse(result.error)); + return true; + } + if (result.data) { + return handleResponse(result.data); + } + return false; +} + + + + + +exports.RequestController = RequestController; exports.emitAsync = emitAsync; exports.handleRequest = handleRequest; +//# sourceMappingURL=chunk-FGSEOIC4.js.map \ No newline at end of file diff --git a/node_modules/@mswjs/interceptors/lib/browser/chunk-FGSEOIC4.js.map b/node_modules/@mswjs/interceptors/lib/browser/chunk-FGSEOIC4.js.map new file mode 100644 index 0000000000000000000000000000000000000000..9c5a436574e934d12c4688b420d1d0056a473f9d --- /dev/null +++ b/node_modules/@mswjs/interceptors/lib/browser/chunk-FGSEOIC4.js.map @@ -0,0 +1 @@ +{"version":3,"sources":["../../src/RequestController.ts","../../src/InterceptorError.ts","../../src/utils/emitAsync.ts","../../src/utils/handleRequest.ts","../../src/utils/isPropertyAccessible.ts","../../src/utils/responseUtils.ts","../../src/utils/isNodeLikeError.ts"],"names":["DeferredPromise"],"mappings":"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","sourcesContent":["import { invariant } from 'outvariant'\nimport { DeferredPromise } from '@open-draft/deferred-promise'\nimport { InterceptorError } from './InterceptorError'\n\nconst kRequestHandled = Symbol('kRequestHandled')\nexport const kResponsePromise = Symbol('kResponsePromise')\n\nexport class RequestController {\n /**\n * Internal response promise.\n * Available only for the library internals to grab the\n * response instance provided by the developer.\n * @note This promise cannot be rejected. It's either infinitely\n * pending or resolved with whichever Response was passed to `respondWith()`.\n */\n [kResponsePromise]: DeferredPromise;\n\n /**\n * Internal flag indicating if this request has been handled.\n * @note The response promise becomes \"fulfilled\" on the next tick.\n */\n [kRequestHandled]: boolean\n\n constructor(private request: Request) {\n this[kRequestHandled] = false\n this[kResponsePromise] = new DeferredPromise()\n }\n\n /**\n * Respond to this request with the given `Response` instance.\n * @example\n * controller.respondWith(new Response())\n * controller.respondWith(Response.json({ id }))\n * controller.respondWith(Response.error())\n */\n public respondWith(response: Response): void {\n invariant.as(\n InterceptorError,\n !this[kRequestHandled],\n 'Failed to respond to the \"%s %s\" request: the \"request\" event has already been handled.',\n this.request.method,\n this.request.url\n )\n\n this[kRequestHandled] = true\n this[kResponsePromise].resolve(response)\n\n /**\n * @note The request conrtoller doesn't do anything\n * apart from letting the interceptor await the response\n * provided by the developer through the response promise.\n * Each interceptor implements the actual respondWith/errorWith\n * logic based on that interceptor's needs.\n */\n }\n\n /**\n * Error this request with the given error.\n * @example\n * controller.errorWith()\n * controller.errorWith(new Error('Oops!'))\n */\n public errorWith(error?: Error): void {\n invariant.as(\n InterceptorError,\n !this[kRequestHandled],\n 'Failed to error the \"%s %s\" request: the \"request\" event has already been handled.',\n this.request.method,\n this.request.url\n )\n\n this[kRequestHandled] = true\n\n /**\n * @note Resolve the response promise, not reject.\n * This helps us differentiate between unhandled exceptions\n * and intended errors (\"errorWith\") while waiting for the response.\n */\n this[kResponsePromise].resolve(error)\n }\n}\n","export class InterceptorError extends Error {\n constructor(message?: string) {\n super(message)\n this.name = 'InterceptorError'\n Object.setPrototypeOf(this, InterceptorError.prototype)\n }\n}\n","import { Emitter, EventMap } from 'strict-event-emitter'\n\n/**\n * Emits an event on the given emitter but executes\n * the listeners sequentially. This accounts for asynchronous\n * listeners (e.g. those having \"sleep\" and handling the request).\n */\nexport async function emitAsync<\n Events extends EventMap,\n EventName extends keyof Events\n>(\n emitter: Emitter,\n eventName: EventName,\n ...data: Events[EventName]\n): Promise {\n const listners = emitter.listeners(eventName)\n\n if (listners.length === 0) {\n return\n }\n\n for (const listener of listners) {\n await listener.apply(emitter, data)\n }\n}\n","import type { Emitter } from 'strict-event-emitter'\nimport { DeferredPromise } from '@open-draft/deferred-promise'\nimport { until } from '@open-draft/until'\nimport type { HttpRequestEventMap } from '../glossary'\nimport { emitAsync } from './emitAsync'\nimport { kResponsePromise, RequestController } from '../RequestController'\nimport {\n createServerErrorResponse,\n isResponseError,\n ResponseError,\n} from './responseUtils'\nimport { InterceptorError } from '../InterceptorError'\nimport { isNodeLikeError } from './isNodeLikeError'\n\ninterface HandleRequestOptions {\n requestId: string\n request: Request\n emitter: Emitter\n controller: RequestController\n\n /**\n * Called when the request has been handled\n * with the given `Response` instance.\n */\n onResponse: (response: Response) => void | Promise\n\n /**\n * Called when the request has been handled\n * with the given `Response.error()` instance.\n */\n onRequestError: (response: ResponseError) => void\n\n /**\n * Called when an unhandled error happens during the\n * request handling. This is never a thrown error/response.\n */\n onError: (error: unknown) => void\n}\n\n/**\n * @returns {Promise} Indicates whether the request has been handled.\n */\nexport async function handleRequest(\n options: HandleRequestOptions\n): Promise {\n const handleResponse = async (response: Response | Error) => {\n if (response instanceof Error) {\n options.onError(response)\n }\n\n // Handle \"Response.error()\" instances.\n else if (isResponseError(response)) {\n options.onRequestError(response)\n } else {\n await options.onResponse(response)\n }\n\n return true\n }\n\n const handleResponseError = async (error: unknown): Promise => {\n // Forward the special interceptor error instances\n // to the developer. These must not be handled in any way.\n if (error instanceof InterceptorError) {\n throw result.error\n }\n\n // Support mocking Node.js-like errors.\n if (isNodeLikeError(error)) {\n options.onError(error)\n return true\n }\n\n // Handle thrown responses.\n if (error instanceof Response) {\n return await handleResponse(error)\n }\n\n return false\n }\n\n // Add the last \"request\" listener to check if the request\n // has been handled in any way. If it hasn't, resolve the\n // response promise with undefined.\n options.emitter.once('request', ({ requestId: pendingRequestId }) => {\n if (pendingRequestId !== options.requestId) {\n return\n }\n\n if (options.controller[kResponsePromise].state === 'pending') {\n options.controller[kResponsePromise].resolve(undefined)\n }\n })\n\n const requestAbortPromise = new DeferredPromise()\n\n /**\n * @note `signal` is not always defined in React Native.\n */\n if (options.request.signal) {\n if (options.request.signal.aborted) {\n requestAbortPromise.reject(options.request.signal.reason)\n } else {\n options.request.signal.addEventListener(\n 'abort',\n () => {\n requestAbortPromise.reject(options.request.signal.reason)\n },\n { once: true }\n )\n }\n }\n\n const result = await until(async () => {\n // Emit the \"request\" event and wait until all the listeners\n // for that event are finished (e.g. async listeners awaited).\n // By the end of this promise, the developer cannot affect the\n // request anymore.\n const requestListtenersPromise = emitAsync(options.emitter, 'request', {\n requestId: options.requestId,\n request: options.request,\n controller: options.controller,\n })\n\n await Promise.race([\n // Short-circuit the request handling promise if the request gets aborted.\n requestAbortPromise,\n requestListtenersPromise,\n options.controller[kResponsePromise],\n ])\n\n // The response promise will settle immediately once\n // the developer calls either \"respondWith\" or \"errorWith\".\n const mockedResponse = await options.controller[kResponsePromise]\n return mockedResponse\n })\n\n // Handle the request being aborted while waiting for the request listeners.\n if (requestAbortPromise.state === 'rejected') {\n options.onError(requestAbortPromise.rejectionReason)\n return true\n }\n\n if (result.error) {\n // Handle the error during the request listener execution.\n // These can be thrown responses or request errors.\n if (await handleResponseError(result.error)) {\n return true\n }\n\n // If the developer has added \"unhandledException\" listeners,\n // allow them to handle the error. They can translate it to a\n // mocked response, network error, or forward it as-is.\n if (options.emitter.listenerCount('unhandledException') > 0) {\n // Create a new request controller just for the unhandled exception case.\n // This is needed because the original controller might have been already\n // interacted with (e.g. \"respondWith\" or \"errorWith\" called on it).\n const unhandledExceptionController = new RequestController(\n options.request\n )\n\n await emitAsync(options.emitter, 'unhandledException', {\n error: result.error,\n request: options.request,\n requestId: options.requestId,\n controller: unhandledExceptionController,\n }).then(() => {\n // If all the \"unhandledException\" listeners have finished\n // but have not handled the response in any way, preemptively\n // resolve the pending response promise from the new controller.\n // This prevents it from hanging forever.\n if (\n unhandledExceptionController[kResponsePromise].state === 'pending'\n ) {\n unhandledExceptionController[kResponsePromise].resolve(undefined)\n }\n })\n\n const nextResult = await until(\n () => unhandledExceptionController[kResponsePromise]\n )\n\n /**\n * @note Handle the result of the unhandled controller\n * in the same way as the original request controller.\n * The exception here is that thrown errors within the\n * \"unhandledException\" event do NOT result in another\n * emit of the same event. They are forwarded as-is.\n */\n if (nextResult.error) {\n return handleResponseError(nextResult.error)\n }\n\n if (nextResult.data) {\n return handleResponse(nextResult.data)\n }\n }\n\n // Otherwise, coerce unhandled exceptions to a 500 Internal Server Error response.\n options.onResponse(createServerErrorResponse(result.error))\n return true\n }\n\n /**\n * Handle a mocked Response instance.\n * @note That this can also be an Error in case\n * the developer called \"errorWith\". This differentiates\n * unhandled exceptions from intended errors.\n */\n if (result.data) {\n return handleResponse(result.data)\n }\n\n // In all other cases, consider the request unhandled.\n // The interceptor must perform it as-is.\n return false\n}\n","/**\n * A function that validates if property access is possible on an object\n * without throwing. It returns `true` if the property access is possible\n * and `false` otherwise.\n *\n * Environments like miniflare will throw on property access on certain objects\n * like Request and Response, for unimplemented properties.\n */\nexport function isPropertyAccessible>(\n obj: Obj,\n key: keyof Obj\n) {\n try {\n obj[key]\n return true\n } catch {\n return false\n }\n}\n","import { isPropertyAccessible } from './isPropertyAccessible'\n\n/**\n * Creates a generic 500 Unhandled Exception response.\n */\nexport function createServerErrorResponse(body: unknown): Response {\n return new Response(\n JSON.stringify(\n body instanceof Error\n ? {\n name: body.name,\n message: body.message,\n stack: body.stack,\n }\n : body\n ),\n {\n status: 500,\n statusText: 'Unhandled Exception',\n headers: {\n 'Content-Type': 'application/json',\n },\n }\n )\n}\n\nexport type ResponseError = Response & { type: 'error' }\n\n/**\n * Check if the given response is a `Response.error()`.\n *\n * @note Some environments, like Miniflare (Cloudflare) do not\n * implement the \"Response.type\" property and throw on its access.\n * Safely check if we can access \"type\" on \"Response\" before continuing.\n * @see https://github.com/mswjs/msw/issues/1834\n */\nexport function isResponseError(response: Response): response is ResponseError {\n return isPropertyAccessible(response, 'type') && response.type === 'error'\n}\n","export function isNodeLikeError(\n error: unknown\n): error is NodeJS.ErrnoException {\n if (error == null) {\n return false\n }\n\n if (!(error instanceof Error)) {\n return false\n }\n\n return 'code' in error && 'errno' in error\n}\n"]} \ No newline at end of file diff --git a/node_modules/@mswjs/interceptors/lib/browser/chunk-H5O73WD2.mjs b/node_modules/@mswjs/interceptors/lib/browser/chunk-H5O73WD2.mjs new file mode 100644 index 0000000000000000000000000000000000000000..193b4416ef5549ae1365c2b4311bad69be081efd --- /dev/null +++ b/node_modules/@mswjs/interceptors/lib/browser/chunk-H5O73WD2.mjs @@ -0,0 +1,228 @@ +// src/RequestController.ts +import { invariant } from "outvariant"; +import { DeferredPromise } from "@open-draft/deferred-promise"; + +// src/InterceptorError.ts +var InterceptorError = class extends Error { + constructor(message) { + super(message); + this.name = "InterceptorError"; + Object.setPrototypeOf(this, InterceptorError.prototype); + } +}; + +// src/RequestController.ts +var kRequestHandled = Symbol("kRequestHandled"); +var kResponsePromise = Symbol("kResponsePromise"); +var RequestController = class { + constructor(request) { + this.request = request; + this[kRequestHandled] = false; + this[kResponsePromise] = new DeferredPromise(); + } + /** + * Respond to this request with the given `Response` instance. + * @example + * controller.respondWith(new Response()) + * controller.respondWith(Response.json({ id })) + * controller.respondWith(Response.error()) + */ + respondWith(response) { + invariant.as( + InterceptorError, + !this[kRequestHandled], + 'Failed to respond to the "%s %s" request: the "request" event has already been handled.', + this.request.method, + this.request.url + ); + this[kRequestHandled] = true; + this[kResponsePromise].resolve(response); + } + /** + * Error this request with the given error. + * @example + * controller.errorWith() + * controller.errorWith(new Error('Oops!')) + */ + errorWith(error) { + invariant.as( + InterceptorError, + !this[kRequestHandled], + 'Failed to error the "%s %s" request: the "request" event has already been handled.', + this.request.method, + this.request.url + ); + this[kRequestHandled] = true; + this[kResponsePromise].resolve(error); + } +}; +kResponsePromise, kRequestHandled; + +// src/utils/emitAsync.ts +async function emitAsync(emitter, eventName, ...data) { + const listners = emitter.listeners(eventName); + if (listners.length === 0) { + return; + } + for (const listener of listners) { + await listener.apply(emitter, data); + } +} + +// src/utils/handleRequest.ts +import { DeferredPromise as DeferredPromise2 } from "@open-draft/deferred-promise"; +import { until } from "@open-draft/until"; + +// src/utils/isPropertyAccessible.ts +function isPropertyAccessible(obj, key) { + try { + obj[key]; + return true; + } catch (e) { + return false; + } +} + +// src/utils/responseUtils.ts +function createServerErrorResponse(body) { + return new Response( + JSON.stringify( + body instanceof Error ? { + name: body.name, + message: body.message, + stack: body.stack + } : body + ), + { + status: 500, + statusText: "Unhandled Exception", + headers: { + "Content-Type": "application/json" + } + } + ); +} +function isResponseError(response) { + return isPropertyAccessible(response, "type") && response.type === "error"; +} + +// src/utils/isNodeLikeError.ts +function isNodeLikeError(error) { + if (error == null) { + return false; + } + if (!(error instanceof Error)) { + return false; + } + return "code" in error && "errno" in error; +} + +// src/utils/handleRequest.ts +async function handleRequest(options) { + const handleResponse = async (response) => { + if (response instanceof Error) { + options.onError(response); + } else if (isResponseError(response)) { + options.onRequestError(response); + } else { + await options.onResponse(response); + } + return true; + }; + const handleResponseError = async (error) => { + if (error instanceof InterceptorError) { + throw result.error; + } + if (isNodeLikeError(error)) { + options.onError(error); + return true; + } + if (error instanceof Response) { + return await handleResponse(error); + } + return false; + }; + options.emitter.once("request", ({ requestId: pendingRequestId }) => { + if (pendingRequestId !== options.requestId) { + return; + } + if (options.controller[kResponsePromise].state === "pending") { + options.controller[kResponsePromise].resolve(void 0); + } + }); + const requestAbortPromise = new DeferredPromise2(); + if (options.request.signal) { + if (options.request.signal.aborted) { + requestAbortPromise.reject(options.request.signal.reason); + } else { + options.request.signal.addEventListener( + "abort", + () => { + requestAbortPromise.reject(options.request.signal.reason); + }, + { once: true } + ); + } + } + const result = await until(async () => { + const requestListtenersPromise = emitAsync(options.emitter, "request", { + requestId: options.requestId, + request: options.request, + controller: options.controller + }); + await Promise.race([ + // Short-circuit the request handling promise if the request gets aborted. + requestAbortPromise, + requestListtenersPromise, + options.controller[kResponsePromise] + ]); + const mockedResponse = await options.controller[kResponsePromise]; + return mockedResponse; + }); + if (requestAbortPromise.state === "rejected") { + options.onError(requestAbortPromise.rejectionReason); + return true; + } + if (result.error) { + if (await handleResponseError(result.error)) { + return true; + } + if (options.emitter.listenerCount("unhandledException") > 0) { + const unhandledExceptionController = new RequestController( + options.request + ); + await emitAsync(options.emitter, "unhandledException", { + error: result.error, + request: options.request, + requestId: options.requestId, + controller: unhandledExceptionController + }).then(() => { + if (unhandledExceptionController[kResponsePromise].state === "pending") { + unhandledExceptionController[kResponsePromise].resolve(void 0); + } + }); + const nextResult = await until( + () => unhandledExceptionController[kResponsePromise] + ); + if (nextResult.error) { + return handleResponseError(nextResult.error); + } + if (nextResult.data) { + return handleResponse(nextResult.data); + } + } + options.onResponse(createServerErrorResponse(result.error)); + return true; + } + if (result.data) { + return handleResponse(result.data); + } + return false; +} + +export { + RequestController, + emitAsync, + handleRequest +}; +//# sourceMappingURL=chunk-H5O73WD2.mjs.map \ No newline at end of file diff --git a/node_modules/@mswjs/interceptors/lib/browser/chunk-H5O73WD2.mjs.map b/node_modules/@mswjs/interceptors/lib/browser/chunk-H5O73WD2.mjs.map new file mode 100644 index 0000000000000000000000000000000000000000..41215da76064f753f0fe9ade069a3f63da6bc0aa --- /dev/null +++ b/node_modules/@mswjs/interceptors/lib/browser/chunk-H5O73WD2.mjs.map @@ -0,0 +1 @@ +{"version":3,"sources":["../../src/RequestController.ts","../../src/InterceptorError.ts","../../src/utils/emitAsync.ts","../../src/utils/handleRequest.ts","../../src/utils/isPropertyAccessible.ts","../../src/utils/responseUtils.ts","../../src/utils/isNodeLikeError.ts"],"sourcesContent":["import { invariant } from 'outvariant'\nimport { DeferredPromise } from '@open-draft/deferred-promise'\nimport { InterceptorError } from './InterceptorError'\n\nconst kRequestHandled = Symbol('kRequestHandled')\nexport const kResponsePromise = Symbol('kResponsePromise')\n\nexport class RequestController {\n /**\n * Internal response promise.\n * Available only for the library internals to grab the\n * response instance provided by the developer.\n * @note This promise cannot be rejected. It's either infinitely\n * pending or resolved with whichever Response was passed to `respondWith()`.\n */\n [kResponsePromise]: DeferredPromise;\n\n /**\n * Internal flag indicating if this request has been handled.\n * @note The response promise becomes \"fulfilled\" on the next tick.\n */\n [kRequestHandled]: boolean\n\n constructor(private request: Request) {\n this[kRequestHandled] = false\n this[kResponsePromise] = new DeferredPromise()\n }\n\n /**\n * Respond to this request with the given `Response` instance.\n * @example\n * controller.respondWith(new Response())\n * controller.respondWith(Response.json({ id }))\n * controller.respondWith(Response.error())\n */\n public respondWith(response: Response): void {\n invariant.as(\n InterceptorError,\n !this[kRequestHandled],\n 'Failed to respond to the \"%s %s\" request: the \"request\" event has already been handled.',\n this.request.method,\n this.request.url\n )\n\n this[kRequestHandled] = true\n this[kResponsePromise].resolve(response)\n\n /**\n * @note The request conrtoller doesn't do anything\n * apart from letting the interceptor await the response\n * provided by the developer through the response promise.\n * Each interceptor implements the actual respondWith/errorWith\n * logic based on that interceptor's needs.\n */\n }\n\n /**\n * Error this request with the given error.\n * @example\n * controller.errorWith()\n * controller.errorWith(new Error('Oops!'))\n */\n public errorWith(error?: Error): void {\n invariant.as(\n InterceptorError,\n !this[kRequestHandled],\n 'Failed to error the \"%s %s\" request: the \"request\" event has already been handled.',\n this.request.method,\n this.request.url\n )\n\n this[kRequestHandled] = true\n\n /**\n * @note Resolve the response promise, not reject.\n * This helps us differentiate between unhandled exceptions\n * and intended errors (\"errorWith\") while waiting for the response.\n */\n this[kResponsePromise].resolve(error)\n }\n}\n","export class InterceptorError extends Error {\n constructor(message?: string) {\n super(message)\n this.name = 'InterceptorError'\n Object.setPrototypeOf(this, InterceptorError.prototype)\n }\n}\n","import { Emitter, EventMap } from 'strict-event-emitter'\n\n/**\n * Emits an event on the given emitter but executes\n * the listeners sequentially. This accounts for asynchronous\n * listeners (e.g. those having \"sleep\" and handling the request).\n */\nexport async function emitAsync<\n Events extends EventMap,\n EventName extends keyof Events\n>(\n emitter: Emitter,\n eventName: EventName,\n ...data: Events[EventName]\n): Promise {\n const listners = emitter.listeners(eventName)\n\n if (listners.length === 0) {\n return\n }\n\n for (const listener of listners) {\n await listener.apply(emitter, data)\n }\n}\n","import type { Emitter } from 'strict-event-emitter'\nimport { DeferredPromise } from '@open-draft/deferred-promise'\nimport { until } from '@open-draft/until'\nimport type { HttpRequestEventMap } from '../glossary'\nimport { emitAsync } from './emitAsync'\nimport { kResponsePromise, RequestController } from '../RequestController'\nimport {\n createServerErrorResponse,\n isResponseError,\n ResponseError,\n} from './responseUtils'\nimport { InterceptorError } from '../InterceptorError'\nimport { isNodeLikeError } from './isNodeLikeError'\n\ninterface HandleRequestOptions {\n requestId: string\n request: Request\n emitter: Emitter\n controller: RequestController\n\n /**\n * Called when the request has been handled\n * with the given `Response` instance.\n */\n onResponse: (response: Response) => void | Promise\n\n /**\n * Called when the request has been handled\n * with the given `Response.error()` instance.\n */\n onRequestError: (response: ResponseError) => void\n\n /**\n * Called when an unhandled error happens during the\n * request handling. This is never a thrown error/response.\n */\n onError: (error: unknown) => void\n}\n\n/**\n * @returns {Promise} Indicates whether the request has been handled.\n */\nexport async function handleRequest(\n options: HandleRequestOptions\n): Promise {\n const handleResponse = async (response: Response | Error) => {\n if (response instanceof Error) {\n options.onError(response)\n }\n\n // Handle \"Response.error()\" instances.\n else if (isResponseError(response)) {\n options.onRequestError(response)\n } else {\n await options.onResponse(response)\n }\n\n return true\n }\n\n const handleResponseError = async (error: unknown): Promise => {\n // Forward the special interceptor error instances\n // to the developer. These must not be handled in any way.\n if (error instanceof InterceptorError) {\n throw result.error\n }\n\n // Support mocking Node.js-like errors.\n if (isNodeLikeError(error)) {\n options.onError(error)\n return true\n }\n\n // Handle thrown responses.\n if (error instanceof Response) {\n return await handleResponse(error)\n }\n\n return false\n }\n\n // Add the last \"request\" listener to check if the request\n // has been handled in any way. If it hasn't, resolve the\n // response promise with undefined.\n options.emitter.once('request', ({ requestId: pendingRequestId }) => {\n if (pendingRequestId !== options.requestId) {\n return\n }\n\n if (options.controller[kResponsePromise].state === 'pending') {\n options.controller[kResponsePromise].resolve(undefined)\n }\n })\n\n const requestAbortPromise = new DeferredPromise()\n\n /**\n * @note `signal` is not always defined in React Native.\n */\n if (options.request.signal) {\n if (options.request.signal.aborted) {\n requestAbortPromise.reject(options.request.signal.reason)\n } else {\n options.request.signal.addEventListener(\n 'abort',\n () => {\n requestAbortPromise.reject(options.request.signal.reason)\n },\n { once: true }\n )\n }\n }\n\n const result = await until(async () => {\n // Emit the \"request\" event and wait until all the listeners\n // for that event are finished (e.g. async listeners awaited).\n // By the end of this promise, the developer cannot affect the\n // request anymore.\n const requestListtenersPromise = emitAsync(options.emitter, 'request', {\n requestId: options.requestId,\n request: options.request,\n controller: options.controller,\n })\n\n await Promise.race([\n // Short-circuit the request handling promise if the request gets aborted.\n requestAbortPromise,\n requestListtenersPromise,\n options.controller[kResponsePromise],\n ])\n\n // The response promise will settle immediately once\n // the developer calls either \"respondWith\" or \"errorWith\".\n const mockedResponse = await options.controller[kResponsePromise]\n return mockedResponse\n })\n\n // Handle the request being aborted while waiting for the request listeners.\n if (requestAbortPromise.state === 'rejected') {\n options.onError(requestAbortPromise.rejectionReason)\n return true\n }\n\n if (result.error) {\n // Handle the error during the request listener execution.\n // These can be thrown responses or request errors.\n if (await handleResponseError(result.error)) {\n return true\n }\n\n // If the developer has added \"unhandledException\" listeners,\n // allow them to handle the error. They can translate it to a\n // mocked response, network error, or forward it as-is.\n if (options.emitter.listenerCount('unhandledException') > 0) {\n // Create a new request controller just for the unhandled exception case.\n // This is needed because the original controller might have been already\n // interacted with (e.g. \"respondWith\" or \"errorWith\" called on it).\n const unhandledExceptionController = new RequestController(\n options.request\n )\n\n await emitAsync(options.emitter, 'unhandledException', {\n error: result.error,\n request: options.request,\n requestId: options.requestId,\n controller: unhandledExceptionController,\n }).then(() => {\n // If all the \"unhandledException\" listeners have finished\n // but have not handled the response in any way, preemptively\n // resolve the pending response promise from the new controller.\n // This prevents it from hanging forever.\n if (\n unhandledExceptionController[kResponsePromise].state === 'pending'\n ) {\n unhandledExceptionController[kResponsePromise].resolve(undefined)\n }\n })\n\n const nextResult = await until(\n () => unhandledExceptionController[kResponsePromise]\n )\n\n /**\n * @note Handle the result of the unhandled controller\n * in the same way as the original request controller.\n * The exception here is that thrown errors within the\n * \"unhandledException\" event do NOT result in another\n * emit of the same event. They are forwarded as-is.\n */\n if (nextResult.error) {\n return handleResponseError(nextResult.error)\n }\n\n if (nextResult.data) {\n return handleResponse(nextResult.data)\n }\n }\n\n // Otherwise, coerce unhandled exceptions to a 500 Internal Server Error response.\n options.onResponse(createServerErrorResponse(result.error))\n return true\n }\n\n /**\n * Handle a mocked Response instance.\n * @note That this can also be an Error in case\n * the developer called \"errorWith\". This differentiates\n * unhandled exceptions from intended errors.\n */\n if (result.data) {\n return handleResponse(result.data)\n }\n\n // In all other cases, consider the request unhandled.\n // The interceptor must perform it as-is.\n return false\n}\n","/**\n * A function that validates if property access is possible on an object\n * without throwing. It returns `true` if the property access is possible\n * and `false` otherwise.\n *\n * Environments like miniflare will throw on property access on certain objects\n * like Request and Response, for unimplemented properties.\n */\nexport function isPropertyAccessible>(\n obj: Obj,\n key: keyof Obj\n) {\n try {\n obj[key]\n return true\n } catch {\n return false\n }\n}\n","import { isPropertyAccessible } from './isPropertyAccessible'\n\n/**\n * Creates a generic 500 Unhandled Exception response.\n */\nexport function createServerErrorResponse(body: unknown): Response {\n return new Response(\n JSON.stringify(\n body instanceof Error\n ? {\n name: body.name,\n message: body.message,\n stack: body.stack,\n }\n : body\n ),\n {\n status: 500,\n statusText: 'Unhandled Exception',\n headers: {\n 'Content-Type': 'application/json',\n },\n }\n )\n}\n\nexport type ResponseError = Response & { type: 'error' }\n\n/**\n * Check if the given response is a `Response.error()`.\n *\n * @note Some environments, like Miniflare (Cloudflare) do not\n * implement the \"Response.type\" property and throw on its access.\n * Safely check if we can access \"type\" on \"Response\" before continuing.\n * @see https://github.com/mswjs/msw/issues/1834\n */\nexport function isResponseError(response: Response): response is ResponseError {\n return isPropertyAccessible(response, 'type') && response.type === 'error'\n}\n","export function isNodeLikeError(\n error: unknown\n): error is NodeJS.ErrnoException {\n if (error == null) {\n return false\n }\n\n if (!(error instanceof Error)) {\n return false\n }\n\n return 'code' in error && 'errno' in error\n}\n"],"mappings":";AAAA,SAAS,iBAAiB;AAC1B,SAAS,uBAAuB;;;ACDzB,IAAM,mBAAN,cAA+B,MAAM;AAAA,EAC1C,YAAY,SAAkB;AAC5B,UAAM,OAAO;AACb,SAAK,OAAO;AACZ,WAAO,eAAe,MAAM,iBAAiB,SAAS;AAAA,EACxD;AACF;;;ADFA,IAAM,kBAAkB,OAAO,iBAAiB;AACzC,IAAM,mBAAmB,OAAO,kBAAkB;AAElD,IAAM,oBAAN,MAAwB;AAAA,EAgB7B,YAAoB,SAAkB;AAAlB;AAClB,SAAK,eAAe,IAAI;AACxB,SAAK,gBAAgB,IAAI,IAAI,gBAAgB;AAAA,EAC/C;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASO,YAAY,UAA0B;AAC3C,cAAU;AAAA,MACR;AAAA,MACA,CAAC,KAAK,eAAe;AAAA,MACrB;AAAA,MACA,KAAK,QAAQ;AAAA,MACb,KAAK,QAAQ;AAAA,IACf;AAEA,SAAK,eAAe,IAAI;AACxB,SAAK,gBAAgB,EAAE,QAAQ,QAAQ;AAAA,EASzC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQO,UAAU,OAAqB;AACpC,cAAU;AAAA,MACR;AAAA,MACA,CAAC,KAAK,eAAe;AAAA,MACrB;AAAA,MACA,KAAK,QAAQ;AAAA,MACb,KAAK,QAAQ;AAAA,IACf;AAEA,SAAK,eAAe,IAAI;AAOxB,SAAK,gBAAgB,EAAE,QAAQ,KAAK;AAAA,EACtC;AACF;AAjEG,kBAMA;;;AEdH,eAAsB,UAIpB,SACA,cACG,MACY;AACf,QAAM,WAAW,QAAQ,UAAU,SAAS;AAE5C,MAAI,SAAS,WAAW,GAAG;AACzB;AAAA,EACF;AAEA,aAAW,YAAY,UAAU;AAC/B,UAAM,SAAS,MAAM,SAAS,IAAI;AAAA,EACpC;AACF;;;ACvBA,SAAS,mBAAAA,wBAAuB;AAChC,SAAS,aAAa;;;ACMf,SAAS,qBACd,KACA,KACA;AACA,MAAI;AACF,QAAI,GAAG;AACP,WAAO;AAAA,EACT,SAAQ,GAAN;AACA,WAAO;AAAA,EACT;AACF;;;ACbO,SAAS,0BAA0B,MAAyB;AACjE,SAAO,IAAI;AAAA,IACT,KAAK;AAAA,MACH,gBAAgB,QACZ;AAAA,QACE,MAAM,KAAK;AAAA,QACX,SAAS,KAAK;AAAA,QACd,OAAO,KAAK;AAAA,MACd,IACA;AAAA,IACN;AAAA,IACA;AAAA,MACE,QAAQ;AAAA,MACR,YAAY;AAAA,MACZ,SAAS;AAAA,QACP,gBAAgB;AAAA,MAClB;AAAA,IACF;AAAA,EACF;AACF;AAYO,SAAS,gBAAgB,UAA+C;AAC7E,SAAO,qBAAqB,UAAU,MAAM,KAAK,SAAS,SAAS;AACrE;;;ACtCO,SAAS,gBACd,OACgC;AAChC,MAAI,SAAS,MAAM;AACjB,WAAO;AAAA,EACT;AAEA,MAAI,EAAE,iBAAiB,QAAQ;AAC7B,WAAO;AAAA,EACT;AAEA,SAAO,UAAU,SAAS,WAAW;AACvC;;;AH8BA,eAAsB,cACpB,SACkB;AAClB,QAAM,iBAAiB,OAAO,aAA+B;AAC3D,QAAI,oBAAoB,OAAO;AAC7B,cAAQ,QAAQ,QAAQ;AAAA,IAC1B,WAGS,gBAAgB,QAAQ,GAAG;AAClC,cAAQ,eAAe,QAAQ;AAAA,IACjC,OAAO;AACL,YAAM,QAAQ,WAAW,QAAQ;AAAA,IACnC;AAEA,WAAO;AAAA,EACT;AAEA,QAAM,sBAAsB,OAAO,UAAqC;AAGtE,QAAI,iBAAiB,kBAAkB;AACrC,YAAM,OAAO;AAAA,IACf;AAGA,QAAI,gBAAgB,KAAK,GAAG;AAC1B,cAAQ,QAAQ,KAAK;AACrB,aAAO;AAAA,IACT;AAGA,QAAI,iBAAiB,UAAU;AAC7B,aAAO,MAAM,eAAe,KAAK;AAAA,IACnC;AAEA,WAAO;AAAA,EACT;AAKA,UAAQ,QAAQ,KAAK,WAAW,CAAC,EAAE,WAAW,iBAAiB,MAAM;AACnE,QAAI,qBAAqB,QAAQ,WAAW;AAC1C;AAAA,IACF;AAEA,QAAI,QAAQ,WAAW,gBAAgB,EAAE,UAAU,WAAW;AAC5D,cAAQ,WAAW,gBAAgB,EAAE,QAAQ,MAAS;AAAA,IACxD;AAAA,EACF,CAAC;AAED,QAAM,sBAAsB,IAAIC,iBAA+B;AAK/D,MAAI,QAAQ,QAAQ,QAAQ;AAC1B,QAAI,QAAQ,QAAQ,OAAO,SAAS;AAClC,0BAAoB,OAAO,QAAQ,QAAQ,OAAO,MAAM;AAAA,IAC1D,OAAO;AACL,cAAQ,QAAQ,OAAO;AAAA,QACrB;AAAA,QACA,MAAM;AACJ,8BAAoB,OAAO,QAAQ,QAAQ,OAAO,MAAM;AAAA,QAC1D;AAAA,QACA,EAAE,MAAM,KAAK;AAAA,MACf;AAAA,IACF;AAAA,EACF;AAEA,QAAM,SAAS,MAAM,MAAM,YAAY;AAKrC,UAAM,2BAA2B,UAAU,QAAQ,SAAS,WAAW;AAAA,MACrE,WAAW,QAAQ;AAAA,MACnB,SAAS,QAAQ;AAAA,MACjB,YAAY,QAAQ;AAAA,IACtB,CAAC;AAED,UAAM,QAAQ,KAAK;AAAA;AAAA,MAEjB;AAAA,MACA;AAAA,MACA,QAAQ,WAAW,gBAAgB;AAAA,IACrC,CAAC;AAID,UAAM,iBAAiB,MAAM,QAAQ,WAAW,gBAAgB;AAChE,WAAO;AAAA,EACT,CAAC;AAGD,MAAI,oBAAoB,UAAU,YAAY;AAC5C,YAAQ,QAAQ,oBAAoB,eAAe;AACnD,WAAO;AAAA,EACT;AAEA,MAAI,OAAO,OAAO;AAGhB,QAAI,MAAM,oBAAoB,OAAO,KAAK,GAAG;AAC3C,aAAO;AAAA,IACT;AAKA,QAAI,QAAQ,QAAQ,cAAc,oBAAoB,IAAI,GAAG;AAI3D,YAAM,+BAA+B,IAAI;AAAA,QACvC,QAAQ;AAAA,MACV;AAEA,YAAM,UAAU,QAAQ,SAAS,sBAAsB;AAAA,QACrD,OAAO,OAAO;AAAA,QACd,SAAS,QAAQ;AAAA,QACjB,WAAW,QAAQ;AAAA,QACnB,YAAY;AAAA,MACd,CAAC,EAAE,KAAK,MAAM;AAKZ,YACE,6BAA6B,gBAAgB,EAAE,UAAU,WACzD;AACA,uCAA6B,gBAAgB,EAAE,QAAQ,MAAS;AAAA,QAClE;AAAA,MACF,CAAC;AAED,YAAM,aAAa,MAAM;AAAA,QACvB,MAAM,6BAA6B,gBAAgB;AAAA,MACrD;AASA,UAAI,WAAW,OAAO;AACpB,eAAO,oBAAoB,WAAW,KAAK;AAAA,MAC7C;AAEA,UAAI,WAAW,MAAM;AACnB,eAAO,eAAe,WAAW,IAAI;AAAA,MACvC;AAAA,IACF;AAGA,YAAQ,WAAW,0BAA0B,OAAO,KAAK,CAAC;AAC1D,WAAO;AAAA,EACT;AAQA,MAAI,OAAO,MAAM;AACf,WAAO,eAAe,OAAO,IAAI;AAAA,EACnC;AAIA,SAAO;AACT;","names":["DeferredPromise","DeferredPromise"]} \ No newline at end of file diff --git a/node_modules/@mswjs/interceptors/lib/browser/chunk-LK6DILFK.js b/node_modules/@mswjs/interceptors/lib/browser/chunk-LK6DILFK.js new file mode 100644 index 0000000000000000000000000000000000000000..f41d9eae5715ee544bf3d8f597fd16e59a271f58 --- /dev/null +++ b/node_modules/@mswjs/interceptors/lib/browser/chunk-LK6DILFK.js @@ -0,0 +1,22 @@ +"use strict";Object.defineProperty(exports, "__esModule", {value: true});// src/utils/bufferUtils.ts +var encoder = new TextEncoder(); +function encodeBuffer(text) { + return encoder.encode(text); +} +function decodeBuffer(buffer, encoding) { + const decoder = new TextDecoder(encoding); + return decoder.decode(buffer); +} +function toArrayBuffer(array) { + return array.buffer.slice( + array.byteOffset, + array.byteOffset + array.byteLength + ); +} + + + + + +exports.encodeBuffer = encodeBuffer; exports.decodeBuffer = decodeBuffer; exports.toArrayBuffer = toArrayBuffer; +//# sourceMappingURL=chunk-LK6DILFK.js.map \ No newline at end of file diff --git a/node_modules/@mswjs/interceptors/lib/browser/chunk-LK6DILFK.js.map b/node_modules/@mswjs/interceptors/lib/browser/chunk-LK6DILFK.js.map new file mode 100644 index 0000000000000000000000000000000000000000..691683680b4e26eecaa7dfe2d0466c8f348eb21f --- /dev/null +++ b/node_modules/@mswjs/interceptors/lib/browser/chunk-LK6DILFK.js.map @@ -0,0 +1 @@ +{"version":3,"sources":["../../src/utils/bufferUtils.ts"],"names":[],"mappings":";AAAA,IAAM,UAAU,IAAI,YAAY;AAEzB,SAAS,aAAa,MAA0B;AACrD,SAAO,QAAQ,OAAO,IAAI;AAC5B;AAEO,SAAS,aAAa,QAAqB,UAA2B;AAC3E,QAAM,UAAU,IAAI,YAAY,QAAQ;AACxC,SAAO,QAAQ,OAAO,MAAM;AAC9B;AAOO,SAAS,cAAc,OAAgC;AAC5D,SAAO,MAAM,OAAO;AAAA,IAClB,MAAM;AAAA,IACN,MAAM,aAAa,MAAM;AAAA,EAC3B;AACF","sourcesContent":["const encoder = new TextEncoder()\n\nexport function encodeBuffer(text: string): Uint8Array {\n return encoder.encode(text)\n}\n\nexport function decodeBuffer(buffer: ArrayBuffer, encoding?: string): string {\n const decoder = new TextDecoder(encoding)\n return decoder.decode(buffer)\n}\n\n/**\n * Create an `ArrayBuffer` from the given `Uint8Array`.\n * Takes the byte offset into account to produce the right buffer\n * in the case when the buffer is bigger than the data view.\n */\nexport function toArrayBuffer(array: Uint8Array): ArrayBuffer {\n return array.buffer.slice(\n array.byteOffset,\n array.byteOffset + array.byteLength\n )\n}\n"]} \ No newline at end of file diff --git a/node_modules/@mswjs/interceptors/lib/browser/chunk-PFGO5BSM.js b/node_modules/@mswjs/interceptors/lib/browser/chunk-PFGO5BSM.js new file mode 100644 index 0000000000000000000000000000000000000000..3206fc0cb780f904a0c0b48ce7194828ae296162 --- /dev/null +++ b/node_modules/@mswjs/interceptors/lib/browser/chunk-PFGO5BSM.js @@ -0,0 +1,25 @@ +"use strict";Object.defineProperty(exports, "__esModule", {value: true});// src/utils/hasConfigurableGlobal.ts +function hasConfigurableGlobal(propertyName) { + const descriptor = Object.getOwnPropertyDescriptor(globalThis, propertyName); + if (typeof descriptor === "undefined") { + return false; + } + if (typeof descriptor.get === "function" && typeof descriptor.get() === "undefined") { + return false; + } + if (typeof descriptor.get === "undefined" && descriptor.value == null) { + return false; + } + if (typeof descriptor.set === "undefined" && !descriptor.configurable) { + console.error( + `[MSW] Failed to apply interceptor: the global \`${propertyName}\` property is non-configurable. This is likely an issue with your environment. If you are using a framework, please open an issue about this in their repository.` + ); + return false; + } + return true; +} + + + +exports.hasConfigurableGlobal = hasConfigurableGlobal; +//# sourceMappingURL=chunk-PFGO5BSM.js.map \ No newline at end of file diff --git a/node_modules/@mswjs/interceptors/lib/browser/chunk-PFGO5BSM.js.map b/node_modules/@mswjs/interceptors/lib/browser/chunk-PFGO5BSM.js.map new file mode 100644 index 0000000000000000000000000000000000000000..4069b5ab7b51ea60c2a3a8490c4b95b71d3797ab --- /dev/null +++ b/node_modules/@mswjs/interceptors/lib/browser/chunk-PFGO5BSM.js.map @@ -0,0 +1 @@ +{"version":3,"sources":["../../src/utils/hasConfigurableGlobal.ts"],"names":[],"mappings":";AAIO,SAAS,sBAAsB,cAA+B;AACnE,QAAM,aAAa,OAAO,yBAAyB,YAAY,YAAY;AAG3E,MAAI,OAAO,eAAe,aAAa;AACrC,WAAO;AAAA,EACT;AAGA,MACE,OAAO,WAAW,QAAQ,cAC1B,OAAO,WAAW,IAAI,MAAM,aAC5B;AACA,WAAO;AAAA,EACT;AAGA,MAAI,OAAO,WAAW,QAAQ,eAAe,WAAW,SAAS,MAAM;AACrE,WAAO;AAAA,EACT;AAEA,MAAI,OAAO,WAAW,QAAQ,eAAe,CAAC,WAAW,cAAc;AACrE,YAAQ;AAAA,MACN,mDAAmD;AAAA,IACrD;AACA,WAAO;AAAA,EACT;AAEA,SAAO;AACT","sourcesContent":["/**\n * Returns a boolean indicating whether the given global property\n * is defined and is configurable.\n */\nexport function hasConfigurableGlobal(propertyName: string): boolean {\n const descriptor = Object.getOwnPropertyDescriptor(globalThis, propertyName)\n\n // The property is not set at all.\n if (typeof descriptor === 'undefined') {\n return false\n }\n\n // The property is set to a getter that returns undefined.\n if (\n typeof descriptor.get === 'function' &&\n typeof descriptor.get() === 'undefined'\n ) {\n return false\n }\n\n // The property is set to a value equal to undefined.\n if (typeof descriptor.get === 'undefined' && descriptor.value == null) {\n return false\n }\n\n if (typeof descriptor.set === 'undefined' && !descriptor.configurable) {\n console.error(\n `[MSW] Failed to apply interceptor: the global \\`${propertyName}\\` property is non-configurable. This is likely an issue with your environment. If you are using a framework, please open an issue about this in their repository.`\n )\n return false\n }\n\n return true\n}\n"]} \ No newline at end of file diff --git a/node_modules/@mswjs/interceptors/lib/browser/chunk-QED3Q6Z2.mjs b/node_modules/@mswjs/interceptors/lib/browser/chunk-QED3Q6Z2.mjs new file mode 100644 index 0000000000000000000000000000000000000000..f71287cc2bb3c1a2b3e2e33bd976835de3dfeea0 --- /dev/null +++ b/node_modules/@mswjs/interceptors/lib/browser/chunk-QED3Q6Z2.mjs @@ -0,0 +1,169 @@ +// src/Interceptor.ts +import { Logger } from "@open-draft/logger"; +import { Emitter } from "strict-event-emitter"; +var INTERNAL_REQUEST_ID_HEADER_NAME = "x-interceptors-internal-request-id"; +function getGlobalSymbol(symbol) { + return ( + // @ts-ignore https://github.com/Microsoft/TypeScript/issues/24587 + globalThis[symbol] || void 0 + ); +} +function setGlobalSymbol(symbol, value) { + globalThis[symbol] = value; +} +function deleteGlobalSymbol(symbol) { + delete globalThis[symbol]; +} +var InterceptorReadyState = /* @__PURE__ */ ((InterceptorReadyState2) => { + InterceptorReadyState2["INACTIVE"] = "INACTIVE"; + InterceptorReadyState2["APPLYING"] = "APPLYING"; + InterceptorReadyState2["APPLIED"] = "APPLIED"; + InterceptorReadyState2["DISPOSING"] = "DISPOSING"; + InterceptorReadyState2["DISPOSED"] = "DISPOSED"; + return InterceptorReadyState2; +})(InterceptorReadyState || {}); +var Interceptor = class { + constructor(symbol) { + this.symbol = symbol; + this.readyState = "INACTIVE" /* INACTIVE */; + this.emitter = new Emitter(); + this.subscriptions = []; + this.logger = new Logger(symbol.description); + this.emitter.setMaxListeners(0); + this.logger.info("constructing the interceptor..."); + } + /** + * Determine if this interceptor can be applied + * in the current environment. + */ + checkEnvironment() { + return true; + } + /** + * Apply this interceptor to the current process. + * Returns an already running interceptor instance if it's present. + */ + apply() { + const logger = this.logger.extend("apply"); + logger.info("applying the interceptor..."); + if (this.readyState === "APPLIED" /* APPLIED */) { + logger.info("intercepted already applied!"); + return; + } + const shouldApply = this.checkEnvironment(); + if (!shouldApply) { + logger.info("the interceptor cannot be applied in this environment!"); + return; + } + this.readyState = "APPLYING" /* APPLYING */; + const runningInstance = this.getInstance(); + if (runningInstance) { + logger.info("found a running instance, reusing..."); + this.on = (event, listener) => { + logger.info('proxying the "%s" listener', event); + runningInstance.emitter.addListener(event, listener); + this.subscriptions.push(() => { + runningInstance.emitter.removeListener(event, listener); + logger.info('removed proxied "%s" listener!', event); + }); + return this; + }; + this.readyState = "APPLIED" /* APPLIED */; + return; + } + logger.info("no running instance found, setting up a new instance..."); + this.setup(); + this.setInstance(); + this.readyState = "APPLIED" /* APPLIED */; + } + /** + * Setup the module augments and stubs necessary for this interceptor. + * This method is not run if there's a running interceptor instance + * to prevent instantiating an interceptor multiple times. + */ + setup() { + } + /** + * Listen to the interceptor's public events. + */ + on(event, listener) { + const logger = this.logger.extend("on"); + if (this.readyState === "DISPOSING" /* DISPOSING */ || this.readyState === "DISPOSED" /* DISPOSED */) { + logger.info("cannot listen to events, already disposed!"); + return this; + } + logger.info('adding "%s" event listener:', event, listener); + this.emitter.on(event, listener); + return this; + } + once(event, listener) { + this.emitter.once(event, listener); + return this; + } + off(event, listener) { + this.emitter.off(event, listener); + return this; + } + removeAllListeners(event) { + this.emitter.removeAllListeners(event); + return this; + } + /** + * Disposes of any side-effects this interceptor has introduced. + */ + dispose() { + const logger = this.logger.extend("dispose"); + if (this.readyState === "DISPOSED" /* DISPOSED */) { + logger.info("cannot dispose, already disposed!"); + return; + } + logger.info("disposing the interceptor..."); + this.readyState = "DISPOSING" /* DISPOSING */; + if (!this.getInstance()) { + logger.info("no interceptors running, skipping dispose..."); + return; + } + this.clearInstance(); + logger.info("global symbol deleted:", getGlobalSymbol(this.symbol)); + if (this.subscriptions.length > 0) { + logger.info("disposing of %d subscriptions...", this.subscriptions.length); + for (const dispose of this.subscriptions) { + dispose(); + } + this.subscriptions = []; + logger.info("disposed of all subscriptions!", this.subscriptions.length); + } + this.emitter.removeAllListeners(); + logger.info("destroyed the listener!"); + this.readyState = "DISPOSED" /* DISPOSED */; + } + getInstance() { + var _a; + const instance = getGlobalSymbol(this.symbol); + this.logger.info("retrieved global instance:", (_a = instance == null ? void 0 : instance.constructor) == null ? void 0 : _a.name); + return instance; + } + setInstance() { + setGlobalSymbol(this.symbol, this); + this.logger.info("set global instance!", this.symbol.description); + } + clearInstance() { + deleteGlobalSymbol(this.symbol); + this.logger.info("cleared global instance!", this.symbol.description); + } +}; + +// src/createRequestId.ts +function createRequestId() { + return Math.random().toString(16).slice(2); +} + +export { + INTERNAL_REQUEST_ID_HEADER_NAME, + getGlobalSymbol, + deleteGlobalSymbol, + InterceptorReadyState, + Interceptor, + createRequestId +}; +//# sourceMappingURL=chunk-QED3Q6Z2.mjs.map \ No newline at end of file diff --git a/node_modules/@mswjs/interceptors/lib/browser/chunk-QED3Q6Z2.mjs.map b/node_modules/@mswjs/interceptors/lib/browser/chunk-QED3Q6Z2.mjs.map new file mode 100644 index 0000000000000000000000000000000000000000..1225c8315c0c1bf92027275ccc242fff6276743e --- /dev/null +++ b/node_modules/@mswjs/interceptors/lib/browser/chunk-QED3Q6Z2.mjs.map @@ -0,0 +1 @@ +{"version":3,"sources":["../../src/Interceptor.ts","../../src/createRequestId.ts"],"sourcesContent":["import { Logger } from '@open-draft/logger'\nimport { Emitter, Listener } from 'strict-event-emitter'\n\nexport type InterceptorEventMap = Record\nexport type InterceptorSubscription = () => void\n\n/**\n * Request header name to detect when a single request\n * is being handled by nested interceptors (XHR -> ClientRequest).\n * Obscure by design to prevent collisions with user-defined headers.\n * Ideally, come up with the Interceptor-level mechanism for this.\n * @see https://github.com/mswjs/interceptors/issues/378\n */\nexport const INTERNAL_REQUEST_ID_HEADER_NAME =\n 'x-interceptors-internal-request-id'\n\nexport function getGlobalSymbol(symbol: Symbol): V | undefined {\n return (\n // @ts-ignore https://github.com/Microsoft/TypeScript/issues/24587\n globalThis[symbol] || undefined\n )\n}\n\nfunction setGlobalSymbol(symbol: Symbol, value: any): void {\n // @ts-ignore\n globalThis[symbol] = value\n}\n\nexport function deleteGlobalSymbol(symbol: Symbol): void {\n // @ts-ignore\n delete globalThis[symbol]\n}\n\nexport enum InterceptorReadyState {\n INACTIVE = 'INACTIVE',\n APPLYING = 'APPLYING',\n APPLIED = 'APPLIED',\n DISPOSING = 'DISPOSING',\n DISPOSED = 'DISPOSED',\n}\n\nexport type ExtractEventNames> =\n Events extends Record ? EventName : never\n\nexport class Interceptor {\n protected emitter: Emitter\n protected subscriptions: Array\n protected logger: Logger\n\n public readyState: InterceptorReadyState\n\n constructor(private readonly symbol: symbol) {\n this.readyState = InterceptorReadyState.INACTIVE\n\n this.emitter = new Emitter()\n this.subscriptions = []\n this.logger = new Logger(symbol.description!)\n\n // Do not limit the maximum number of listeners\n // so not to limit the maximum amount of parallel events emitted.\n this.emitter.setMaxListeners(0)\n\n this.logger.info('constructing the interceptor...')\n }\n\n /**\n * Determine if this interceptor can be applied\n * in the current environment.\n */\n protected checkEnvironment(): boolean {\n return true\n }\n\n /**\n * Apply this interceptor to the current process.\n * Returns an already running interceptor instance if it's present.\n */\n public apply(): void {\n const logger = this.logger.extend('apply')\n logger.info('applying the interceptor...')\n\n if (this.readyState === InterceptorReadyState.APPLIED) {\n logger.info('intercepted already applied!')\n return\n }\n\n const shouldApply = this.checkEnvironment()\n\n if (!shouldApply) {\n logger.info('the interceptor cannot be applied in this environment!')\n return\n }\n\n this.readyState = InterceptorReadyState.APPLYING\n\n // Whenever applying a new interceptor, check if it hasn't been applied already.\n // This enables to apply the same interceptor multiple times, for example from a different\n // interceptor, only proxying events but keeping the stubs in a single place.\n const runningInstance = this.getInstance()\n\n if (runningInstance) {\n logger.info('found a running instance, reusing...')\n\n // Proxy any listeners you set on this instance to the running instance.\n this.on = (event, listener) => {\n logger.info('proxying the \"%s\" listener', event)\n\n // Add listeners to the running instance so they appear\n // at the top of the event listeners list and are executed first.\n runningInstance.emitter.addListener(event, listener)\n\n // Ensure that once this interceptor instance is disposed,\n // it removes all listeners it has appended to the running interceptor instance.\n this.subscriptions.push(() => {\n runningInstance.emitter.removeListener(event, listener)\n logger.info('removed proxied \"%s\" listener!', event)\n })\n\n return this\n }\n\n this.readyState = InterceptorReadyState.APPLIED\n\n return\n }\n\n logger.info('no running instance found, setting up a new instance...')\n\n // Setup the interceptor.\n this.setup()\n\n // Store the newly applied interceptor instance globally.\n this.setInstance()\n\n this.readyState = InterceptorReadyState.APPLIED\n }\n\n /**\n * Setup the module augments and stubs necessary for this interceptor.\n * This method is not run if there's a running interceptor instance\n * to prevent instantiating an interceptor multiple times.\n */\n protected setup(): void {}\n\n /**\n * Listen to the interceptor's public events.\n */\n public on>(\n event: EventName,\n listener: Listener\n ): this {\n const logger = this.logger.extend('on')\n\n if (\n this.readyState === InterceptorReadyState.DISPOSING ||\n this.readyState === InterceptorReadyState.DISPOSED\n ) {\n logger.info('cannot listen to events, already disposed!')\n return this\n }\n\n logger.info('adding \"%s\" event listener:', event, listener)\n\n this.emitter.on(event, listener)\n return this\n }\n\n public once>(\n event: EventName,\n listener: Listener\n ): this {\n this.emitter.once(event, listener)\n return this\n }\n\n public off>(\n event: EventName,\n listener: Listener\n ): this {\n this.emitter.off(event, listener)\n return this\n }\n\n public removeAllListeners>(\n event?: EventName\n ): this {\n this.emitter.removeAllListeners(event)\n return this\n }\n\n /**\n * Disposes of any side-effects this interceptor has introduced.\n */\n public dispose(): void {\n const logger = this.logger.extend('dispose')\n\n if (this.readyState === InterceptorReadyState.DISPOSED) {\n logger.info('cannot dispose, already disposed!')\n return\n }\n\n logger.info('disposing the interceptor...')\n this.readyState = InterceptorReadyState.DISPOSING\n\n if (!this.getInstance()) {\n logger.info('no interceptors running, skipping dispose...')\n return\n }\n\n // Delete the global symbol as soon as possible,\n // indicating that the interceptor is no longer running.\n this.clearInstance()\n\n logger.info('global symbol deleted:', getGlobalSymbol(this.symbol))\n\n if (this.subscriptions.length > 0) {\n logger.info('disposing of %d subscriptions...', this.subscriptions.length)\n\n for (const dispose of this.subscriptions) {\n dispose()\n }\n\n this.subscriptions = []\n\n logger.info('disposed of all subscriptions!', this.subscriptions.length)\n }\n\n this.emitter.removeAllListeners()\n logger.info('destroyed the listener!')\n\n this.readyState = InterceptorReadyState.DISPOSED\n }\n\n private getInstance(): this | undefined {\n const instance = getGlobalSymbol(this.symbol)\n this.logger.info('retrieved global instance:', instance?.constructor?.name)\n return instance\n }\n\n private setInstance(): void {\n setGlobalSymbol(this.symbol, this)\n this.logger.info('set global instance!', this.symbol.description)\n }\n\n private clearInstance(): void {\n deleteGlobalSymbol(this.symbol)\n this.logger.info('cleared global instance!', this.symbol.description)\n }\n}\n","/**\n * Generate a random ID string to represent a request.\n * @example\n * createRequestId()\n * // \"f774b6c9c600f\"\n */\nexport function createRequestId(): string {\n return Math.random().toString(16).slice(2)\n}\n"],"mappings":"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","names":["InterceptorReadyState"]} \ No newline at end of file diff --git a/node_modules/@mswjs/interceptors/lib/browser/chunk-QVOTKFTB.js b/node_modules/@mswjs/interceptors/lib/browser/chunk-QVOTKFTB.js new file mode 100644 index 0000000000000000000000000000000000000000..a9677a67efe12b34a6966f6f9e8fe58b0e0428b5 --- /dev/null +++ b/node_modules/@mswjs/interceptors/lib/browser/chunk-QVOTKFTB.js @@ -0,0 +1,295 @@ +"use strict";Object.defineProperty(exports, "__esModule", {value: true}); + + + +var _chunkFGSEOIC4js = require('./chunk-FGSEOIC4.js'); + + + +var _chunkBC2BLJQNjs = require('./chunk-BC2BLJQN.js'); + + +var _chunkPFGO5BSMjs = require('./chunk-PFGO5BSM.js'); + + + +var _chunkTIPR373Rjs = require('./chunk-TIPR373R.js'); + +// src/interceptors/fetch/index.ts +var _outvariant = require('outvariant'); +var _deferredpromise = require('@open-draft/deferred-promise'); + +// src/utils/canParseUrl.ts +function canParseUrl(url) { + try { + new URL(url); + return true; + } catch (_error) { + return false; + } +} + +// src/interceptors/fetch/utils/createNetworkError.ts +function createNetworkError(cause) { + return Object.assign(new TypeError("Failed to fetch"), { + cause + }); +} + +// src/interceptors/fetch/utils/followRedirect.ts +var REQUEST_BODY_HEADERS = [ + "content-encoding", + "content-language", + "content-location", + "content-type", + "content-length" +]; +var kRedirectCount = Symbol("kRedirectCount"); +async function followFetchRedirect(request, response) { + if (response.status !== 303 && request.body != null) { + return Promise.reject(createNetworkError()); + } + const requestUrl = new URL(request.url); + let locationUrl; + try { + locationUrl = new URL(response.headers.get("location"), request.url); + } catch (error) { + return Promise.reject(createNetworkError(error)); + } + if (!(locationUrl.protocol === "http:" || locationUrl.protocol === "https:")) { + return Promise.reject( + createNetworkError("URL scheme must be a HTTP(S) scheme") + ); + } + if (Reflect.get(request, kRedirectCount) > 20) { + return Promise.reject(createNetworkError("redirect count exceeded")); + } + Object.defineProperty(request, kRedirectCount, { + value: (Reflect.get(request, kRedirectCount) || 0) + 1 + }); + if (request.mode === "cors" && (locationUrl.username || locationUrl.password) && !sameOrigin(requestUrl, locationUrl)) { + return Promise.reject( + createNetworkError('cross origin not allowed for request mode "cors"') + ); + } + const requestInit = {}; + if ([301, 302].includes(response.status) && request.method === "POST" || response.status === 303 && !["HEAD", "GET"].includes(request.method)) { + requestInit.method = "GET"; + requestInit.body = null; + REQUEST_BODY_HEADERS.forEach((headerName) => { + request.headers.delete(headerName); + }); + } + if (!sameOrigin(requestUrl, locationUrl)) { + request.headers.delete("authorization"); + request.headers.delete("proxy-authorization"); + request.headers.delete("cookie"); + request.headers.delete("host"); + } + requestInit.headers = request.headers; + return fetch(new Request(locationUrl, requestInit)); +} +function sameOrigin(left, right) { + if (left.origin === right.origin && left.origin === "null") { + return true; + } + if (left.protocol === right.protocol && left.hostname === right.hostname && left.port === right.port) { + return true; + } + return false; +} + +// src/interceptors/fetch/utils/brotli-decompress.browser.ts +var BrotliDecompressionStream = class extends TransformStream { + constructor() { + console.warn( + "[Interceptors]: Brotli decompression of response streams is not supported in the browser" + ); + super({ + transform(chunk, controller) { + controller.enqueue(chunk); + } + }); + } +}; + +// src/interceptors/fetch/utils/decompression.ts +var PipelineStream = class extends TransformStream { + constructor(transformStreams, ...strategies) { + super({}, ...strategies); + const readable = [super.readable, ...transformStreams].reduce( + (readable2, transform) => readable2.pipeThrough(transform) + ); + Object.defineProperty(this, "readable", { + get() { + return readable; + } + }); + } +}; +function parseContentEncoding(contentEncoding) { + return contentEncoding.toLowerCase().split(",").map((coding) => coding.trim()); +} +function createDecompressionStream(contentEncoding) { + if (contentEncoding === "") { + return null; + } + const codings = parseContentEncoding(contentEncoding); + if (codings.length === 0) { + return null; + } + const transformers = codings.reduceRight( + (transformers2, coding) => { + if (coding === "gzip" || coding === "x-gzip") { + return transformers2.concat(new DecompressionStream("gzip")); + } else if (coding === "deflate") { + return transformers2.concat(new DecompressionStream("deflate")); + } else if (coding === "br") { + return transformers2.concat(new BrotliDecompressionStream()); + } else { + transformers2.length = 0; + } + return transformers2; + }, + [] + ); + return new PipelineStream(transformers); +} +function decompressResponse(response) { + if (response.body === null) { + return null; + } + const decompressionStream = createDecompressionStream( + response.headers.get("content-encoding") || "" + ); + if (!decompressionStream) { + return null; + } + response.body.pipeTo(decompressionStream.writable); + return decompressionStream.readable; +} + +// src/interceptors/fetch/index.ts +var _FetchInterceptor = class extends _chunkTIPR373Rjs.Interceptor { + constructor() { + super(_FetchInterceptor.symbol); + } + checkEnvironment() { + return _chunkPFGO5BSMjs.hasConfigurableGlobal.call(void 0, "fetch"); + } + async setup() { + const pureFetch = globalThis.fetch; + _outvariant.invariant.call(void 0, + !pureFetch[_chunkBC2BLJQNjs.IS_PATCHED_MODULE], + 'Failed to patch the "fetch" module: already patched.' + ); + globalThis.fetch = async (input, init) => { + const requestId = _chunkTIPR373Rjs.createRequestId.call(void 0, ); + const resolvedInput = typeof input === "string" && typeof location !== "undefined" && !canParseUrl(input) ? new URL(input, location.origin) : input; + const request = new Request(resolvedInput, init); + const responsePromise = new (0, _deferredpromise.DeferredPromise)(); + const controller = new (0, _chunkFGSEOIC4js.RequestController)(request); + this.logger.info("[%s] %s", request.method, request.url); + this.logger.info("awaiting for the mocked response..."); + this.logger.info( + 'emitting the "request" event for %s listener(s)...', + this.emitter.listenerCount("request") + ); + const isRequestHandled = await _chunkFGSEOIC4js.handleRequest.call(void 0, { + request, + requestId, + emitter: this.emitter, + controller, + onResponse: async (rawResponse) => { + this.logger.info("received mocked response!", { + rawResponse + }); + const decompressedStream = decompressResponse(rawResponse); + const response = decompressedStream === null ? rawResponse : new (0, _chunkBC2BLJQNjs.FetchResponse)(decompressedStream, rawResponse); + _chunkBC2BLJQNjs.FetchResponse.setUrl(request.url, response); + if (_chunkBC2BLJQNjs.FetchResponse.isRedirectResponse(response.status)) { + if (request.redirect === "error") { + responsePromise.reject(createNetworkError("unexpected redirect")); + return; + } + if (request.redirect === "follow") { + followFetchRedirect(request, response).then( + (response2) => { + responsePromise.resolve(response2); + }, + (reason) => { + responsePromise.reject(reason); + } + ); + return; + } + } + if (this.emitter.listenerCount("response") > 0) { + this.logger.info('emitting the "response" event...'); + await _chunkFGSEOIC4js.emitAsync.call(void 0, this.emitter, "response", { + // Clone the mocked response for the "response" event listener. + // This way, the listener can read the response and not lock its body + // for the actual fetch consumer. + response: response.clone(), + isMockedResponse: true, + request, + requestId + }); + } + responsePromise.resolve(response); + }, + onRequestError: (response) => { + this.logger.info("request has errored!", { response }); + responsePromise.reject(createNetworkError(response)); + }, + onError: (error) => { + this.logger.info("request has been aborted!", { error }); + responsePromise.reject(error); + } + }); + if (isRequestHandled) { + this.logger.info("request has been handled, returning mock promise..."); + return responsePromise; + } + this.logger.info( + "no mocked response received, performing request as-is..." + ); + return pureFetch(request).then(async (response) => { + this.logger.info("original fetch performed", response); + if (this.emitter.listenerCount("response") > 0) { + this.logger.info('emitting the "response" event...'); + const responseClone = response.clone(); + await _chunkFGSEOIC4js.emitAsync.call(void 0, this.emitter, "response", { + response: responseClone, + isMockedResponse: false, + request, + requestId + }); + } + return response; + }); + }; + Object.defineProperty(globalThis.fetch, _chunkBC2BLJQNjs.IS_PATCHED_MODULE, { + enumerable: true, + configurable: true, + value: true + }); + this.subscriptions.push(() => { + Object.defineProperty(globalThis.fetch, _chunkBC2BLJQNjs.IS_PATCHED_MODULE, { + value: void 0 + }); + globalThis.fetch = pureFetch; + this.logger.info( + 'restored native "globalThis.fetch"!', + globalThis.fetch.name + ); + }); + } +}; +var FetchInterceptor = _FetchInterceptor; +FetchInterceptor.symbol = Symbol("fetch"); + + + +exports.FetchInterceptor = FetchInterceptor; +//# sourceMappingURL=chunk-QVOTKFTB.js.map \ No newline at end of file diff --git a/node_modules/@mswjs/interceptors/lib/browser/chunk-QVOTKFTB.js.map b/node_modules/@mswjs/interceptors/lib/browser/chunk-QVOTKFTB.js.map new file mode 100644 index 0000000000000000000000000000000000000000..07453e36c130c076ef276dbfb0ce08657ac0cc5d --- /dev/null +++ b/node_modules/@mswjs/interceptors/lib/browser/chunk-QVOTKFTB.js.map @@ -0,0 +1 @@ +{"version":3,"sources":["../../src/interceptors/fetch/index.ts","../../src/utils/canParseUrl.ts","../../src/interceptors/fetch/utils/createNetworkError.ts","../../src/interceptors/fetch/utils/followRedirect.ts","../../src/interceptors/fetch/utils/brotli-decompress.browser.ts","../../src/interceptors/fetch/utils/decompression.ts"],"names":["readable","transformers","response"],"mappings":";;;;;;;;;;;;;;;;;;AAAA,SAAS,iBAAiB;AAC1B,SAAS,uBAAuB;;;ACIzB,SAAS,YAAY,KAAsB;AAChD,MAAI;AACF,QAAI,IAAI,GAAG;AACX,WAAO;AAAA,EACT,SAAS,QAAP;AACA,WAAO;AAAA,EACT;AACF;;;ACZO,SAAS,mBAAmB,OAAiB;AAClD,SAAO,OAAO,OAAO,IAAI,UAAU,iBAAiB,GAAG;AAAA,IACrD;AAAA,EACF,CAAC;AACH;;;ACFA,IAAM,uBAAuB;AAAA,EAC3B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAEA,IAAM,iBAAiB,OAAO,gBAAgB;AAK9C,eAAsB,oBACpB,SACA,UACmB;AACnB,MAAI,SAAS,WAAW,OAAO,QAAQ,QAAQ,MAAM;AACnD,WAAO,QAAQ,OAAO,mBAAmB,CAAC;AAAA,EAC5C;AAEA,QAAM,aAAa,IAAI,IAAI,QAAQ,GAAG;AAEtC,MAAI;AACJ,MAAI;AAEF,kBAAc,IAAI,IAAI,SAAS,QAAQ,IAAI,UAAU,GAAI,QAAQ,GAAG;AAAA,EACtE,SAAS,OAAP;AACA,WAAO,QAAQ,OAAO,mBAAmB,KAAK,CAAC;AAAA,EACjD;AAEA,MACE,EAAE,YAAY,aAAa,WAAW,YAAY,aAAa,WAC/D;AACA,WAAO,QAAQ;AAAA,MACb,mBAAmB,qCAAqC;AAAA,IAC1D;AAAA,EACF;AAEA,MAAI,QAAQ,IAAI,SAAS,cAAc,IAAI,IAAI;AAC7C,WAAO,QAAQ,OAAO,mBAAmB,yBAAyB,CAAC;AAAA,EACrE;AAEA,SAAO,eAAe,SAAS,gBAAgB;AAAA,IAC7C,QAAQ,QAAQ,IAAI,SAAS,cAAc,KAAK,KAAK;AAAA,EACvD,CAAC;AAED,MACE,QAAQ,SAAS,WAChB,YAAY,YAAY,YAAY,aACrC,CAAC,WAAW,YAAY,WAAW,GACnC;AACA,WAAO,QAAQ;AAAA,MACb,mBAAmB,kDAAkD;AAAA,IACvE;AAAA,EACF;AAEA,QAAM,cAA2B,CAAC;AAElC,MACG,CAAC,KAAK,GAAG,EAAE,SAAS,SAAS,MAAM,KAAK,QAAQ,WAAW,UAC3D,SAAS,WAAW,OAAO,CAAC,CAAC,QAAQ,KAAK,EAAE,SAAS,QAAQ,MAAM,GACpE;AACA,gBAAY,SAAS;AACrB,gBAAY,OAAO;AAEnB,yBAAqB,QAAQ,CAAC,eAAe;AAC3C,cAAQ,QAAQ,OAAO,UAAU;AAAA,IACnC,CAAC;AAAA,EACH;AAEA,MAAI,CAAC,WAAW,YAAY,WAAW,GAAG;AACxC,YAAQ,QAAQ,OAAO,eAAe;AACtC,YAAQ,QAAQ,OAAO,qBAAqB;AAC5C,YAAQ,QAAQ,OAAO,QAAQ;AAC/B,YAAQ,QAAQ,OAAO,MAAM;AAAA,EAC/B;AAQA,cAAY,UAAU,QAAQ;AAC9B,SAAO,MAAM,IAAI,QAAQ,aAAa,WAAW,CAAC;AACpD;AAKA,SAAS,WAAW,MAAW,OAAqB;AAClD,MAAI,KAAK,WAAW,MAAM,UAAU,KAAK,WAAW,QAAQ;AAC1D,WAAO;AAAA,EACT;AAEA,MACE,KAAK,aAAa,MAAM,YACxB,KAAK,aAAa,MAAM,YACxB,KAAK,SAAS,MAAM,MACpB;AACA,WAAO;AAAA,EACT;AAEA,SAAO;AACT;;;AC3GO,IAAM,4BAAN,cAAwC,gBAAgB;AAAA,EAC7D,cAAc;AACZ,YAAQ;AAAA,MACN;AAAA,IACF;AAEA,UAAM;AAAA,MACJ,UAAU,OAAO,YAAY;AAE3B,mBAAW,QAAQ,KAAK;AAAA,MAC1B;AAAA,IACF,CAAC;AAAA,EACH;AACF;;;ACRA,IAAM,iBAAN,cAA6B,gBAAgB;AAAA,EAC3C,YACE,qBACG,YACH;AACA,UAAM,CAAC,GAAG,GAAG,UAAU;AAEvB,UAAM,WAAW,CAAC,MAAM,UAAiB,GAAG,gBAAgB,EAAE;AAAA,MAC5D,CAACA,WAAU,cAAcA,UAAS,YAAY,SAAS;AAAA,IACzD;AAEA,WAAO,eAAe,MAAM,YAAY;AAAA,MACtC,MAAM;AACJ,eAAO;AAAA,MACT;AAAA,IACF,CAAC;AAAA,EACH;AACF;AAEO,SAAS,qBAAqB,iBAAwC;AAC3E,SAAO,gBACJ,YAAY,EACZ,MAAM,GAAG,EACT,IAAI,CAAC,WAAW,OAAO,KAAK,CAAC;AAClC;AAEA,SAAS,0BACP,iBACwB;AACxB,MAAI,oBAAoB,IAAI;AAC1B,WAAO;AAAA,EACT;AAEA,QAAM,UAAU,qBAAqB,eAAe;AAEpD,MAAI,QAAQ,WAAW,GAAG;AACxB,WAAO;AAAA,EACT;AAEA,QAAM,eAAe,QAAQ;AAAA,IAC3B,CAACC,eAAc,WAAW;AACxB,UAAI,WAAW,UAAU,WAAW,UAAU;AAC5C,eAAOA,cAAa,OAAO,IAAI,oBAAoB,MAAM,CAAC;AAAA,MAC5D,WAAW,WAAW,WAAW;AAC/B,eAAOA,cAAa,OAAO,IAAI,oBAAoB,SAAS,CAAC;AAAA,MAC/D,WAAW,WAAW,MAAM;AAC1B,eAAOA,cAAa,OAAO,IAAI,0BAA0B,CAAC;AAAA,MAC5D,OAAO;AACL,QAAAA,cAAa,SAAS;AAAA,MACxB;AAEA,aAAOA;AAAA,IACT;AAAA,IACA,CAAC;AAAA,EACH;AAEA,SAAO,IAAI,eAAe,YAAY;AACxC;AAEO,SAAS,mBACd,UAC4B;AAC5B,MAAI,SAAS,SAAS,MAAM;AAC1B,WAAO;AAAA,EACT;AAEA,QAAM,sBAAsB;AAAA,IAC1B,SAAS,QAAQ,IAAI,kBAAkB,KAAK;AAAA,EAC9C;AAEA,MAAI,CAAC,qBAAqB;AACxB,WAAO;AAAA,EACT;AAKA,WAAS,KAAK,OAAO,oBAAoB,QAAQ;AACjD,SAAO,oBAAoB;AAC7B;;;ALrEO,IAAM,oBAAN,cAA+B,YAAiC;AAAA,EAGrE,cAAc;AACZ,UAAM,kBAAiB,MAAM;AAAA,EAC/B;AAAA,EAEU,mBAAmB;AAC3B,WAAO,sBAAsB,OAAO;AAAA,EACtC;AAAA,EAEA,MAAgB,QAAQ;AACtB,UAAM,YAAY,WAAW;AAE7B;AAAA,MACE,CAAE,UAAkB,iBAAiB;AAAA,MACrC;AAAA,IACF;AAEA,eAAW,QAAQ,OAAO,OAAO,SAAS;AACxC,YAAM,YAAY,gBAAgB;AAQlC,YAAM,gBACJ,OAAO,UAAU,YACjB,OAAO,aAAa,eACpB,CAAC,YAAY,KAAK,IACd,IAAI,IAAI,OAAO,SAAS,MAAM,IAC9B;AAEN,YAAM,UAAU,IAAI,QAAQ,eAAe,IAAI;AAC/C,YAAM,kBAAkB,IAAI,gBAA0B;AACtD,YAAM,aAAa,IAAI,kBAAkB,OAAO;AAEhD,WAAK,OAAO,KAAK,WAAW,QAAQ,QAAQ,QAAQ,GAAG;AACvD,WAAK,OAAO,KAAK,qCAAqC;AAEtD,WAAK,OAAO;AAAA,QACV;AAAA,QACA,KAAK,QAAQ,cAAc,SAAS;AAAA,MACtC;AAEA,YAAM,mBAAmB,MAAM,cAAc;AAAA,QAC3C;AAAA,QACA;AAAA,QACA,SAAS,KAAK;AAAA,QACd;AAAA,QACA,YAAY,OAAO,gBAAgB;AACjC,eAAK,OAAO,KAAK,6BAA6B;AAAA,YAC5C;AAAA,UACF,CAAC;AAGD,gBAAM,qBAAqB,mBAAmB,WAAW;AACzD,gBAAM,WACJ,uBAAuB,OACnB,cACA,IAAI,cAAc,oBAAoB,WAAW;AAEvD,wBAAc,OAAO,QAAQ,KAAK,QAAQ;AAQ1C,cAAI,cAAc,mBAAmB,SAAS,MAAM,GAAG;AAGrD,gBAAI,QAAQ,aAAa,SAAS;AAChC,8BAAgB,OAAO,mBAAmB,qBAAqB,CAAC;AAChE;AAAA,YACF;AAEA,gBAAI,QAAQ,aAAa,UAAU;AACjC,kCAAoB,SAAS,QAAQ,EAAE;AAAA,gBACrC,CAACC,cAAa;AACZ,kCAAgB,QAAQA,SAAQ;AAAA,gBAClC;AAAA,gBACA,CAAC,WAAW;AACV,kCAAgB,OAAO,MAAM;AAAA,gBAC/B;AAAA,cACF;AACA;AAAA,YACF;AAAA,UACF;AAEA,cAAI,KAAK,QAAQ,cAAc,UAAU,IAAI,GAAG;AAC9C,iBAAK,OAAO,KAAK,kCAAkC;AAKnD,kBAAM,UAAU,KAAK,SAAS,YAAY;AAAA;AAAA;AAAA;AAAA,cAIxC,UAAU,SAAS,MAAM;AAAA,cACzB,kBAAkB;AAAA,cAClB;AAAA,cACA;AAAA,YACF,CAAC;AAAA,UACH;AAEA,0BAAgB,QAAQ,QAAQ;AAAA,QAClC;AAAA,QACA,gBAAgB,CAAC,aAAa;AAC5B,eAAK,OAAO,KAAK,wBAAwB,EAAE,SAAS,CAAC;AACrD,0BAAgB,OAAO,mBAAmB,QAAQ,CAAC;AAAA,QACrD;AAAA,QACA,SAAS,CAAC,UAAU;AAClB,eAAK,OAAO,KAAK,6BAA6B,EAAE,MAAM,CAAC;AACvD,0BAAgB,OAAO,KAAK;AAAA,QAC9B;AAAA,MACF,CAAC;AAED,UAAI,kBAAkB;AACpB,aAAK,OAAO,KAAK,qDAAqD;AACtE,eAAO;AAAA,MACT;AAEA,WAAK,OAAO;AAAA,QACV;AAAA,MACF;AAEA,aAAO,UAAU,OAAO,EAAE,KAAK,OAAO,aAAa;AACjD,aAAK,OAAO,KAAK,4BAA4B,QAAQ;AAErD,YAAI,KAAK,QAAQ,cAAc,UAAU,IAAI,GAAG;AAC9C,eAAK,OAAO,KAAK,kCAAkC;AAEnD,gBAAM,gBAAgB,SAAS,MAAM;AAErC,gBAAM,UAAU,KAAK,SAAS,YAAY;AAAA,YACxC,UAAU;AAAA,YACV,kBAAkB;AAAA,YAClB;AAAA,YACA;AAAA,UACF,CAAC;AAAA,QACH;AAEA,eAAO;AAAA,MACT,CAAC;AAAA,IACH;AAEA,WAAO,eAAe,WAAW,OAAO,mBAAmB;AAAA,MACzD,YAAY;AAAA,MACZ,cAAc;AAAA,MACd,OAAO;AAAA,IACT,CAAC;AAED,SAAK,cAAc,KAAK,MAAM;AAC5B,aAAO,eAAe,WAAW,OAAO,mBAAmB;AAAA,QACzD,OAAO;AAAA,MACT,CAAC;AAED,iBAAW,QAAQ;AAEnB,WAAK,OAAO;AAAA,QACV;AAAA,QACA,WAAW,MAAM;AAAA,MACnB;AAAA,IACF,CAAC;AAAA,EACH;AACF;AA1KO,IAAM,mBAAN;AAAM,iBACJ,SAAS,OAAO,OAAO","sourcesContent":["import { invariant } from 'outvariant'\nimport { DeferredPromise } from '@open-draft/deferred-promise'\nimport { HttpRequestEventMap, IS_PATCHED_MODULE } from '../../glossary'\nimport { Interceptor } from '../../Interceptor'\nimport { RequestController } from '../../RequestController'\nimport { emitAsync } from '../../utils/emitAsync'\nimport { handleRequest } from '../../utils/handleRequest'\nimport { canParseUrl } from '../../utils/canParseUrl'\nimport { createRequestId } from '../../createRequestId'\nimport { createNetworkError } from './utils/createNetworkError'\nimport { followFetchRedirect } from './utils/followRedirect'\nimport { decompressResponse } from './utils/decompression'\nimport { hasConfigurableGlobal } from '../../utils/hasConfigurableGlobal'\nimport { FetchResponse } from '../../utils/fetchUtils'\n\nexport class FetchInterceptor extends Interceptor {\n static symbol = Symbol('fetch')\n\n constructor() {\n super(FetchInterceptor.symbol)\n }\n\n protected checkEnvironment() {\n return hasConfigurableGlobal('fetch')\n }\n\n protected async setup() {\n const pureFetch = globalThis.fetch\n\n invariant(\n !(pureFetch as any)[IS_PATCHED_MODULE],\n 'Failed to patch the \"fetch\" module: already patched.'\n )\n\n globalThis.fetch = async (input, init) => {\n const requestId = createRequestId()\n\n /**\n * @note Resolve potentially relative request URL\n * against the present `location`. This is mainly\n * for native `fetch` in JSDOM.\n * @see https://github.com/mswjs/msw/issues/1625\n */\n const resolvedInput =\n typeof input === 'string' &&\n typeof location !== 'undefined' &&\n !canParseUrl(input)\n ? new URL(input, location.origin)\n : input\n\n const request = new Request(resolvedInput, init)\n const responsePromise = new DeferredPromise()\n const controller = new RequestController(request)\n\n this.logger.info('[%s] %s', request.method, request.url)\n this.logger.info('awaiting for the mocked response...')\n\n this.logger.info(\n 'emitting the \"request\" event for %s listener(s)...',\n this.emitter.listenerCount('request')\n )\n\n const isRequestHandled = await handleRequest({\n request,\n requestId,\n emitter: this.emitter,\n controller,\n onResponse: async (rawResponse) => {\n this.logger.info('received mocked response!', {\n rawResponse,\n })\n\n // Decompress the mocked response body, if applicable.\n const decompressedStream = decompressResponse(rawResponse)\n const response =\n decompressedStream === null\n ? rawResponse\n : new FetchResponse(decompressedStream, rawResponse)\n\n FetchResponse.setUrl(request.url, response)\n\n /**\n * Undici's handling of following redirect responses.\n * Treat the \"manual\" redirect mode as a regular mocked response.\n * This way, the client can manually follow the redirect it receives.\n * @see https://github.com/nodejs/undici/blob/a6dac3149c505b58d2e6d068b97f4dc993da55f0/lib/web/fetch/index.js#L1173\n */\n if (FetchResponse.isRedirectResponse(response.status)) {\n // Reject the request promise if its `redirect` is set to `error`\n // and it receives a mocked redirect response.\n if (request.redirect === 'error') {\n responsePromise.reject(createNetworkError('unexpected redirect'))\n return\n }\n\n if (request.redirect === 'follow') {\n followFetchRedirect(request, response).then(\n (response) => {\n responsePromise.resolve(response)\n },\n (reason) => {\n responsePromise.reject(reason)\n }\n )\n return\n }\n }\n\n if (this.emitter.listenerCount('response') > 0) {\n this.logger.info('emitting the \"response\" event...')\n\n // Await the response listeners to finish before resolving\n // the response promise. This ensures all your logic finishes\n // before the interceptor resolves the pending response.\n await emitAsync(this.emitter, 'response', {\n // Clone the mocked response for the \"response\" event listener.\n // This way, the listener can read the response and not lock its body\n // for the actual fetch consumer.\n response: response.clone(),\n isMockedResponse: true,\n request,\n requestId,\n })\n }\n\n responsePromise.resolve(response)\n },\n onRequestError: (response) => {\n this.logger.info('request has errored!', { response })\n responsePromise.reject(createNetworkError(response))\n },\n onError: (error) => {\n this.logger.info('request has been aborted!', { error })\n responsePromise.reject(error)\n },\n })\n\n if (isRequestHandled) {\n this.logger.info('request has been handled, returning mock promise...')\n return responsePromise\n }\n\n this.logger.info(\n 'no mocked response received, performing request as-is...'\n )\n\n return pureFetch(request).then(async (response) => {\n this.logger.info('original fetch performed', response)\n\n if (this.emitter.listenerCount('response') > 0) {\n this.logger.info('emitting the \"response\" event...')\n\n const responseClone = response.clone()\n\n await emitAsync(this.emitter, 'response', {\n response: responseClone,\n isMockedResponse: false,\n request,\n requestId,\n })\n }\n\n return response\n })\n }\n\n Object.defineProperty(globalThis.fetch, IS_PATCHED_MODULE, {\n enumerable: true,\n configurable: true,\n value: true,\n })\n\n this.subscriptions.push(() => {\n Object.defineProperty(globalThis.fetch, IS_PATCHED_MODULE, {\n value: undefined,\n })\n\n globalThis.fetch = pureFetch\n\n this.logger.info(\n 'restored native \"globalThis.fetch\"!',\n globalThis.fetch.name\n )\n })\n }\n}\n","/**\n * Returns a boolean indicating whether the given URL string\n * can be parsed into a `URL` instance.\n * A substitute for `URL.canParse()` for Node.js 18.\n */\nexport function canParseUrl(url: string): boolean {\n try {\n new URL(url)\n return true\n } catch (_error) {\n return false\n }\n}\n","export function createNetworkError(cause?: unknown) {\n return Object.assign(new TypeError('Failed to fetch'), {\n cause,\n })\n}\n","import { createNetworkError } from './createNetworkError'\n\nconst REQUEST_BODY_HEADERS = [\n 'content-encoding',\n 'content-language',\n 'content-location',\n 'content-type',\n 'content-length',\n]\n\nconst kRedirectCount = Symbol('kRedirectCount')\n\n/**\n * @see https://github.com/nodejs/undici/blob/a6dac3149c505b58d2e6d068b97f4dc993da55f0/lib/web/fetch/index.js#L1210\n */\nexport async function followFetchRedirect(\n request: Request,\n response: Response\n): Promise {\n if (response.status !== 303 && request.body != null) {\n return Promise.reject(createNetworkError())\n }\n\n const requestUrl = new URL(request.url)\n\n let locationUrl: URL\n try {\n // If the location is a relative URL, use the request URL as the base URL.\n locationUrl = new URL(response.headers.get('location')!, request.url) \n } catch (error) {\n return Promise.reject(createNetworkError(error))\n }\n\n if (\n !(locationUrl.protocol === 'http:' || locationUrl.protocol === 'https:')\n ) {\n return Promise.reject(\n createNetworkError('URL scheme must be a HTTP(S) scheme')\n )\n }\n\n if (Reflect.get(request, kRedirectCount) > 20) {\n return Promise.reject(createNetworkError('redirect count exceeded'))\n }\n\n Object.defineProperty(request, kRedirectCount, {\n value: (Reflect.get(request, kRedirectCount) || 0) + 1,\n })\n\n if (\n request.mode === 'cors' &&\n (locationUrl.username || locationUrl.password) &&\n !sameOrigin(requestUrl, locationUrl)\n ) {\n return Promise.reject(\n createNetworkError('cross origin not allowed for request mode \"cors\"')\n )\n }\n\n const requestInit: RequestInit = {}\n\n if (\n ([301, 302].includes(response.status) && request.method === 'POST') ||\n (response.status === 303 && !['HEAD', 'GET'].includes(request.method))\n ) {\n requestInit.method = 'GET'\n requestInit.body = null\n\n REQUEST_BODY_HEADERS.forEach((headerName) => {\n request.headers.delete(headerName)\n })\n }\n\n if (!sameOrigin(requestUrl, locationUrl)) {\n request.headers.delete('authorization')\n request.headers.delete('proxy-authorization')\n request.headers.delete('cookie')\n request.headers.delete('host')\n }\n\n /**\n * @note Undici \"safely\" extracts the request body.\n * I suspect we cannot dispatch this request again\n * since its body has been read and the stream is locked.\n */\n\n requestInit.headers = request.headers\n return fetch(new Request(locationUrl, requestInit))\n}\n\n/**\n * @see https://github.com/nodejs/undici/blob/a6dac3149c505b58d2e6d068b97f4dc993da55f0/lib/web/fetch/util.js#L761\n */\nfunction sameOrigin(left: URL, right: URL): boolean {\n if (left.origin === right.origin && left.origin === 'null') {\n return true\n }\n\n if (\n left.protocol === right.protocol &&\n left.hostname === right.hostname &&\n left.port === right.port\n ) {\n return true\n }\n\n return false\n}\n","export class BrotliDecompressionStream extends TransformStream {\n constructor() {\n console.warn(\n '[Interceptors]: Brotli decompression of response streams is not supported in the browser'\n )\n\n super({\n transform(chunk, controller) {\n // Keep the stream as passthrough, it does nothing.\n controller.enqueue(chunk)\n },\n })\n }\n}\n","// Import from an internal alias that resolves to different modules\n// depending on the environment. This way, we can keep the fetch interceptor\n// intact while using different strategies for Brotli decompression.\nimport { BrotliDecompressionStream } from 'internal:brotli-decompress'\n\nclass PipelineStream extends TransformStream {\n constructor(\n transformStreams: Array,\n ...strategies: Array\n ) {\n super({}, ...strategies)\n\n const readable = [super.readable as any, ...transformStreams].reduce(\n (readable, transform) => readable.pipeThrough(transform)\n )\n\n Object.defineProperty(this, 'readable', {\n get() {\n return readable\n },\n })\n }\n}\n\nexport function parseContentEncoding(contentEncoding: string): Array {\n return contentEncoding\n .toLowerCase()\n .split(',')\n .map((coding) => coding.trim())\n}\n\nfunction createDecompressionStream(\n contentEncoding: string\n): TransformStream | null {\n if (contentEncoding === '') {\n return null\n }\n\n const codings = parseContentEncoding(contentEncoding)\n\n if (codings.length === 0) {\n return null\n }\n\n const transformers = codings.reduceRight>(\n (transformers, coding) => {\n if (coding === 'gzip' || coding === 'x-gzip') {\n return transformers.concat(new DecompressionStream('gzip'))\n } else if (coding === 'deflate') {\n return transformers.concat(new DecompressionStream('deflate'))\n } else if (coding === 'br') {\n return transformers.concat(new BrotliDecompressionStream())\n } else {\n transformers.length = 0\n }\n\n return transformers\n },\n []\n )\n\n return new PipelineStream(transformers)\n}\n\nexport function decompressResponse(\n response: Response\n): ReadableStream | null {\n if (response.body === null) {\n return null\n }\n\n const decompressionStream = createDecompressionStream(\n response.headers.get('content-encoding') || ''\n )\n\n if (!decompressionStream) {\n return null\n }\n\n // Use `pipeTo` and return the decompression stream's readable\n // instead of `pipeThrough` because that will lock the original\n // response stream, making it unusable as the input to Response.\n response.body.pipeTo(decompressionStream.writable)\n return decompressionStream.readable\n}\n"]} \ No newline at end of file diff --git a/node_modules/@mswjs/interceptors/lib/browser/chunk-TIPR373R.js b/node_modules/@mswjs/interceptors/lib/browser/chunk-TIPR373R.js new file mode 100644 index 0000000000000000000000000000000000000000..17ca97fd87f21f48b53121da520b6ddfe4e0d01c --- /dev/null +++ b/node_modules/@mswjs/interceptors/lib/browser/chunk-TIPR373R.js @@ -0,0 +1,169 @@ +"use strict";Object.defineProperty(exports, "__esModule", {value: true});// src/Interceptor.ts +var _logger = require('@open-draft/logger'); +var _stricteventemitter = require('strict-event-emitter'); +var INTERNAL_REQUEST_ID_HEADER_NAME = "x-interceptors-internal-request-id"; +function getGlobalSymbol(symbol) { + return ( + // @ts-ignore https://github.com/Microsoft/TypeScript/issues/24587 + globalThis[symbol] || void 0 + ); +} +function setGlobalSymbol(symbol, value) { + globalThis[symbol] = value; +} +function deleteGlobalSymbol(symbol) { + delete globalThis[symbol]; +} +var InterceptorReadyState = /* @__PURE__ */ ((InterceptorReadyState2) => { + InterceptorReadyState2["INACTIVE"] = "INACTIVE"; + InterceptorReadyState2["APPLYING"] = "APPLYING"; + InterceptorReadyState2["APPLIED"] = "APPLIED"; + InterceptorReadyState2["DISPOSING"] = "DISPOSING"; + InterceptorReadyState2["DISPOSED"] = "DISPOSED"; + return InterceptorReadyState2; +})(InterceptorReadyState || {}); +var Interceptor = class { + constructor(symbol) { + this.symbol = symbol; + this.readyState = "INACTIVE" /* INACTIVE */; + this.emitter = new (0, _stricteventemitter.Emitter)(); + this.subscriptions = []; + this.logger = new (0, _logger.Logger)(symbol.description); + this.emitter.setMaxListeners(0); + this.logger.info("constructing the interceptor..."); + } + /** + * Determine if this interceptor can be applied + * in the current environment. + */ + checkEnvironment() { + return true; + } + /** + * Apply this interceptor to the current process. + * Returns an already running interceptor instance if it's present. + */ + apply() { + const logger = this.logger.extend("apply"); + logger.info("applying the interceptor..."); + if (this.readyState === "APPLIED" /* APPLIED */) { + logger.info("intercepted already applied!"); + return; + } + const shouldApply = this.checkEnvironment(); + if (!shouldApply) { + logger.info("the interceptor cannot be applied in this environment!"); + return; + } + this.readyState = "APPLYING" /* APPLYING */; + const runningInstance = this.getInstance(); + if (runningInstance) { + logger.info("found a running instance, reusing..."); + this.on = (event, listener) => { + logger.info('proxying the "%s" listener', event); + runningInstance.emitter.addListener(event, listener); + this.subscriptions.push(() => { + runningInstance.emitter.removeListener(event, listener); + logger.info('removed proxied "%s" listener!', event); + }); + return this; + }; + this.readyState = "APPLIED" /* APPLIED */; + return; + } + logger.info("no running instance found, setting up a new instance..."); + this.setup(); + this.setInstance(); + this.readyState = "APPLIED" /* APPLIED */; + } + /** + * Setup the module augments and stubs necessary for this interceptor. + * This method is not run if there's a running interceptor instance + * to prevent instantiating an interceptor multiple times. + */ + setup() { + } + /** + * Listen to the interceptor's public events. + */ + on(event, listener) { + const logger = this.logger.extend("on"); + if (this.readyState === "DISPOSING" /* DISPOSING */ || this.readyState === "DISPOSED" /* DISPOSED */) { + logger.info("cannot listen to events, already disposed!"); + return this; + } + logger.info('adding "%s" event listener:', event, listener); + this.emitter.on(event, listener); + return this; + } + once(event, listener) { + this.emitter.once(event, listener); + return this; + } + off(event, listener) { + this.emitter.off(event, listener); + return this; + } + removeAllListeners(event) { + this.emitter.removeAllListeners(event); + return this; + } + /** + * Disposes of any side-effects this interceptor has introduced. + */ + dispose() { + const logger = this.logger.extend("dispose"); + if (this.readyState === "DISPOSED" /* DISPOSED */) { + logger.info("cannot dispose, already disposed!"); + return; + } + logger.info("disposing the interceptor..."); + this.readyState = "DISPOSING" /* DISPOSING */; + if (!this.getInstance()) { + logger.info("no interceptors running, skipping dispose..."); + return; + } + this.clearInstance(); + logger.info("global symbol deleted:", getGlobalSymbol(this.symbol)); + if (this.subscriptions.length > 0) { + logger.info("disposing of %d subscriptions...", this.subscriptions.length); + for (const dispose of this.subscriptions) { + dispose(); + } + this.subscriptions = []; + logger.info("disposed of all subscriptions!", this.subscriptions.length); + } + this.emitter.removeAllListeners(); + logger.info("destroyed the listener!"); + this.readyState = "DISPOSED" /* DISPOSED */; + } + getInstance() { + var _a; + const instance = getGlobalSymbol(this.symbol); + this.logger.info("retrieved global instance:", (_a = instance == null ? void 0 : instance.constructor) == null ? void 0 : _a.name); + return instance; + } + setInstance() { + setGlobalSymbol(this.symbol, this); + this.logger.info("set global instance!", this.symbol.description); + } + clearInstance() { + deleteGlobalSymbol(this.symbol); + this.logger.info("cleared global instance!", this.symbol.description); + } +}; + +// src/createRequestId.ts +function createRequestId() { + return Math.random().toString(16).slice(2); +} + + + + + + + + +exports.INTERNAL_REQUEST_ID_HEADER_NAME = INTERNAL_REQUEST_ID_HEADER_NAME; exports.getGlobalSymbol = getGlobalSymbol; exports.deleteGlobalSymbol = deleteGlobalSymbol; exports.InterceptorReadyState = InterceptorReadyState; exports.Interceptor = Interceptor; exports.createRequestId = createRequestId; +//# sourceMappingURL=chunk-TIPR373R.js.map \ No newline at end of file diff --git a/node_modules/@mswjs/interceptors/lib/browser/chunk-TIPR373R.js.map b/node_modules/@mswjs/interceptors/lib/browser/chunk-TIPR373R.js.map new file mode 100644 index 0000000000000000000000000000000000000000..0becb9b1b416a6f58a91a5e4b16674781dfda461 --- /dev/null +++ b/node_modules/@mswjs/interceptors/lib/browser/chunk-TIPR373R.js.map @@ -0,0 +1 @@ +{"version":3,"sources":["../../src/Interceptor.ts","../../src/createRequestId.ts"],"names":["InterceptorReadyState"],"mappings":"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","sourcesContent":["import { Logger } from '@open-draft/logger'\nimport { Emitter, Listener } from 'strict-event-emitter'\n\nexport type InterceptorEventMap = Record\nexport type InterceptorSubscription = () => void\n\n/**\n * Request header name to detect when a single request\n * is being handled by nested interceptors (XHR -> ClientRequest).\n * Obscure by design to prevent collisions with user-defined headers.\n * Ideally, come up with the Interceptor-level mechanism for this.\n * @see https://github.com/mswjs/interceptors/issues/378\n */\nexport const INTERNAL_REQUEST_ID_HEADER_NAME =\n 'x-interceptors-internal-request-id'\n\nexport function getGlobalSymbol(symbol: Symbol): V | undefined {\n return (\n // @ts-ignore https://github.com/Microsoft/TypeScript/issues/24587\n globalThis[symbol] || undefined\n )\n}\n\nfunction setGlobalSymbol(symbol: Symbol, value: any): void {\n // @ts-ignore\n globalThis[symbol] = value\n}\n\nexport function deleteGlobalSymbol(symbol: Symbol): void {\n // @ts-ignore\n delete globalThis[symbol]\n}\n\nexport enum InterceptorReadyState {\n INACTIVE = 'INACTIVE',\n APPLYING = 'APPLYING',\n APPLIED = 'APPLIED',\n DISPOSING = 'DISPOSING',\n DISPOSED = 'DISPOSED',\n}\n\nexport type ExtractEventNames> =\n Events extends Record ? EventName : never\n\nexport class Interceptor {\n protected emitter: Emitter\n protected subscriptions: Array\n protected logger: Logger\n\n public readyState: InterceptorReadyState\n\n constructor(private readonly symbol: symbol) {\n this.readyState = InterceptorReadyState.INACTIVE\n\n this.emitter = new Emitter()\n this.subscriptions = []\n this.logger = new Logger(symbol.description!)\n\n // Do not limit the maximum number of listeners\n // so not to limit the maximum amount of parallel events emitted.\n this.emitter.setMaxListeners(0)\n\n this.logger.info('constructing the interceptor...')\n }\n\n /**\n * Determine if this interceptor can be applied\n * in the current environment.\n */\n protected checkEnvironment(): boolean {\n return true\n }\n\n /**\n * Apply this interceptor to the current process.\n * Returns an already running interceptor instance if it's present.\n */\n public apply(): void {\n const logger = this.logger.extend('apply')\n logger.info('applying the interceptor...')\n\n if (this.readyState === InterceptorReadyState.APPLIED) {\n logger.info('intercepted already applied!')\n return\n }\n\n const shouldApply = this.checkEnvironment()\n\n if (!shouldApply) {\n logger.info('the interceptor cannot be applied in this environment!')\n return\n }\n\n this.readyState = InterceptorReadyState.APPLYING\n\n // Whenever applying a new interceptor, check if it hasn't been applied already.\n // This enables to apply the same interceptor multiple times, for example from a different\n // interceptor, only proxying events but keeping the stubs in a single place.\n const runningInstance = this.getInstance()\n\n if (runningInstance) {\n logger.info('found a running instance, reusing...')\n\n // Proxy any listeners you set on this instance to the running instance.\n this.on = (event, listener) => {\n logger.info('proxying the \"%s\" listener', event)\n\n // Add listeners to the running instance so they appear\n // at the top of the event listeners list and are executed first.\n runningInstance.emitter.addListener(event, listener)\n\n // Ensure that once this interceptor instance is disposed,\n // it removes all listeners it has appended to the running interceptor instance.\n this.subscriptions.push(() => {\n runningInstance.emitter.removeListener(event, listener)\n logger.info('removed proxied \"%s\" listener!', event)\n })\n\n return this\n }\n\n this.readyState = InterceptorReadyState.APPLIED\n\n return\n }\n\n logger.info('no running instance found, setting up a new instance...')\n\n // Setup the interceptor.\n this.setup()\n\n // Store the newly applied interceptor instance globally.\n this.setInstance()\n\n this.readyState = InterceptorReadyState.APPLIED\n }\n\n /**\n * Setup the module augments and stubs necessary for this interceptor.\n * This method is not run if there's a running interceptor instance\n * to prevent instantiating an interceptor multiple times.\n */\n protected setup(): void {}\n\n /**\n * Listen to the interceptor's public events.\n */\n public on>(\n event: EventName,\n listener: Listener\n ): this {\n const logger = this.logger.extend('on')\n\n if (\n this.readyState === InterceptorReadyState.DISPOSING ||\n this.readyState === InterceptorReadyState.DISPOSED\n ) {\n logger.info('cannot listen to events, already disposed!')\n return this\n }\n\n logger.info('adding \"%s\" event listener:', event, listener)\n\n this.emitter.on(event, listener)\n return this\n }\n\n public once>(\n event: EventName,\n listener: Listener\n ): this {\n this.emitter.once(event, listener)\n return this\n }\n\n public off>(\n event: EventName,\n listener: Listener\n ): this {\n this.emitter.off(event, listener)\n return this\n }\n\n public removeAllListeners>(\n event?: EventName\n ): this {\n this.emitter.removeAllListeners(event)\n return this\n }\n\n /**\n * Disposes of any side-effects this interceptor has introduced.\n */\n public dispose(): void {\n const logger = this.logger.extend('dispose')\n\n if (this.readyState === InterceptorReadyState.DISPOSED) {\n logger.info('cannot dispose, already disposed!')\n return\n }\n\n logger.info('disposing the interceptor...')\n this.readyState = InterceptorReadyState.DISPOSING\n\n if (!this.getInstance()) {\n logger.info('no interceptors running, skipping dispose...')\n return\n }\n\n // Delete the global symbol as soon as possible,\n // indicating that the interceptor is no longer running.\n this.clearInstance()\n\n logger.info('global symbol deleted:', getGlobalSymbol(this.symbol))\n\n if (this.subscriptions.length > 0) {\n logger.info('disposing of %d subscriptions...', this.subscriptions.length)\n\n for (const dispose of this.subscriptions) {\n dispose()\n }\n\n this.subscriptions = []\n\n logger.info('disposed of all subscriptions!', this.subscriptions.length)\n }\n\n this.emitter.removeAllListeners()\n logger.info('destroyed the listener!')\n\n this.readyState = InterceptorReadyState.DISPOSED\n }\n\n private getInstance(): this | undefined {\n const instance = getGlobalSymbol(this.symbol)\n this.logger.info('retrieved global instance:', instance?.constructor?.name)\n return instance\n }\n\n private setInstance(): void {\n setGlobalSymbol(this.symbol, this)\n this.logger.info('set global instance!', this.symbol.description)\n }\n\n private clearInstance(): void {\n deleteGlobalSymbol(this.symbol)\n this.logger.info('cleared global instance!', this.symbol.description)\n }\n}\n","/**\n * Generate a random ID string to represent a request.\n * @example\n * createRequestId()\n * // \"f774b6c9c600f\"\n */\nexport function createRequestId(): string {\n return Math.random().toString(16).slice(2)\n}\n"]} \ No newline at end of file diff --git a/node_modules/@mswjs/interceptors/lib/browser/chunk-TX5GBTFY.mjs b/node_modules/@mswjs/interceptors/lib/browser/chunk-TX5GBTFY.mjs new file mode 100644 index 0000000000000000000000000000000000000000..f42b2faa86ecb8bf3f85d30e0bbeeb04b5f1b4dc --- /dev/null +++ b/node_modules/@mswjs/interceptors/lib/browser/chunk-TX5GBTFY.mjs @@ -0,0 +1,25 @@ +// src/utils/hasConfigurableGlobal.ts +function hasConfigurableGlobal(propertyName) { + const descriptor = Object.getOwnPropertyDescriptor(globalThis, propertyName); + if (typeof descriptor === "undefined") { + return false; + } + if (typeof descriptor.get === "function" && typeof descriptor.get() === "undefined") { + return false; + } + if (typeof descriptor.get === "undefined" && descriptor.value == null) { + return false; + } + if (typeof descriptor.set === "undefined" && !descriptor.configurable) { + console.error( + `[MSW] Failed to apply interceptor: the global \`${propertyName}\` property is non-configurable. This is likely an issue with your environment. If you are using a framework, please open an issue about this in their repository.` + ); + return false; + } + return true; +} + +export { + hasConfigurableGlobal +}; +//# sourceMappingURL=chunk-TX5GBTFY.mjs.map \ No newline at end of file diff --git a/node_modules/@mswjs/interceptors/lib/browser/chunk-TX5GBTFY.mjs.map b/node_modules/@mswjs/interceptors/lib/browser/chunk-TX5GBTFY.mjs.map new file mode 100644 index 0000000000000000000000000000000000000000..c5a9cb80f9e3490ec747574f677a05f8d48bd34d --- /dev/null +++ b/node_modules/@mswjs/interceptors/lib/browser/chunk-TX5GBTFY.mjs.map @@ -0,0 +1 @@ +{"version":3,"sources":["../../src/utils/hasConfigurableGlobal.ts"],"sourcesContent":["/**\n * Returns a boolean indicating whether the given global property\n * is defined and is configurable.\n */\nexport function hasConfigurableGlobal(propertyName: string): boolean {\n const descriptor = Object.getOwnPropertyDescriptor(globalThis, propertyName)\n\n // The property is not set at all.\n if (typeof descriptor === 'undefined') {\n return false\n }\n\n // The property is set to a getter that returns undefined.\n if (\n typeof descriptor.get === 'function' &&\n typeof descriptor.get() === 'undefined'\n ) {\n return false\n }\n\n // The property is set to a value equal to undefined.\n if (typeof descriptor.get === 'undefined' && descriptor.value == null) {\n return false\n }\n\n if (typeof descriptor.set === 'undefined' && !descriptor.configurable) {\n console.error(\n `[MSW] Failed to apply interceptor: the global \\`${propertyName}\\` property is non-configurable. This is likely an issue with your environment. If you are using a framework, please open an issue about this in their repository.`\n )\n return false\n }\n\n return true\n}\n"],"mappings":";AAIO,SAAS,sBAAsB,cAA+B;AACnE,QAAM,aAAa,OAAO,yBAAyB,YAAY,YAAY;AAG3E,MAAI,OAAO,eAAe,aAAa;AACrC,WAAO;AAAA,EACT;AAGA,MACE,OAAO,WAAW,QAAQ,cAC1B,OAAO,WAAW,IAAI,MAAM,aAC5B;AACA,WAAO;AAAA,EACT;AAGA,MAAI,OAAO,WAAW,QAAQ,eAAe,WAAW,SAAS,MAAM;AACrE,WAAO;AAAA,EACT;AAEA,MAAI,OAAO,WAAW,QAAQ,eAAe,CAAC,WAAW,cAAc;AACrE,YAAQ;AAAA,MACN,mDAAmD;AAAA,IACrD;AACA,WAAO;AAAA,EACT;AAEA,SAAO;AACT;","names":[]} \ No newline at end of file diff --git a/node_modules/@mswjs/interceptors/lib/browser/chunk-XTX2SIN6.mjs b/node_modules/@mswjs/interceptors/lib/browser/chunk-XTX2SIN6.mjs new file mode 100644 index 0000000000000000000000000000000000000000..dcaaa244eab04ebeeedad46b2a7f80cdcef8aeff --- /dev/null +++ b/node_modules/@mswjs/interceptors/lib/browser/chunk-XTX2SIN6.mjs @@ -0,0 +1,295 @@ +import { + RequestController, + emitAsync, + handleRequest +} from "./chunk-H5O73WD2.mjs"; +import { + FetchResponse, + IS_PATCHED_MODULE +} from "./chunk-5UK33FSU.mjs"; +import { + hasConfigurableGlobal +} from "./chunk-TX5GBTFY.mjs"; +import { + Interceptor, + createRequestId +} from "./chunk-QED3Q6Z2.mjs"; + +// src/interceptors/fetch/index.ts +import { invariant } from "outvariant"; +import { DeferredPromise } from "@open-draft/deferred-promise"; + +// src/utils/canParseUrl.ts +function canParseUrl(url) { + try { + new URL(url); + return true; + } catch (_error) { + return false; + } +} + +// src/interceptors/fetch/utils/createNetworkError.ts +function createNetworkError(cause) { + return Object.assign(new TypeError("Failed to fetch"), { + cause + }); +} + +// src/interceptors/fetch/utils/followRedirect.ts +var REQUEST_BODY_HEADERS = [ + "content-encoding", + "content-language", + "content-location", + "content-type", + "content-length" +]; +var kRedirectCount = Symbol("kRedirectCount"); +async function followFetchRedirect(request, response) { + if (response.status !== 303 && request.body != null) { + return Promise.reject(createNetworkError()); + } + const requestUrl = new URL(request.url); + let locationUrl; + try { + locationUrl = new URL(response.headers.get("location"), request.url); + } catch (error) { + return Promise.reject(createNetworkError(error)); + } + if (!(locationUrl.protocol === "http:" || locationUrl.protocol === "https:")) { + return Promise.reject( + createNetworkError("URL scheme must be a HTTP(S) scheme") + ); + } + if (Reflect.get(request, kRedirectCount) > 20) { + return Promise.reject(createNetworkError("redirect count exceeded")); + } + Object.defineProperty(request, kRedirectCount, { + value: (Reflect.get(request, kRedirectCount) || 0) + 1 + }); + if (request.mode === "cors" && (locationUrl.username || locationUrl.password) && !sameOrigin(requestUrl, locationUrl)) { + return Promise.reject( + createNetworkError('cross origin not allowed for request mode "cors"') + ); + } + const requestInit = {}; + if ([301, 302].includes(response.status) && request.method === "POST" || response.status === 303 && !["HEAD", "GET"].includes(request.method)) { + requestInit.method = "GET"; + requestInit.body = null; + REQUEST_BODY_HEADERS.forEach((headerName) => { + request.headers.delete(headerName); + }); + } + if (!sameOrigin(requestUrl, locationUrl)) { + request.headers.delete("authorization"); + request.headers.delete("proxy-authorization"); + request.headers.delete("cookie"); + request.headers.delete("host"); + } + requestInit.headers = request.headers; + return fetch(new Request(locationUrl, requestInit)); +} +function sameOrigin(left, right) { + if (left.origin === right.origin && left.origin === "null") { + return true; + } + if (left.protocol === right.protocol && left.hostname === right.hostname && left.port === right.port) { + return true; + } + return false; +} + +// src/interceptors/fetch/utils/brotli-decompress.browser.ts +var BrotliDecompressionStream = class extends TransformStream { + constructor() { + console.warn( + "[Interceptors]: Brotli decompression of response streams is not supported in the browser" + ); + super({ + transform(chunk, controller) { + controller.enqueue(chunk); + } + }); + } +}; + +// src/interceptors/fetch/utils/decompression.ts +var PipelineStream = class extends TransformStream { + constructor(transformStreams, ...strategies) { + super({}, ...strategies); + const readable = [super.readable, ...transformStreams].reduce( + (readable2, transform) => readable2.pipeThrough(transform) + ); + Object.defineProperty(this, "readable", { + get() { + return readable; + } + }); + } +}; +function parseContentEncoding(contentEncoding) { + return contentEncoding.toLowerCase().split(",").map((coding) => coding.trim()); +} +function createDecompressionStream(contentEncoding) { + if (contentEncoding === "") { + return null; + } + const codings = parseContentEncoding(contentEncoding); + if (codings.length === 0) { + return null; + } + const transformers = codings.reduceRight( + (transformers2, coding) => { + if (coding === "gzip" || coding === "x-gzip") { + return transformers2.concat(new DecompressionStream("gzip")); + } else if (coding === "deflate") { + return transformers2.concat(new DecompressionStream("deflate")); + } else if (coding === "br") { + return transformers2.concat(new BrotliDecompressionStream()); + } else { + transformers2.length = 0; + } + return transformers2; + }, + [] + ); + return new PipelineStream(transformers); +} +function decompressResponse(response) { + if (response.body === null) { + return null; + } + const decompressionStream = createDecompressionStream( + response.headers.get("content-encoding") || "" + ); + if (!decompressionStream) { + return null; + } + response.body.pipeTo(decompressionStream.writable); + return decompressionStream.readable; +} + +// src/interceptors/fetch/index.ts +var _FetchInterceptor = class extends Interceptor { + constructor() { + super(_FetchInterceptor.symbol); + } + checkEnvironment() { + return hasConfigurableGlobal("fetch"); + } + async setup() { + const pureFetch = globalThis.fetch; + invariant( + !pureFetch[IS_PATCHED_MODULE], + 'Failed to patch the "fetch" module: already patched.' + ); + globalThis.fetch = async (input, init) => { + const requestId = createRequestId(); + const resolvedInput = typeof input === "string" && typeof location !== "undefined" && !canParseUrl(input) ? new URL(input, location.origin) : input; + const request = new Request(resolvedInput, init); + const responsePromise = new DeferredPromise(); + const controller = new RequestController(request); + this.logger.info("[%s] %s", request.method, request.url); + this.logger.info("awaiting for the mocked response..."); + this.logger.info( + 'emitting the "request" event for %s listener(s)...', + this.emitter.listenerCount("request") + ); + const isRequestHandled = await handleRequest({ + request, + requestId, + emitter: this.emitter, + controller, + onResponse: async (rawResponse) => { + this.logger.info("received mocked response!", { + rawResponse + }); + const decompressedStream = decompressResponse(rawResponse); + const response = decompressedStream === null ? rawResponse : new FetchResponse(decompressedStream, rawResponse); + FetchResponse.setUrl(request.url, response); + if (FetchResponse.isRedirectResponse(response.status)) { + if (request.redirect === "error") { + responsePromise.reject(createNetworkError("unexpected redirect")); + return; + } + if (request.redirect === "follow") { + followFetchRedirect(request, response).then( + (response2) => { + responsePromise.resolve(response2); + }, + (reason) => { + responsePromise.reject(reason); + } + ); + return; + } + } + if (this.emitter.listenerCount("response") > 0) { + this.logger.info('emitting the "response" event...'); + await emitAsync(this.emitter, "response", { + // Clone the mocked response for the "response" event listener. + // This way, the listener can read the response and not lock its body + // for the actual fetch consumer. + response: response.clone(), + isMockedResponse: true, + request, + requestId + }); + } + responsePromise.resolve(response); + }, + onRequestError: (response) => { + this.logger.info("request has errored!", { response }); + responsePromise.reject(createNetworkError(response)); + }, + onError: (error) => { + this.logger.info("request has been aborted!", { error }); + responsePromise.reject(error); + } + }); + if (isRequestHandled) { + this.logger.info("request has been handled, returning mock promise..."); + return responsePromise; + } + this.logger.info( + "no mocked response received, performing request as-is..." + ); + return pureFetch(request).then(async (response) => { + this.logger.info("original fetch performed", response); + if (this.emitter.listenerCount("response") > 0) { + this.logger.info('emitting the "response" event...'); + const responseClone = response.clone(); + await emitAsync(this.emitter, "response", { + response: responseClone, + isMockedResponse: false, + request, + requestId + }); + } + return response; + }); + }; + Object.defineProperty(globalThis.fetch, IS_PATCHED_MODULE, { + enumerable: true, + configurable: true, + value: true + }); + this.subscriptions.push(() => { + Object.defineProperty(globalThis.fetch, IS_PATCHED_MODULE, { + value: void 0 + }); + globalThis.fetch = pureFetch; + this.logger.info( + 'restored native "globalThis.fetch"!', + globalThis.fetch.name + ); + }); + } +}; +var FetchInterceptor = _FetchInterceptor; +FetchInterceptor.symbol = Symbol("fetch"); + +export { + FetchInterceptor +}; +//# sourceMappingURL=chunk-XTX2SIN6.mjs.map \ No newline at end of file diff --git a/node_modules/@mswjs/interceptors/lib/browser/chunk-XTX2SIN6.mjs.map b/node_modules/@mswjs/interceptors/lib/browser/chunk-XTX2SIN6.mjs.map new file mode 100644 index 0000000000000000000000000000000000000000..31bf961168ee76858143b0a7aef8153ae551d1ff --- /dev/null +++ b/node_modules/@mswjs/interceptors/lib/browser/chunk-XTX2SIN6.mjs.map @@ -0,0 +1 @@ +{"version":3,"sources":["../../src/interceptors/fetch/index.ts","../../src/utils/canParseUrl.ts","../../src/interceptors/fetch/utils/createNetworkError.ts","../../src/interceptors/fetch/utils/followRedirect.ts","../../src/interceptors/fetch/utils/brotli-decompress.browser.ts","../../src/interceptors/fetch/utils/decompression.ts"],"sourcesContent":["import { invariant } from 'outvariant'\nimport { DeferredPromise } from '@open-draft/deferred-promise'\nimport { HttpRequestEventMap, IS_PATCHED_MODULE } from '../../glossary'\nimport { Interceptor } from '../../Interceptor'\nimport { RequestController } from '../../RequestController'\nimport { emitAsync } from '../../utils/emitAsync'\nimport { handleRequest } from '../../utils/handleRequest'\nimport { canParseUrl } from '../../utils/canParseUrl'\nimport { createRequestId } from '../../createRequestId'\nimport { createNetworkError } from './utils/createNetworkError'\nimport { followFetchRedirect } from './utils/followRedirect'\nimport { decompressResponse } from './utils/decompression'\nimport { hasConfigurableGlobal } from '../../utils/hasConfigurableGlobal'\nimport { FetchResponse } from '../../utils/fetchUtils'\n\nexport class FetchInterceptor extends Interceptor {\n static symbol = Symbol('fetch')\n\n constructor() {\n super(FetchInterceptor.symbol)\n }\n\n protected checkEnvironment() {\n return hasConfigurableGlobal('fetch')\n }\n\n protected async setup() {\n const pureFetch = globalThis.fetch\n\n invariant(\n !(pureFetch as any)[IS_PATCHED_MODULE],\n 'Failed to patch the \"fetch\" module: already patched.'\n )\n\n globalThis.fetch = async (input, init) => {\n const requestId = createRequestId()\n\n /**\n * @note Resolve potentially relative request URL\n * against the present `location`. This is mainly\n * for native `fetch` in JSDOM.\n * @see https://github.com/mswjs/msw/issues/1625\n */\n const resolvedInput =\n typeof input === 'string' &&\n typeof location !== 'undefined' &&\n !canParseUrl(input)\n ? new URL(input, location.origin)\n : input\n\n const request = new Request(resolvedInput, init)\n const responsePromise = new DeferredPromise()\n const controller = new RequestController(request)\n\n this.logger.info('[%s] %s', request.method, request.url)\n this.logger.info('awaiting for the mocked response...')\n\n this.logger.info(\n 'emitting the \"request\" event for %s listener(s)...',\n this.emitter.listenerCount('request')\n )\n\n const isRequestHandled = await handleRequest({\n request,\n requestId,\n emitter: this.emitter,\n controller,\n onResponse: async (rawResponse) => {\n this.logger.info('received mocked response!', {\n rawResponse,\n })\n\n // Decompress the mocked response body, if applicable.\n const decompressedStream = decompressResponse(rawResponse)\n const response =\n decompressedStream === null\n ? rawResponse\n : new FetchResponse(decompressedStream, rawResponse)\n\n FetchResponse.setUrl(request.url, response)\n\n /**\n * Undici's handling of following redirect responses.\n * Treat the \"manual\" redirect mode as a regular mocked response.\n * This way, the client can manually follow the redirect it receives.\n * @see https://github.com/nodejs/undici/blob/a6dac3149c505b58d2e6d068b97f4dc993da55f0/lib/web/fetch/index.js#L1173\n */\n if (FetchResponse.isRedirectResponse(response.status)) {\n // Reject the request promise if its `redirect` is set to `error`\n // and it receives a mocked redirect response.\n if (request.redirect === 'error') {\n responsePromise.reject(createNetworkError('unexpected redirect'))\n return\n }\n\n if (request.redirect === 'follow') {\n followFetchRedirect(request, response).then(\n (response) => {\n responsePromise.resolve(response)\n },\n (reason) => {\n responsePromise.reject(reason)\n }\n )\n return\n }\n }\n\n if (this.emitter.listenerCount('response') > 0) {\n this.logger.info('emitting the \"response\" event...')\n\n // Await the response listeners to finish before resolving\n // the response promise. This ensures all your logic finishes\n // before the interceptor resolves the pending response.\n await emitAsync(this.emitter, 'response', {\n // Clone the mocked response for the \"response\" event listener.\n // This way, the listener can read the response and not lock its body\n // for the actual fetch consumer.\n response: response.clone(),\n isMockedResponse: true,\n request,\n requestId,\n })\n }\n\n responsePromise.resolve(response)\n },\n onRequestError: (response) => {\n this.logger.info('request has errored!', { response })\n responsePromise.reject(createNetworkError(response))\n },\n onError: (error) => {\n this.logger.info('request has been aborted!', { error })\n responsePromise.reject(error)\n },\n })\n\n if (isRequestHandled) {\n this.logger.info('request has been handled, returning mock promise...')\n return responsePromise\n }\n\n this.logger.info(\n 'no mocked response received, performing request as-is...'\n )\n\n return pureFetch(request).then(async (response) => {\n this.logger.info('original fetch performed', response)\n\n if (this.emitter.listenerCount('response') > 0) {\n this.logger.info('emitting the \"response\" event...')\n\n const responseClone = response.clone()\n\n await emitAsync(this.emitter, 'response', {\n response: responseClone,\n isMockedResponse: false,\n request,\n requestId,\n })\n }\n\n return response\n })\n }\n\n Object.defineProperty(globalThis.fetch, IS_PATCHED_MODULE, {\n enumerable: true,\n configurable: true,\n value: true,\n })\n\n this.subscriptions.push(() => {\n Object.defineProperty(globalThis.fetch, IS_PATCHED_MODULE, {\n value: undefined,\n })\n\n globalThis.fetch = pureFetch\n\n this.logger.info(\n 'restored native \"globalThis.fetch\"!',\n globalThis.fetch.name\n )\n })\n }\n}\n","/**\n * Returns a boolean indicating whether the given URL string\n * can be parsed into a `URL` instance.\n * A substitute for `URL.canParse()` for Node.js 18.\n */\nexport function canParseUrl(url: string): boolean {\n try {\n new URL(url)\n return true\n } catch (_error) {\n return false\n }\n}\n","export function createNetworkError(cause?: unknown) {\n return Object.assign(new TypeError('Failed to fetch'), {\n cause,\n })\n}\n","import { createNetworkError } from './createNetworkError'\n\nconst REQUEST_BODY_HEADERS = [\n 'content-encoding',\n 'content-language',\n 'content-location',\n 'content-type',\n 'content-length',\n]\n\nconst kRedirectCount = Symbol('kRedirectCount')\n\n/**\n * @see https://github.com/nodejs/undici/blob/a6dac3149c505b58d2e6d068b97f4dc993da55f0/lib/web/fetch/index.js#L1210\n */\nexport async function followFetchRedirect(\n request: Request,\n response: Response\n): Promise {\n if (response.status !== 303 && request.body != null) {\n return Promise.reject(createNetworkError())\n }\n\n const requestUrl = new URL(request.url)\n\n let locationUrl: URL\n try {\n // If the location is a relative URL, use the request URL as the base URL.\n locationUrl = new URL(response.headers.get('location')!, request.url) \n } catch (error) {\n return Promise.reject(createNetworkError(error))\n }\n\n if (\n !(locationUrl.protocol === 'http:' || locationUrl.protocol === 'https:')\n ) {\n return Promise.reject(\n createNetworkError('URL scheme must be a HTTP(S) scheme')\n )\n }\n\n if (Reflect.get(request, kRedirectCount) > 20) {\n return Promise.reject(createNetworkError('redirect count exceeded'))\n }\n\n Object.defineProperty(request, kRedirectCount, {\n value: (Reflect.get(request, kRedirectCount) || 0) + 1,\n })\n\n if (\n request.mode === 'cors' &&\n (locationUrl.username || locationUrl.password) &&\n !sameOrigin(requestUrl, locationUrl)\n ) {\n return Promise.reject(\n createNetworkError('cross origin not allowed for request mode \"cors\"')\n )\n }\n\n const requestInit: RequestInit = {}\n\n if (\n ([301, 302].includes(response.status) && request.method === 'POST') ||\n (response.status === 303 && !['HEAD', 'GET'].includes(request.method))\n ) {\n requestInit.method = 'GET'\n requestInit.body = null\n\n REQUEST_BODY_HEADERS.forEach((headerName) => {\n request.headers.delete(headerName)\n })\n }\n\n if (!sameOrigin(requestUrl, locationUrl)) {\n request.headers.delete('authorization')\n request.headers.delete('proxy-authorization')\n request.headers.delete('cookie')\n request.headers.delete('host')\n }\n\n /**\n * @note Undici \"safely\" extracts the request body.\n * I suspect we cannot dispatch this request again\n * since its body has been read and the stream is locked.\n */\n\n requestInit.headers = request.headers\n return fetch(new Request(locationUrl, requestInit))\n}\n\n/**\n * @see https://github.com/nodejs/undici/blob/a6dac3149c505b58d2e6d068b97f4dc993da55f0/lib/web/fetch/util.js#L761\n */\nfunction sameOrigin(left: URL, right: URL): boolean {\n if (left.origin === right.origin && left.origin === 'null') {\n return true\n }\n\n if (\n left.protocol === right.protocol &&\n left.hostname === right.hostname &&\n left.port === right.port\n ) {\n return true\n }\n\n return false\n}\n","export class BrotliDecompressionStream extends TransformStream {\n constructor() {\n console.warn(\n '[Interceptors]: Brotli decompression of response streams is not supported in the browser'\n )\n\n super({\n transform(chunk, controller) {\n // Keep the stream as passthrough, it does nothing.\n controller.enqueue(chunk)\n },\n })\n }\n}\n","// Import from an internal alias that resolves to different modules\n// depending on the environment. This way, we can keep the fetch interceptor\n// intact while using different strategies for Brotli decompression.\nimport { BrotliDecompressionStream } from 'internal:brotli-decompress'\n\nclass PipelineStream extends TransformStream {\n constructor(\n transformStreams: Array,\n ...strategies: Array\n ) {\n super({}, ...strategies)\n\n const readable = [super.readable as any, ...transformStreams].reduce(\n (readable, transform) => readable.pipeThrough(transform)\n )\n\n Object.defineProperty(this, 'readable', {\n get() {\n return readable\n },\n })\n }\n}\n\nexport function parseContentEncoding(contentEncoding: string): Array {\n return contentEncoding\n .toLowerCase()\n .split(',')\n .map((coding) => coding.trim())\n}\n\nfunction createDecompressionStream(\n contentEncoding: string\n): TransformStream | null {\n if (contentEncoding === '') {\n return null\n }\n\n const codings = parseContentEncoding(contentEncoding)\n\n if (codings.length === 0) {\n return null\n }\n\n const transformers = codings.reduceRight>(\n (transformers, coding) => {\n if (coding === 'gzip' || coding === 'x-gzip') {\n return transformers.concat(new DecompressionStream('gzip'))\n } else if (coding === 'deflate') {\n return transformers.concat(new DecompressionStream('deflate'))\n } else if (coding === 'br') {\n return transformers.concat(new BrotliDecompressionStream())\n } else {\n transformers.length = 0\n }\n\n return transformers\n },\n []\n )\n\n return new PipelineStream(transformers)\n}\n\nexport function decompressResponse(\n response: Response\n): ReadableStream | null {\n if (response.body === null) {\n return null\n }\n\n const decompressionStream = createDecompressionStream(\n response.headers.get('content-encoding') || ''\n )\n\n if (!decompressionStream) {\n return null\n }\n\n // Use `pipeTo` and return the decompression stream's readable\n // instead of `pipeThrough` because that will lock the original\n // response stream, making it unusable as the input to Response.\n response.body.pipeTo(decompressionStream.writable)\n return decompressionStream.readable\n}\n"],"mappings":"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","names":["readable","transformers","response"]} \ No newline at end of file diff --git a/node_modules/@mswjs/interceptors/lib/browser/chunk-ZIT2QX7D.js b/node_modules/@mswjs/interceptors/lib/browser/chunk-ZIT2QX7D.js new file mode 100644 index 0000000000000000000000000000000000000000..8a8b74e1c09f71013dd83cbac39cbf1c072d8295 --- /dev/null +++ b/node_modules/@mswjs/interceptors/lib/browser/chunk-ZIT2QX7D.js @@ -0,0 +1,844 @@ +"use strict";Object.defineProperty(exports, "__esModule", {value: true}); + + + +var _chunkLK6DILFKjs = require('./chunk-LK6DILFK.js'); + + + +var _chunkFGSEOIC4js = require('./chunk-FGSEOIC4.js'); + + + +var _chunkBC2BLJQNjs = require('./chunk-BC2BLJQN.js'); + + +var _chunkPFGO5BSMjs = require('./chunk-PFGO5BSM.js'); + + + + +var _chunkTIPR373Rjs = require('./chunk-TIPR373R.js'); + +// src/interceptors/XMLHttpRequest/index.ts +var _outvariant = require('outvariant'); + +// src/interceptors/XMLHttpRequest/XMLHttpRequestController.ts + +var _isnodeprocess = require('is-node-process'); + +// src/interceptors/XMLHttpRequest/utils/concatArrayBuffer.ts +function concatArrayBuffer(left, right) { + const result = new Uint8Array(left.byteLength + right.byteLength); + result.set(left, 0); + result.set(right, left.byteLength); + return result; +} + +// src/interceptors/XMLHttpRequest/polyfills/EventPolyfill.ts +var EventPolyfill = class { + constructor(type, options) { + this.NONE = 0; + this.CAPTURING_PHASE = 1; + this.AT_TARGET = 2; + this.BUBBLING_PHASE = 3; + this.type = ""; + this.srcElement = null; + this.currentTarget = null; + this.eventPhase = 0; + this.isTrusted = true; + this.composed = false; + this.cancelable = true; + this.defaultPrevented = false; + this.bubbles = true; + this.lengthComputable = true; + this.loaded = 0; + this.total = 0; + this.cancelBubble = false; + this.returnValue = true; + this.type = type; + this.target = (options == null ? void 0 : options.target) || null; + this.currentTarget = (options == null ? void 0 : options.currentTarget) || null; + this.timeStamp = Date.now(); + } + composedPath() { + return []; + } + initEvent(type, bubbles, cancelable) { + this.type = type; + this.bubbles = !!bubbles; + this.cancelable = !!cancelable; + } + preventDefault() { + this.defaultPrevented = true; + } + stopPropagation() { + } + stopImmediatePropagation() { + } +}; + +// src/interceptors/XMLHttpRequest/polyfills/ProgressEventPolyfill.ts +var ProgressEventPolyfill = class extends EventPolyfill { + constructor(type, init) { + super(type); + this.lengthComputable = (init == null ? void 0 : init.lengthComputable) || false; + this.composed = (init == null ? void 0 : init.composed) || false; + this.loaded = (init == null ? void 0 : init.loaded) || 0; + this.total = (init == null ? void 0 : init.total) || 0; + } +}; + +// src/interceptors/XMLHttpRequest/utils/createEvent.ts +var SUPPORTS_PROGRESS_EVENT = typeof ProgressEvent !== "undefined"; +function createEvent(target, type, init) { + const progressEvents = [ + "error", + "progress", + "loadstart", + "loadend", + "load", + "timeout", + "abort" + ]; + const ProgressEventClass = SUPPORTS_PROGRESS_EVENT ? ProgressEvent : ProgressEventPolyfill; + const event = progressEvents.includes(type) ? new ProgressEventClass(type, { + lengthComputable: true, + loaded: (init == null ? void 0 : init.loaded) || 0, + total: (init == null ? void 0 : init.total) || 0 + }) : new EventPolyfill(type, { + target, + currentTarget: target + }); + return event; +} + +// src/utils/findPropertySource.ts +function findPropertySource(target, propertyName) { + if (!(propertyName in target)) { + return null; + } + const hasProperty = Object.prototype.hasOwnProperty.call(target, propertyName); + if (hasProperty) { + return target; + } + const prototype = Reflect.getPrototypeOf(target); + return prototype ? findPropertySource(prototype, propertyName) : null; +} + +// src/utils/createProxy.ts +function createProxy(target, options) { + const proxy = new Proxy(target, optionsToProxyHandler(options)); + return proxy; +} +function optionsToProxyHandler(options) { + const { constructorCall, methodCall, getProperty, setProperty } = options; + const handler = {}; + if (typeof constructorCall !== "undefined") { + handler.construct = function(target, args, newTarget) { + const next = Reflect.construct.bind(null, target, args, newTarget); + return constructorCall.call(newTarget, args, next); + }; + } + handler.set = function(target, propertyName, nextValue) { + const next = () => { + const propertySource = findPropertySource(target, propertyName) || target; + const ownDescriptors = Reflect.getOwnPropertyDescriptor( + propertySource, + propertyName + ); + if (typeof (ownDescriptors == null ? void 0 : ownDescriptors.set) !== "undefined") { + ownDescriptors.set.apply(target, [nextValue]); + return true; + } + return Reflect.defineProperty(propertySource, propertyName, { + writable: true, + enumerable: true, + configurable: true, + value: nextValue + }); + }; + if (typeof setProperty !== "undefined") { + return setProperty.call(target, [propertyName, nextValue], next); + } + return next(); + }; + handler.get = function(target, propertyName, receiver) { + const next = () => target[propertyName]; + const value = typeof getProperty !== "undefined" ? getProperty.call(target, [propertyName, receiver], next) : next(); + if (typeof value === "function") { + return (...args) => { + const next2 = value.bind(target, ...args); + if (typeof methodCall !== "undefined") { + return methodCall.call(target, [propertyName, args], next2); + } + return next2(); + }; + } + return value; + }; + return handler; +} + +// src/interceptors/XMLHttpRequest/utils/isDomParserSupportedType.ts +function isDomParserSupportedType(type) { + const supportedTypes = [ + "application/xhtml+xml", + "application/xml", + "image/svg+xml", + "text/html", + "text/xml" + ]; + return supportedTypes.some((supportedType) => { + return type.startsWith(supportedType); + }); +} + +// src/utils/parseJson.ts +function parseJson(data) { + try { + const json = JSON.parse(data); + return json; + } catch (_) { + return null; + } +} + +// src/interceptors/XMLHttpRequest/utils/createResponse.ts +function createResponse(request, body) { + const responseBodyOrNull = _chunkBC2BLJQNjs.FetchResponse.isResponseWithBody(request.status) ? body : null; + return new (0, _chunkBC2BLJQNjs.FetchResponse)(responseBodyOrNull, { + url: request.responseURL, + status: request.status, + statusText: request.statusText, + headers: createHeadersFromXMLHttpReqestHeaders( + request.getAllResponseHeaders() + ) + }); +} +function createHeadersFromXMLHttpReqestHeaders(headersString) { + const headers = new Headers(); + const lines = headersString.split(/[\r\n]+/); + for (const line of lines) { + if (line.trim() === "") { + continue; + } + const [name, ...parts] = line.split(": "); + const value = parts.join(": "); + headers.append(name, value); + } + return headers; +} + +// src/interceptors/XMLHttpRequest/utils/getBodyByteLength.ts +async function getBodyByteLength(input) { + const explicitContentLength = input.headers.get("content-length"); + if (explicitContentLength != null && explicitContentLength !== "") { + return Number(explicitContentLength); + } + const buffer = await input.arrayBuffer(); + return buffer.byteLength; +} + +// src/interceptors/XMLHttpRequest/XMLHttpRequestController.ts +var kIsRequestHandled = Symbol("kIsRequestHandled"); +var IS_NODE = _isnodeprocess.isNodeProcess.call(void 0, ); +var kFetchRequest = Symbol("kFetchRequest"); +var XMLHttpRequestController = class { + constructor(initialRequest, logger) { + this.initialRequest = initialRequest; + this.logger = logger; + this.method = "GET"; + this.url = null; + this[kIsRequestHandled] = false; + this.events = /* @__PURE__ */ new Map(); + this.uploadEvents = /* @__PURE__ */ new Map(); + this.requestId = _chunkTIPR373Rjs.createRequestId.call(void 0, ); + this.requestHeaders = new Headers(); + this.responseBuffer = new Uint8Array(); + this.request = createProxy(initialRequest, { + setProperty: ([propertyName, nextValue], invoke) => { + switch (propertyName) { + case "ontimeout": { + const eventName = propertyName.slice( + 2 + ); + this.request.addEventListener(eventName, nextValue); + return invoke(); + } + default: { + return invoke(); + } + } + }, + methodCall: ([methodName, args], invoke) => { + var _a; + switch (methodName) { + case "open": { + const [method, url] = args; + if (typeof url === "undefined") { + this.method = "GET"; + this.url = toAbsoluteUrl(method); + } else { + this.method = method; + this.url = toAbsoluteUrl(url); + } + this.logger = this.logger.extend(`${this.method} ${this.url.href}`); + this.logger.info("open", this.method, this.url.href); + return invoke(); + } + case "addEventListener": { + const [eventName, listener] = args; + this.registerEvent(eventName, listener); + this.logger.info("addEventListener", eventName, listener); + return invoke(); + } + case "setRequestHeader": { + const [name, value] = args; + this.requestHeaders.set(name, value); + this.logger.info("setRequestHeader", name, value); + return invoke(); + } + case "send": { + const [body] = args; + this.request.addEventListener("load", () => { + if (typeof this.onResponse !== "undefined") { + const fetchResponse = createResponse( + this.request, + /** + * The `response` property is the right way to read + * the ambiguous response body, as the request's "responseType" may differ. + * @see https://xhr.spec.whatwg.org/#the-response-attribute + */ + this.request.response + ); + this.onResponse.call(this, { + response: fetchResponse, + isMockedResponse: this[kIsRequestHandled], + request: fetchRequest, + requestId: this.requestId + }); + } + }); + const requestBody = typeof body === "string" ? _chunkLK6DILFKjs.encodeBuffer.call(void 0, body) : body; + const fetchRequest = this.toFetchApiRequest(requestBody); + this[kFetchRequest] = fetchRequest.clone(); + const onceRequestSettled = ((_a = this.onRequest) == null ? void 0 : _a.call(this, { + request: fetchRequest, + requestId: this.requestId + })) || Promise.resolve(); + onceRequestSettled.finally(() => { + if (!this[kIsRequestHandled]) { + this.logger.info( + "request callback settled but request has not been handled (readystate %d), performing as-is...", + this.request.readyState + ); + if (IS_NODE) { + this.request.setRequestHeader( + _chunkTIPR373Rjs.INTERNAL_REQUEST_ID_HEADER_NAME, + this.requestId + ); + } + return invoke(); + } + }); + break; + } + default: { + return invoke(); + } + } + } + }); + define( + this.request, + "upload", + createProxy(this.request.upload, { + setProperty: ([propertyName, nextValue], invoke) => { + switch (propertyName) { + case "onloadstart": + case "onprogress": + case "onaboart": + case "onerror": + case "onload": + case "ontimeout": + case "onloadend": { + const eventName = propertyName.slice( + 2 + ); + this.registerUploadEvent(eventName, nextValue); + } + } + return invoke(); + }, + methodCall: ([methodName, args], invoke) => { + switch (methodName) { + case "addEventListener": { + const [eventName, listener] = args; + this.registerUploadEvent(eventName, listener); + this.logger.info("upload.addEventListener", eventName, listener); + return invoke(); + } + } + } + }) + ); + } + registerEvent(eventName, listener) { + const prevEvents = this.events.get(eventName) || []; + const nextEvents = prevEvents.concat(listener); + this.events.set(eventName, nextEvents); + this.logger.info('registered event "%s"', eventName, listener); + } + registerUploadEvent(eventName, listener) { + const prevEvents = this.uploadEvents.get(eventName) || []; + const nextEvents = prevEvents.concat(listener); + this.uploadEvents.set(eventName, nextEvents); + this.logger.info('registered upload event "%s"', eventName, listener); + } + /** + * Responds to the current request with the given + * Fetch API `Response` instance. + */ + async respondWith(response) { + this[kIsRequestHandled] = true; + if (this[kFetchRequest]) { + const totalRequestBodyLength = await getBodyByteLength( + this[kFetchRequest] + ); + this.trigger("loadstart", this.request.upload, { + loaded: 0, + total: totalRequestBodyLength + }); + this.trigger("progress", this.request.upload, { + loaded: totalRequestBodyLength, + total: totalRequestBodyLength + }); + this.trigger("load", this.request.upload, { + loaded: totalRequestBodyLength, + total: totalRequestBodyLength + }); + this.trigger("loadend", this.request.upload, { + loaded: totalRequestBodyLength, + total: totalRequestBodyLength + }); + } + this.logger.info( + "responding with a mocked response: %d %s", + response.status, + response.statusText + ); + define(this.request, "status", response.status); + define(this.request, "statusText", response.statusText); + define(this.request, "responseURL", this.url.href); + this.request.getResponseHeader = new Proxy(this.request.getResponseHeader, { + apply: (_, __, args) => { + this.logger.info("getResponseHeader", args[0]); + if (this.request.readyState < this.request.HEADERS_RECEIVED) { + this.logger.info("headers not received yet, returning null"); + return null; + } + const headerValue = response.headers.get(args[0]); + this.logger.info( + 'resolved response header "%s" to', + args[0], + headerValue + ); + return headerValue; + } + }); + this.request.getAllResponseHeaders = new Proxy( + this.request.getAllResponseHeaders, + { + apply: () => { + this.logger.info("getAllResponseHeaders"); + if (this.request.readyState < this.request.HEADERS_RECEIVED) { + this.logger.info("headers not received yet, returning empty string"); + return ""; + } + const headersList = Array.from(response.headers.entries()); + const allHeaders = headersList.map(([headerName, headerValue]) => { + return `${headerName}: ${headerValue}`; + }).join("\r\n"); + this.logger.info("resolved all response headers to", allHeaders); + return allHeaders; + } + } + ); + Object.defineProperties(this.request, { + response: { + enumerable: true, + configurable: false, + get: () => this.response + }, + responseText: { + enumerable: true, + configurable: false, + get: () => this.responseText + }, + responseXML: { + enumerable: true, + configurable: false, + get: () => this.responseXML + } + }); + const totalResponseBodyLength = await getBodyByteLength(response.clone()); + this.logger.info("calculated response body length", totalResponseBodyLength); + this.trigger("loadstart", this.request, { + loaded: 0, + total: totalResponseBodyLength + }); + this.setReadyState(this.request.HEADERS_RECEIVED); + this.setReadyState(this.request.LOADING); + const finalizeResponse = () => { + this.logger.info("finalizing the mocked response..."); + this.setReadyState(this.request.DONE); + this.trigger("load", this.request, { + loaded: this.responseBuffer.byteLength, + total: totalResponseBodyLength + }); + this.trigger("loadend", this.request, { + loaded: this.responseBuffer.byteLength, + total: totalResponseBodyLength + }); + }; + if (response.body) { + this.logger.info("mocked response has body, streaming..."); + const reader = response.body.getReader(); + const readNextResponseBodyChunk = async () => { + const { value, done } = await reader.read(); + if (done) { + this.logger.info("response body stream done!"); + finalizeResponse(); + return; + } + if (value) { + this.logger.info("read response body chunk:", value); + this.responseBuffer = concatArrayBuffer(this.responseBuffer, value); + this.trigger("progress", this.request, { + loaded: this.responseBuffer.byteLength, + total: totalResponseBodyLength + }); + } + readNextResponseBodyChunk(); + }; + readNextResponseBodyChunk(); + } else { + finalizeResponse(); + } + } + responseBufferToText() { + return _chunkLK6DILFKjs.decodeBuffer.call(void 0, this.responseBuffer); + } + get response() { + this.logger.info( + "getResponse (responseType: %s)", + this.request.responseType + ); + if (this.request.readyState !== this.request.DONE) { + return null; + } + switch (this.request.responseType) { + case "json": { + const responseJson = parseJson(this.responseBufferToText()); + this.logger.info("resolved response JSON", responseJson); + return responseJson; + } + case "arraybuffer": { + const arrayBuffer = _chunkLK6DILFKjs.toArrayBuffer.call(void 0, this.responseBuffer); + this.logger.info("resolved response ArrayBuffer", arrayBuffer); + return arrayBuffer; + } + case "blob": { + const mimeType = this.request.getResponseHeader("Content-Type") || "text/plain"; + const responseBlob = new Blob([this.responseBufferToText()], { + type: mimeType + }); + this.logger.info( + "resolved response Blob (mime type: %s)", + responseBlob, + mimeType + ); + return responseBlob; + } + default: { + const responseText = this.responseBufferToText(); + this.logger.info( + 'resolving "%s" response type as text', + this.request.responseType, + responseText + ); + return responseText; + } + } + } + get responseText() { + _outvariant.invariant.call(void 0, + this.request.responseType === "" || this.request.responseType === "text", + "InvalidStateError: The object is in invalid state." + ); + if (this.request.readyState !== this.request.LOADING && this.request.readyState !== this.request.DONE) { + return ""; + } + const responseText = this.responseBufferToText(); + this.logger.info('getResponseText: "%s"', responseText); + return responseText; + } + get responseXML() { + _outvariant.invariant.call(void 0, + this.request.responseType === "" || this.request.responseType === "document", + "InvalidStateError: The object is in invalid state." + ); + if (this.request.readyState !== this.request.DONE) { + return null; + } + const contentType = this.request.getResponseHeader("Content-Type") || ""; + if (typeof DOMParser === "undefined") { + console.warn( + "Cannot retrieve XMLHttpRequest response body as XML: DOMParser is not defined. You are likely using an environment that is not browser or does not polyfill browser globals correctly." + ); + return null; + } + if (isDomParserSupportedType(contentType)) { + return new DOMParser().parseFromString( + this.responseBufferToText(), + contentType + ); + } + return null; + } + errorWith(error) { + this[kIsRequestHandled] = true; + this.logger.info("responding with an error"); + this.setReadyState(this.request.DONE); + this.trigger("error", this.request); + this.trigger("loadend", this.request); + } + /** + * Transitions this request's `readyState` to the given one. + */ + setReadyState(nextReadyState) { + this.logger.info( + "setReadyState: %d -> %d", + this.request.readyState, + nextReadyState + ); + if (this.request.readyState === nextReadyState) { + this.logger.info("ready state identical, skipping transition..."); + return; + } + define(this.request, "readyState", nextReadyState); + this.logger.info("set readyState to: %d", nextReadyState); + if (nextReadyState !== this.request.UNSENT) { + this.logger.info('triggerring "readystatechange" event...'); + this.trigger("readystatechange", this.request); + } + } + /** + * Triggers given event on the `XMLHttpRequest` instance. + */ + trigger(eventName, target, options) { + const callback = target[`on${eventName}`]; + const event = createEvent(target, eventName, options); + this.logger.info('trigger "%s"', eventName, options || ""); + if (typeof callback === "function") { + this.logger.info('found a direct "%s" callback, calling...', eventName); + callback.call(target, event); + } + const events = target instanceof XMLHttpRequestUpload ? this.uploadEvents : this.events; + for (const [registeredEventName, listeners] of events) { + if (registeredEventName === eventName) { + this.logger.info( + 'found %d listener(s) for "%s" event, calling...', + listeners.length, + eventName + ); + listeners.forEach((listener) => listener.call(target, event)); + } + } + } + /** + * Converts this `XMLHttpRequest` instance into a Fetch API `Request` instance. + */ + toFetchApiRequest(body) { + this.logger.info("converting request to a Fetch API Request..."); + const resolvedBody = body instanceof Document ? body.documentElement.innerText : body; + const fetchRequest = new Request(this.url.href, { + method: this.method, + headers: this.requestHeaders, + /** + * @see https://xhr.spec.whatwg.org/#cross-origin-credentials + */ + credentials: this.request.withCredentials ? "include" : "same-origin", + body: ["GET", "HEAD"].includes(this.method.toUpperCase()) ? null : resolvedBody + }); + const proxyHeaders = createProxy(fetchRequest.headers, { + methodCall: ([methodName, args], invoke) => { + switch (methodName) { + case "append": + case "set": { + const [headerName, headerValue] = args; + this.request.setRequestHeader(headerName, headerValue); + break; + } + case "delete": { + const [headerName] = args; + console.warn( + `XMLHttpRequest: Cannot remove a "${headerName}" header from the Fetch API representation of the "${fetchRequest.method} ${fetchRequest.url}" request. XMLHttpRequest headers cannot be removed.` + ); + break; + } + } + return invoke(); + } + }); + define(fetchRequest, "headers", proxyHeaders); + this.logger.info("converted request to a Fetch API Request!", fetchRequest); + return fetchRequest; + } +}; +kIsRequestHandled, kFetchRequest; +function toAbsoluteUrl(url) { + if (typeof location === "undefined") { + return new URL(url); + } + return new URL(url.toString(), location.href); +} +function define(target, property, value) { + Reflect.defineProperty(target, property, { + // Ensure writable properties to allow redefining readonly properties. + writable: true, + enumerable: true, + value + }); +} + +// src/interceptors/XMLHttpRequest/XMLHttpRequestProxy.ts +function createXMLHttpRequestProxy({ + emitter, + logger +}) { + const XMLHttpRequestProxy = new Proxy(globalThis.XMLHttpRequest, { + construct(target, args, newTarget) { + logger.info("constructed new XMLHttpRequest"); + const originalRequest = Reflect.construct( + target, + args, + newTarget + ); + const prototypeDescriptors = Object.getOwnPropertyDescriptors( + target.prototype + ); + for (const propertyName in prototypeDescriptors) { + Reflect.defineProperty( + originalRequest, + propertyName, + prototypeDescriptors[propertyName] + ); + } + const xhrRequestController = new XMLHttpRequestController( + originalRequest, + logger + ); + xhrRequestController.onRequest = async function({ request, requestId }) { + const controller = new (0, _chunkFGSEOIC4js.RequestController)(request); + this.logger.info("awaiting mocked response..."); + this.logger.info( + 'emitting the "request" event for %s listener(s)...', + emitter.listenerCount("request") + ); + const isRequestHandled = await _chunkFGSEOIC4js.handleRequest.call(void 0, { + request, + requestId, + controller, + emitter, + onResponse: async (response) => { + await this.respondWith(response); + }, + onRequestError: () => { + this.errorWith(new TypeError("Network error")); + }, + onError: (error) => { + this.logger.info("request errored!", { error }); + if (error instanceof Error) { + this.errorWith(error); + } + } + }); + if (!isRequestHandled) { + this.logger.info( + "no mocked response received, performing request as-is..." + ); + } + }; + xhrRequestController.onResponse = async function({ + response, + isMockedResponse, + request, + requestId + }) { + this.logger.info( + 'emitting the "response" event for %s listener(s)...', + emitter.listenerCount("response") + ); + emitter.emit("response", { + response, + isMockedResponse, + request, + requestId + }); + }; + return xhrRequestController.request; + } + }); + return XMLHttpRequestProxy; +} + +// src/interceptors/XMLHttpRequest/index.ts +var _XMLHttpRequestInterceptor = class extends _chunkTIPR373Rjs.Interceptor { + constructor() { + super(_XMLHttpRequestInterceptor.interceptorSymbol); + } + checkEnvironment() { + return _chunkPFGO5BSMjs.hasConfigurableGlobal.call(void 0, "XMLHttpRequest"); + } + setup() { + const logger = this.logger.extend("setup"); + logger.info('patching "XMLHttpRequest" module...'); + const PureXMLHttpRequest = globalThis.XMLHttpRequest; + _outvariant.invariant.call(void 0, + !PureXMLHttpRequest[_chunkBC2BLJQNjs.IS_PATCHED_MODULE], + 'Failed to patch the "XMLHttpRequest" module: already patched.' + ); + globalThis.XMLHttpRequest = createXMLHttpRequestProxy({ + emitter: this.emitter, + logger: this.logger + }); + logger.info( + 'native "XMLHttpRequest" module patched!', + globalThis.XMLHttpRequest.name + ); + Object.defineProperty(globalThis.XMLHttpRequest, _chunkBC2BLJQNjs.IS_PATCHED_MODULE, { + enumerable: true, + configurable: true, + value: true + }); + this.subscriptions.push(() => { + Object.defineProperty(globalThis.XMLHttpRequest, _chunkBC2BLJQNjs.IS_PATCHED_MODULE, { + value: void 0 + }); + globalThis.XMLHttpRequest = PureXMLHttpRequest; + logger.info( + 'native "XMLHttpRequest" module restored!', + globalThis.XMLHttpRequest.name + ); + }); + } +}; +var XMLHttpRequestInterceptor = _XMLHttpRequestInterceptor; +XMLHttpRequestInterceptor.interceptorSymbol = Symbol("xhr"); + + + +exports.XMLHttpRequestInterceptor = XMLHttpRequestInterceptor; +//# sourceMappingURL=chunk-ZIT2QX7D.js.map \ No newline at end of file diff --git a/node_modules/@mswjs/interceptors/lib/browser/chunk-ZIT2QX7D.js.map b/node_modules/@mswjs/interceptors/lib/browser/chunk-ZIT2QX7D.js.map new file mode 100644 index 0000000000000000000000000000000000000000..dcd5d0b31b357e198244c80da143f952a0b74c92 --- /dev/null +++ b/node_modules/@mswjs/interceptors/lib/browser/chunk-ZIT2QX7D.js.map @@ -0,0 +1 @@ +{"version":3,"sources":["../../src/interceptors/XMLHttpRequest/index.ts","../../src/interceptors/XMLHttpRequest/XMLHttpRequestController.ts","../../src/interceptors/XMLHttpRequest/utils/concatArrayBuffer.ts","../../src/interceptors/XMLHttpRequest/polyfills/EventPolyfill.ts","../../src/interceptors/XMLHttpRequest/polyfills/ProgressEventPolyfill.ts","../../src/interceptors/XMLHttpRequest/utils/createEvent.ts","../../src/utils/findPropertySource.ts","../../src/utils/createProxy.ts","../../src/interceptors/XMLHttpRequest/utils/isDomParserSupportedType.ts","../../src/utils/parseJson.ts","../../src/interceptors/XMLHttpRequest/utils/createResponse.ts","../../src/interceptors/XMLHttpRequest/utils/getBodyByteLength.ts","../../src/interceptors/XMLHttpRequest/XMLHttpRequestProxy.ts"],"names":["invariant","next"],"mappings":"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","sourcesContent":["import { invariant } from 'outvariant'\nimport { Emitter } from 'strict-event-emitter'\nimport { HttpRequestEventMap, IS_PATCHED_MODULE } from '../../glossary'\nimport { Interceptor } from '../../Interceptor'\nimport { createXMLHttpRequestProxy } from './XMLHttpRequestProxy'\nimport { hasConfigurableGlobal } from '../../utils/hasConfigurableGlobal'\n\nexport type XMLHttpRequestEmitter = Emitter\n\nexport class XMLHttpRequestInterceptor extends Interceptor {\n static interceptorSymbol = Symbol('xhr')\n\n constructor() {\n super(XMLHttpRequestInterceptor.interceptorSymbol)\n }\n\n protected checkEnvironment() {\n return hasConfigurableGlobal('XMLHttpRequest')\n }\n\n protected setup() {\n const logger = this.logger.extend('setup')\n\n logger.info('patching \"XMLHttpRequest\" module...')\n\n const PureXMLHttpRequest = globalThis.XMLHttpRequest\n\n invariant(\n !(PureXMLHttpRequest as any)[IS_PATCHED_MODULE],\n 'Failed to patch the \"XMLHttpRequest\" module: already patched.'\n )\n\n globalThis.XMLHttpRequest = createXMLHttpRequestProxy({\n emitter: this.emitter,\n logger: this.logger,\n })\n\n logger.info(\n 'native \"XMLHttpRequest\" module patched!',\n globalThis.XMLHttpRequest.name\n )\n\n Object.defineProperty(globalThis.XMLHttpRequest, IS_PATCHED_MODULE, {\n enumerable: true,\n configurable: true,\n value: true,\n })\n\n this.subscriptions.push(() => {\n Object.defineProperty(globalThis.XMLHttpRequest, IS_PATCHED_MODULE, {\n value: undefined,\n })\n\n globalThis.XMLHttpRequest = PureXMLHttpRequest\n logger.info(\n 'native \"XMLHttpRequest\" module restored!',\n globalThis.XMLHttpRequest.name\n )\n })\n }\n}\n","import { invariant } from 'outvariant'\nimport { isNodeProcess } from 'is-node-process'\nimport type { Logger } from '@open-draft/logger'\nimport { concatArrayBuffer } from './utils/concatArrayBuffer'\nimport { createEvent } from './utils/createEvent'\nimport {\n decodeBuffer,\n encodeBuffer,\n toArrayBuffer,\n} from '../../utils/bufferUtils'\nimport { createProxy } from '../../utils/createProxy'\nimport { isDomParserSupportedType } from './utils/isDomParserSupportedType'\nimport { parseJson } from '../../utils/parseJson'\nimport { createResponse } from './utils/createResponse'\nimport { INTERNAL_REQUEST_ID_HEADER_NAME } from '../../Interceptor'\nimport { createRequestId } from '../../createRequestId'\nimport { getBodyByteLength } from './utils/getBodyByteLength'\n\nconst kIsRequestHandled = Symbol('kIsRequestHandled')\nconst IS_NODE = isNodeProcess()\nconst kFetchRequest = Symbol('kFetchRequest')\n\n/**\n * An `XMLHttpRequest` instance controller that allows us\n * to handle any given request instance (e.g. responding to it).\n */\nexport class XMLHttpRequestController {\n public request: XMLHttpRequest\n public requestId: string\n public onRequest?: (\n this: XMLHttpRequestController,\n args: {\n request: Request\n requestId: string\n }\n ) => Promise\n public onResponse?: (\n this: XMLHttpRequestController,\n args: {\n response: Response\n isMockedResponse: boolean\n request: Request\n requestId: string\n }\n ) => void;\n\n [kIsRequestHandled]: boolean;\n [kFetchRequest]?: Request\n private method: string = 'GET'\n private url: URL = null as any\n private requestHeaders: Headers\n private responseBuffer: Uint8Array\n private events: Map>\n private uploadEvents: Map<\n keyof XMLHttpRequestEventTargetEventMap,\n Array\n >\n\n constructor(readonly initialRequest: XMLHttpRequest, public logger: Logger) {\n this[kIsRequestHandled] = false\n\n this.events = new Map()\n this.uploadEvents = new Map()\n this.requestId = createRequestId()\n this.requestHeaders = new Headers()\n this.responseBuffer = new Uint8Array()\n\n this.request = createProxy(initialRequest, {\n setProperty: ([propertyName, nextValue], invoke) => {\n switch (propertyName) {\n case 'ontimeout': {\n const eventName = propertyName.slice(\n 2\n ) as keyof XMLHttpRequestEventTargetEventMap\n\n /**\n * @note Proxy callbacks to event listeners because JSDOM has trouble\n * translating these properties to callbacks. It seemed to be operating\n * on events exclusively.\n */\n this.request.addEventListener(eventName, nextValue as any)\n\n return invoke()\n }\n\n default: {\n return invoke()\n }\n }\n },\n methodCall: ([methodName, args], invoke) => {\n switch (methodName) {\n case 'open': {\n const [method, url] = args as [string, string | undefined]\n\n if (typeof url === 'undefined') {\n this.method = 'GET'\n this.url = toAbsoluteUrl(method)\n } else {\n this.method = method\n this.url = toAbsoluteUrl(url)\n }\n\n this.logger = this.logger.extend(`${this.method} ${this.url.href}`)\n this.logger.info('open', this.method, this.url.href)\n\n return invoke()\n }\n\n case 'addEventListener': {\n const [eventName, listener] = args as [\n keyof XMLHttpRequestEventTargetEventMap,\n Function\n ]\n\n this.registerEvent(eventName, listener)\n this.logger.info('addEventListener', eventName, listener)\n\n return invoke()\n }\n\n case 'setRequestHeader': {\n const [name, value] = args as [string, string]\n this.requestHeaders.set(name, value)\n\n this.logger.info('setRequestHeader', name, value)\n\n return invoke()\n }\n\n case 'send': {\n const [body] = args as [\n body?: XMLHttpRequestBodyInit | Document | null\n ]\n\n this.request.addEventListener('load', () => {\n if (typeof this.onResponse !== 'undefined') {\n // Create a Fetch API Response representation of whichever\n // response this XMLHttpRequest received. Note those may\n // be either a mocked and the original response.\n const fetchResponse = createResponse(\n this.request,\n /**\n * The `response` property is the right way to read\n * the ambiguous response body, as the request's \"responseType\" may differ.\n * @see https://xhr.spec.whatwg.org/#the-response-attribute\n */\n this.request.response\n )\n\n // Notify the consumer about the response.\n this.onResponse.call(this, {\n response: fetchResponse,\n isMockedResponse: this[kIsRequestHandled],\n request: fetchRequest,\n requestId: this.requestId!,\n })\n }\n })\n\n const requestBody =\n typeof body === 'string' ? encodeBuffer(body) : body\n\n // Delegate request handling to the consumer.\n const fetchRequest = this.toFetchApiRequest(requestBody)\n this[kFetchRequest] = fetchRequest.clone()\n\n const onceRequestSettled =\n this.onRequest?.call(this, {\n request: fetchRequest,\n requestId: this.requestId!,\n }) || Promise.resolve()\n\n onceRequestSettled.finally(() => {\n // If the consumer didn't handle the request (called `.respondWith()`) perform it as-is.\n if (!this[kIsRequestHandled]) {\n this.logger.info(\n 'request callback settled but request has not been handled (readystate %d), performing as-is...',\n this.request.readyState\n )\n\n /**\n * @note Set the intercepted request ID on the original request in Node.js\n * so that if it triggers any other interceptors, they don't attempt\n * to process it once again.\n *\n * For instance, XMLHttpRequest is often implemented via \"http.ClientRequest\"\n * and we don't want for both XHR and ClientRequest interceptors to\n * handle the same request at the same time (e.g. emit the \"response\" event twice).\n */\n if (IS_NODE) {\n this.request.setRequestHeader(\n INTERNAL_REQUEST_ID_HEADER_NAME,\n this.requestId!\n )\n }\n\n return invoke()\n }\n })\n\n break\n }\n\n default: {\n return invoke()\n }\n }\n },\n })\n\n /**\n * Proxy the `.upload` property to gather the event listeners/callbacks.\n */\n define(\n this.request,\n 'upload',\n createProxy(this.request.upload, {\n setProperty: ([propertyName, nextValue], invoke) => {\n switch (propertyName) {\n case 'onloadstart':\n case 'onprogress':\n case 'onaboart':\n case 'onerror':\n case 'onload':\n case 'ontimeout':\n case 'onloadend': {\n const eventName = propertyName.slice(\n 2\n ) as keyof XMLHttpRequestEventTargetEventMap\n\n this.registerUploadEvent(eventName, nextValue as Function)\n }\n }\n\n return invoke()\n },\n methodCall: ([methodName, args], invoke) => {\n switch (methodName) {\n case 'addEventListener': {\n const [eventName, listener] = args as [\n keyof XMLHttpRequestEventTargetEventMap,\n Function\n ]\n this.registerUploadEvent(eventName, listener)\n this.logger.info('upload.addEventListener', eventName, listener)\n\n return invoke()\n }\n }\n },\n })\n )\n }\n\n private registerEvent(\n eventName: keyof XMLHttpRequestEventTargetEventMap,\n listener: Function\n ): void {\n const prevEvents = this.events.get(eventName) || []\n const nextEvents = prevEvents.concat(listener)\n this.events.set(eventName, nextEvents)\n\n this.logger.info('registered event \"%s\"', eventName, listener)\n }\n\n private registerUploadEvent(\n eventName: keyof XMLHttpRequestEventTargetEventMap,\n listener: Function\n ): void {\n const prevEvents = this.uploadEvents.get(eventName) || []\n const nextEvents = prevEvents.concat(listener)\n this.uploadEvents.set(eventName, nextEvents)\n\n this.logger.info('registered upload event \"%s\"', eventName, listener)\n }\n\n /**\n * Responds to the current request with the given\n * Fetch API `Response` instance.\n */\n public async respondWith(response: Response): Promise {\n /**\n * @note Since `XMLHttpRequestController` delegates the handling of the responses\n * to the \"load\" event listener that doesn't distinguish between the mocked and original\n * responses, mark the request that had a mocked response with a corresponding symbol.\n *\n * Mark this request as having a mocked response immediately since\n * calculating request/response total body length is asynchronous.\n */\n this[kIsRequestHandled] = true\n\n /**\n * Dispatch request upload events for requests with a body.\n * @see https://github.com/mswjs/interceptors/issues/573\n */\n if (this[kFetchRequest]) {\n const totalRequestBodyLength = await getBodyByteLength(\n this[kFetchRequest]\n )\n\n this.trigger('loadstart', this.request.upload, {\n loaded: 0,\n total: totalRequestBodyLength,\n })\n this.trigger('progress', this.request.upload, {\n loaded: totalRequestBodyLength,\n total: totalRequestBodyLength,\n })\n this.trigger('load', this.request.upload, {\n loaded: totalRequestBodyLength,\n total: totalRequestBodyLength,\n })\n this.trigger('loadend', this.request.upload, {\n loaded: totalRequestBodyLength,\n total: totalRequestBodyLength,\n })\n }\n\n this.logger.info(\n 'responding with a mocked response: %d %s',\n response.status,\n response.statusText\n )\n\n define(this.request, 'status', response.status)\n define(this.request, 'statusText', response.statusText)\n define(this.request, 'responseURL', this.url.href)\n\n this.request.getResponseHeader = new Proxy(this.request.getResponseHeader, {\n apply: (_, __, args: [name: string]) => {\n this.logger.info('getResponseHeader', args[0])\n\n if (this.request.readyState < this.request.HEADERS_RECEIVED) {\n this.logger.info('headers not received yet, returning null')\n\n // Headers not received yet, nothing to return.\n return null\n }\n\n const headerValue = response.headers.get(args[0])\n this.logger.info(\n 'resolved response header \"%s\" to',\n args[0],\n headerValue\n )\n\n return headerValue\n },\n })\n\n this.request.getAllResponseHeaders = new Proxy(\n this.request.getAllResponseHeaders,\n {\n apply: () => {\n this.logger.info('getAllResponseHeaders')\n\n if (this.request.readyState < this.request.HEADERS_RECEIVED) {\n this.logger.info('headers not received yet, returning empty string')\n\n // Headers not received yet, nothing to return.\n return ''\n }\n\n const headersList = Array.from(response.headers.entries())\n const allHeaders = headersList\n .map(([headerName, headerValue]) => {\n return `${headerName}: ${headerValue}`\n })\n .join('\\r\\n')\n\n this.logger.info('resolved all response headers to', allHeaders)\n\n return allHeaders\n },\n }\n )\n\n // Update the response getters to resolve against the mocked response.\n Object.defineProperties(this.request, {\n response: {\n enumerable: true,\n configurable: false,\n get: () => this.response,\n },\n responseText: {\n enumerable: true,\n configurable: false,\n get: () => this.responseText,\n },\n responseXML: {\n enumerable: true,\n configurable: false,\n get: () => this.responseXML,\n },\n })\n\n const totalResponseBodyLength = await getBodyByteLength(response.clone())\n\n this.logger.info('calculated response body length', totalResponseBodyLength)\n\n this.trigger('loadstart', this.request, {\n loaded: 0,\n total: totalResponseBodyLength,\n })\n\n this.setReadyState(this.request.HEADERS_RECEIVED)\n this.setReadyState(this.request.LOADING)\n\n const finalizeResponse = () => {\n this.logger.info('finalizing the mocked response...')\n\n this.setReadyState(this.request.DONE)\n\n this.trigger('load', this.request, {\n loaded: this.responseBuffer.byteLength,\n total: totalResponseBodyLength,\n })\n\n this.trigger('loadend', this.request, {\n loaded: this.responseBuffer.byteLength,\n total: totalResponseBodyLength,\n })\n }\n\n if (response.body) {\n this.logger.info('mocked response has body, streaming...')\n\n const reader = response.body.getReader()\n\n const readNextResponseBodyChunk = async () => {\n const { value, done } = await reader.read()\n\n if (done) {\n this.logger.info('response body stream done!')\n finalizeResponse()\n return\n }\n\n if (value) {\n this.logger.info('read response body chunk:', value)\n this.responseBuffer = concatArrayBuffer(this.responseBuffer, value)\n\n this.trigger('progress', this.request, {\n loaded: this.responseBuffer.byteLength,\n total: totalResponseBodyLength,\n })\n }\n\n readNextResponseBodyChunk()\n }\n\n readNextResponseBodyChunk()\n } else {\n finalizeResponse()\n }\n }\n\n private responseBufferToText(): string {\n return decodeBuffer(this.responseBuffer)\n }\n\n get response(): unknown {\n this.logger.info(\n 'getResponse (responseType: %s)',\n this.request.responseType\n )\n\n if (this.request.readyState !== this.request.DONE) {\n return null\n }\n\n switch (this.request.responseType) {\n case 'json': {\n const responseJson = parseJson(this.responseBufferToText())\n this.logger.info('resolved response JSON', responseJson)\n\n return responseJson\n }\n\n case 'arraybuffer': {\n const arrayBuffer = toArrayBuffer(this.responseBuffer)\n this.logger.info('resolved response ArrayBuffer', arrayBuffer)\n\n return arrayBuffer\n }\n\n case 'blob': {\n const mimeType =\n this.request.getResponseHeader('Content-Type') || 'text/plain'\n const responseBlob = new Blob([this.responseBufferToText()], {\n type: mimeType,\n })\n\n this.logger.info(\n 'resolved response Blob (mime type: %s)',\n responseBlob,\n mimeType\n )\n\n return responseBlob\n }\n\n default: {\n const responseText = this.responseBufferToText()\n this.logger.info(\n 'resolving \"%s\" response type as text',\n this.request.responseType,\n responseText\n )\n\n return responseText\n }\n }\n }\n\n get responseText(): string {\n /**\n * Throw when trying to read the response body as text when the\n * \"responseType\" doesn't expect text. This just respects the spec better.\n * @see https://xhr.spec.whatwg.org/#the-responsetext-attribute\n */\n invariant(\n this.request.responseType === '' || this.request.responseType === 'text',\n 'InvalidStateError: The object is in invalid state.'\n )\n\n if (\n this.request.readyState !== this.request.LOADING &&\n this.request.readyState !== this.request.DONE\n ) {\n return ''\n }\n\n const responseText = this.responseBufferToText()\n this.logger.info('getResponseText: \"%s\"', responseText)\n\n return responseText\n }\n\n get responseXML(): Document | null {\n invariant(\n this.request.responseType === '' ||\n this.request.responseType === 'document',\n 'InvalidStateError: The object is in invalid state.'\n )\n\n if (this.request.readyState !== this.request.DONE) {\n return null\n }\n\n const contentType = this.request.getResponseHeader('Content-Type') || ''\n\n if (typeof DOMParser === 'undefined') {\n console.warn(\n 'Cannot retrieve XMLHttpRequest response body as XML: DOMParser is not defined. You are likely using an environment that is not browser or does not polyfill browser globals correctly.'\n )\n return null\n }\n\n if (isDomParserSupportedType(contentType)) {\n return new DOMParser().parseFromString(\n this.responseBufferToText(),\n contentType\n )\n }\n\n return null\n }\n\n public errorWith(error?: Error): void {\n /**\n * @note Mark this request as handled even if it received a mock error.\n * This prevents the controller from trying to perform this request as-is.\n */\n this[kIsRequestHandled] = true\n this.logger.info('responding with an error')\n\n this.setReadyState(this.request.DONE)\n this.trigger('error', this.request)\n this.trigger('loadend', this.request)\n }\n\n /**\n * Transitions this request's `readyState` to the given one.\n */\n private setReadyState(nextReadyState: number): void {\n this.logger.info(\n 'setReadyState: %d -> %d',\n this.request.readyState,\n nextReadyState\n )\n\n if (this.request.readyState === nextReadyState) {\n this.logger.info('ready state identical, skipping transition...')\n return\n }\n\n define(this.request, 'readyState', nextReadyState)\n\n this.logger.info('set readyState to: %d', nextReadyState)\n\n if (nextReadyState !== this.request.UNSENT) {\n this.logger.info('triggerring \"readystatechange\" event...')\n\n this.trigger('readystatechange', this.request)\n }\n }\n\n /**\n * Triggers given event on the `XMLHttpRequest` instance.\n */\n private trigger<\n EventName extends keyof (XMLHttpRequestEventTargetEventMap & {\n readystatechange: ProgressEvent\n })\n >(\n eventName: EventName,\n target: XMLHttpRequest | XMLHttpRequestUpload,\n options?: ProgressEventInit\n ): void {\n const callback = (target as XMLHttpRequest)[`on${eventName}`]\n const event = createEvent(target, eventName, options)\n\n this.logger.info('trigger \"%s\"', eventName, options || '')\n\n // Invoke direct callbacks.\n if (typeof callback === 'function') {\n this.logger.info('found a direct \"%s\" callback, calling...', eventName)\n callback.call(target as XMLHttpRequest, event)\n }\n\n // Invoke event listeners.\n const events =\n target instanceof XMLHttpRequestUpload ? this.uploadEvents : this.events\n\n for (const [registeredEventName, listeners] of events) {\n if (registeredEventName === eventName) {\n this.logger.info(\n 'found %d listener(s) for \"%s\" event, calling...',\n listeners.length,\n eventName\n )\n\n listeners.forEach((listener) => listener.call(target, event))\n }\n }\n }\n\n /**\n * Converts this `XMLHttpRequest` instance into a Fetch API `Request` instance.\n */\n private toFetchApiRequest(\n body: XMLHttpRequestBodyInit | Document | null | undefined\n ): Request {\n this.logger.info('converting request to a Fetch API Request...')\n\n // If the `Document` is used as the body of this XMLHttpRequest,\n // set its inner text as the Fetch API Request body.\n const resolvedBody =\n body instanceof Document ? body.documentElement.innerText : body\n\n const fetchRequest = new Request(this.url.href, {\n method: this.method,\n headers: this.requestHeaders,\n /**\n * @see https://xhr.spec.whatwg.org/#cross-origin-credentials\n */\n credentials: this.request.withCredentials ? 'include' : 'same-origin',\n body: ['GET', 'HEAD'].includes(this.method.toUpperCase())\n ? null\n : resolvedBody,\n })\n\n const proxyHeaders = createProxy(fetchRequest.headers, {\n methodCall: ([methodName, args], invoke) => {\n // Forward the latest state of the internal request headers\n // because the interceptor might have modified them\n // without responding to the request.\n switch (methodName) {\n case 'append':\n case 'set': {\n const [headerName, headerValue] = args as [string, string]\n this.request.setRequestHeader(headerName, headerValue)\n break\n }\n\n case 'delete': {\n const [headerName] = args as [string]\n console.warn(\n `XMLHttpRequest: Cannot remove a \"${headerName}\" header from the Fetch API representation of the \"${fetchRequest.method} ${fetchRequest.url}\" request. XMLHttpRequest headers cannot be removed.`\n )\n break\n }\n }\n\n return invoke()\n },\n })\n define(fetchRequest, 'headers', proxyHeaders)\n\n this.logger.info('converted request to a Fetch API Request!', fetchRequest)\n\n return fetchRequest\n }\n}\n\nfunction toAbsoluteUrl(url: string | URL): URL {\n /**\n * @note XMLHttpRequest interceptor may run in environments\n * that implement XMLHttpRequest but don't implement \"location\"\n * (for example, React Native). If that's the case, return the\n * input URL as-is (nothing to be relative to).\n * @see https://github.com/mswjs/msw/issues/1777\n */\n if (typeof location === 'undefined') {\n return new URL(url)\n }\n\n return new URL(url.toString(), location.href)\n}\n\nfunction define(\n target: object,\n property: string | symbol,\n value: unknown\n): void {\n Reflect.defineProperty(target, property, {\n // Ensure writable properties to allow redefining readonly properties.\n writable: true,\n enumerable: true,\n value,\n })\n}\n","/**\n * Concatenate two `Uint8Array` buffers.\n */\nexport function concatArrayBuffer(\n left: Uint8Array,\n right: Uint8Array\n): Uint8Array {\n const result = new Uint8Array(left.byteLength + right.byteLength)\n result.set(left, 0)\n result.set(right, left.byteLength)\n return result\n}\n","export class EventPolyfill implements Event {\n readonly NONE = 0\n readonly CAPTURING_PHASE = 1\n readonly AT_TARGET = 2\n readonly BUBBLING_PHASE = 3\n\n public type: string = ''\n public srcElement: EventTarget | null = null\n public target: EventTarget | null\n public currentTarget: EventTarget | null = null\n public eventPhase: number = 0\n public timeStamp: number\n public isTrusted: boolean = true\n public composed: boolean = false\n public cancelable: boolean = true\n public defaultPrevented: boolean = false\n public bubbles: boolean = true\n public lengthComputable: boolean = true\n public loaded: number = 0\n public total: number = 0\n\n cancelBubble: boolean = false\n returnValue: boolean = true\n\n constructor(\n type: string,\n options?: { target: EventTarget; currentTarget: EventTarget }\n ) {\n this.type = type\n this.target = options?.target || null\n this.currentTarget = options?.currentTarget || null\n this.timeStamp = Date.now()\n }\n\n public composedPath(): EventTarget[] {\n return []\n }\n\n public initEvent(type: string, bubbles?: boolean, cancelable?: boolean) {\n this.type = type\n this.bubbles = !!bubbles\n this.cancelable = !!cancelable\n }\n\n public preventDefault() {\n this.defaultPrevented = true\n }\n\n public stopPropagation() {}\n public stopImmediatePropagation() {}\n}\n","import { EventPolyfill } from './EventPolyfill'\n\nexport class ProgressEventPolyfill extends EventPolyfill {\n readonly lengthComputable: boolean\n readonly composed: boolean\n readonly loaded: number\n readonly total: number\n\n constructor(type: string, init?: ProgressEventInit) {\n super(type)\n\n this.lengthComputable = init?.lengthComputable || false\n this.composed = init?.composed || false\n this.loaded = init?.loaded || 0\n this.total = init?.total || 0\n }\n}\n","import { EventPolyfill } from '../polyfills/EventPolyfill'\nimport { ProgressEventPolyfill } from '../polyfills/ProgressEventPolyfill'\n\nconst SUPPORTS_PROGRESS_EVENT = typeof ProgressEvent !== 'undefined'\n\nexport function createEvent(\n target: XMLHttpRequest | XMLHttpRequestUpload,\n type: string,\n init?: ProgressEventInit\n): EventPolyfill | ProgressEvent {\n const progressEvents = [\n 'error',\n 'progress',\n 'loadstart',\n 'loadend',\n 'load',\n 'timeout',\n 'abort',\n ]\n\n /**\n * `ProgressEvent` is not supported in React Native.\n * @see https://github.com/mswjs/interceptors/issues/40\n */\n const ProgressEventClass = SUPPORTS_PROGRESS_EVENT\n ? ProgressEvent\n : ProgressEventPolyfill\n\n const event = progressEvents.includes(type)\n ? new ProgressEventClass(type, {\n lengthComputable: true,\n loaded: init?.loaded || 0,\n total: init?.total || 0,\n })\n : new EventPolyfill(type, {\n target,\n currentTarget: target,\n })\n\n return event\n}\n","/**\n * Returns the source object of the given property on the target object\n * (the target itself, any parent in its prototype, or null).\n */\nexport function findPropertySource(\n target: object,\n propertyName: string | symbol\n): object | null {\n if (!(propertyName in target)) {\n return null\n }\n\n const hasProperty = Object.prototype.hasOwnProperty.call(target, propertyName)\n if (hasProperty) {\n return target\n }\n\n const prototype = Reflect.getPrototypeOf(target)\n return prototype ? findPropertySource(prototype, propertyName) : null\n}\n","import { findPropertySource } from './findPropertySource'\n\nexport interface ProxyOptions> {\n constructorCall?(args: Array, next: NextFunction): Target\n\n methodCall?(\n this: Target,\n data: [methodName: F, args: Array],\n next: NextFunction\n ): void\n\n setProperty?(\n data: [propertyName: string | symbol, nextValue: unknown],\n next: NextFunction\n ): boolean\n\n getProperty?(\n data: [propertyName: string | symbol, receiver: Target],\n next: NextFunction\n ): void\n}\n\nexport type NextFunction = () => ReturnType\n\nexport function createProxy(\n target: Target,\n options: ProxyOptions\n): Target {\n const proxy = new Proxy(target, optionsToProxyHandler(options))\n\n return proxy\n}\n\nfunction optionsToProxyHandler>(\n options: ProxyOptions\n): ProxyHandler {\n const { constructorCall, methodCall, getProperty, setProperty } = options\n const handler: ProxyHandler = {}\n\n if (typeof constructorCall !== 'undefined') {\n handler.construct = function (target, args, newTarget) {\n const next = Reflect.construct.bind(null, target as any, args, newTarget)\n return constructorCall.call(newTarget, args, next)\n }\n }\n\n handler.set = function (target, propertyName, nextValue) {\n const next = () => {\n const propertySource = findPropertySource(target, propertyName) || target\n const ownDescriptors = Reflect.getOwnPropertyDescriptor(\n propertySource,\n propertyName\n )\n\n // Respect any custom setters present for this property.\n if (typeof ownDescriptors?.set !== 'undefined') {\n ownDescriptors.set.apply(target, [nextValue])\n return true\n }\n\n // Otherwise, set the property on the source.\n return Reflect.defineProperty(propertySource, propertyName, {\n writable: true,\n enumerable: true,\n configurable: true,\n value: nextValue,\n })\n }\n\n if (typeof setProperty !== 'undefined') {\n return setProperty.call(target, [propertyName, nextValue], next)\n }\n\n return next()\n }\n\n handler.get = function (target, propertyName, receiver) {\n /**\n * @note Using `Reflect.get()` here causes \"TypeError: Illegal invocation\".\n */\n const next = () => target[propertyName as any]\n\n const value =\n typeof getProperty !== 'undefined'\n ? getProperty.call(target, [propertyName, receiver], next)\n : next()\n\n if (typeof value === 'function') {\n return (...args: Array) => {\n const next = value.bind(target, ...args)\n\n if (typeof methodCall !== 'undefined') {\n return methodCall.call(target, [propertyName as any, args], next)\n }\n\n return next()\n }\n }\n\n return value\n }\n\n return handler\n}\n","export function isDomParserSupportedType(\n type: string\n): type is DOMParserSupportedType {\n const supportedTypes: Array = [\n 'application/xhtml+xml',\n 'application/xml',\n 'image/svg+xml',\n 'text/html',\n 'text/xml',\n ]\n return supportedTypes.some((supportedType) => {\n return type.startsWith(supportedType)\n })\n}\n","/**\n * Parses a given string into JSON.\n * Gracefully handles invalid JSON by returning `null`.\n */\nexport function parseJson(data: string): Record | null {\n try {\n const json = JSON.parse(data)\n return json\n } catch (_) {\n return null\n }\n}\n","import { FetchResponse } from '../../../utils/fetchUtils'\n\n/**\n * Creates a Fetch API `Response` instance from the given\n * `XMLHttpRequest` instance and a response body.\n */\nexport function createResponse(\n request: XMLHttpRequest,\n body: BodyInit | null\n): Response {\n /**\n * Handle XMLHttpRequest responses that must have null as the\n * response body when represented using Fetch API Response.\n * XMLHttpRequest response will always have an empty string\n * as the \"request.response\" in those cases, resulting in an error\n * when constructing a Response instance.\n * @see https://github.com/mswjs/interceptors/issues/379\n */\n const responseBodyOrNull = FetchResponse.isResponseWithBody(request.status)\n ? body\n : null\n\n return new FetchResponse(responseBodyOrNull, {\n url: request.responseURL,\n status: request.status,\n statusText: request.statusText,\n headers: createHeadersFromXMLHttpReqestHeaders(\n request.getAllResponseHeaders()\n ),\n })\n}\n\nfunction createHeadersFromXMLHttpReqestHeaders(headersString: string): Headers {\n const headers = new Headers()\n\n const lines = headersString.split(/[\\r\\n]+/)\n for (const line of lines) {\n if (line.trim() === '') {\n continue\n }\n\n const [name, ...parts] = line.split(': ')\n const value = parts.join(': ')\n\n headers.append(name, value)\n }\n\n return headers\n}\n","/**\n * Return a total byte length of the given request/response body.\n * If the `Content-Length` header is present, it will be used as the byte length.\n */\nexport async function getBodyByteLength(\n input: Request | Response\n): Promise {\n const explicitContentLength = input.headers.get('content-length')\n\n if (explicitContentLength != null && explicitContentLength !== '') {\n return Number(explicitContentLength)\n }\n\n const buffer = await input.arrayBuffer()\n return buffer.byteLength\n}\n","import type { Logger } from '@open-draft/logger'\nimport { XMLHttpRequestEmitter } from '.'\nimport { RequestController } from '../../RequestController'\nimport { XMLHttpRequestController } from './XMLHttpRequestController'\nimport { handleRequest } from '../../utils/handleRequest'\n\nexport interface XMLHttpRequestProxyOptions {\n emitter: XMLHttpRequestEmitter\n logger: Logger\n}\n\n/**\n * Create a proxied `XMLHttpRequest` class.\n * The proxied class establishes spies on certain methods,\n * allowing us to intercept requests and respond to them.\n */\nexport function createXMLHttpRequestProxy({\n emitter,\n logger,\n}: XMLHttpRequestProxyOptions) {\n const XMLHttpRequestProxy = new Proxy(globalThis.XMLHttpRequest, {\n construct(target, args, newTarget) {\n logger.info('constructed new XMLHttpRequest')\n\n const originalRequest = Reflect.construct(\n target,\n args,\n newTarget\n ) as XMLHttpRequest\n\n /**\n * @note Forward prototype descriptors onto the proxied object.\n * XMLHttpRequest is implemented in JSDOM in a way that assigns\n * a bunch of descriptors, like \"set responseType()\" on the prototype.\n * With this propagation, we make sure that those descriptors trigger\n * when the user operates with the proxied request instance.\n */\n const prototypeDescriptors = Object.getOwnPropertyDescriptors(\n target.prototype\n )\n for (const propertyName in prototypeDescriptors) {\n Reflect.defineProperty(\n originalRequest,\n propertyName,\n prototypeDescriptors[propertyName]\n )\n }\n\n const xhrRequestController = new XMLHttpRequestController(\n originalRequest,\n logger\n )\n\n xhrRequestController.onRequest = async function ({ request, requestId }) {\n const controller = new RequestController(request)\n\n this.logger.info('awaiting mocked response...')\n\n this.logger.info(\n 'emitting the \"request\" event for %s listener(s)...',\n emitter.listenerCount('request')\n )\n\n const isRequestHandled = await handleRequest({\n request,\n requestId,\n controller,\n emitter,\n onResponse: async (response) => {\n await this.respondWith(response)\n },\n onRequestError: () => {\n this.errorWith(new TypeError('Network error'))\n },\n onError: (error) => {\n this.logger.info('request errored!', { error })\n\n if (error instanceof Error) {\n this.errorWith(error)\n }\n },\n })\n\n if (!isRequestHandled) {\n this.logger.info(\n 'no mocked response received, performing request as-is...'\n )\n }\n }\n\n xhrRequestController.onResponse = async function ({\n response,\n isMockedResponse,\n request,\n requestId,\n }) {\n this.logger.info(\n 'emitting the \"response\" event for %s listener(s)...',\n emitter.listenerCount('response')\n )\n\n emitter.emit('response', {\n response,\n isMockedResponse,\n request,\n requestId,\n })\n }\n\n // Return the proxied request from the controller\n // so that the controller can react to the consumer's interactions\n // with this request (opening/sending/etc).\n return xhrRequestController.request\n },\n })\n\n return XMLHttpRequestProxy\n}\n"]} \ No newline at end of file diff --git a/node_modules/@mswjs/interceptors/lib/browser/glossary-6564c252.d.ts b/node_modules/@mswjs/interceptors/lib/browser/glossary-6564c252.d.ts new file mode 100644 index 0000000000000000000000000000000000000000..8a08d254a708043e100e78930f3b6e15f84833f2 --- /dev/null +++ b/node_modules/@mswjs/interceptors/lib/browser/glossary-6564c252.d.ts @@ -0,0 +1,67 @@ +import { DeferredPromise } from '@open-draft/deferred-promise'; + +declare const kRequestHandled: unique symbol; +declare const kResponsePromise: unique symbol; +declare class RequestController { + private request; + /** + * Internal response promise. + * Available only for the library internals to grab the + * response instance provided by the developer. + * @note This promise cannot be rejected. It's either infinitely + * pending or resolved with whichever Response was passed to `respondWith()`. + */ + [kResponsePromise]: DeferredPromise; + /** + * Internal flag indicating if this request has been handled. + * @note The response promise becomes "fulfilled" on the next tick. + */ + [kRequestHandled]: boolean; + constructor(request: Request); + /** + * Respond to this request with the given `Response` instance. + * @example + * controller.respondWith(new Response()) + * controller.respondWith(Response.json({ id })) + * controller.respondWith(Response.error()) + */ + respondWith(response: Response): void; + /** + * Error this request with the given error. + * @example + * controller.errorWith() + * controller.errorWith(new Error('Oops!')) + */ + errorWith(error?: Error): void; +} + +declare const IS_PATCHED_MODULE: unique symbol; + +type RequestCredentials = 'omit' | 'include' | 'same-origin'; +type HttpRequestEventMap = { + request: [ + args: { + request: Request; + requestId: string; + controller: RequestController; + } + ]; + response: [ + args: { + response: Response; + isMockedResponse: boolean; + request: Request; + requestId: string; + } + ]; + unhandledException: [ + args: { + error: unknown; + request: Request; + requestId: string; + controller: RequestController; + } + ]; +}; + +export { HttpRequestEventMap as H, IS_PATCHED_MODULE as I, RequestController as R, RequestCredentials as a }; diff --git a/node_modules/@mswjs/interceptors/lib/browser/index.d.ts b/node_modules/@mswjs/interceptors/lib/browser/index.d.ts new file mode 100644 index 0000000000000000000000000000000000000000..dfd8e4852b10da7410a091266197b07a7b60d7fa --- /dev/null +++ b/node_modules/@mswjs/interceptors/lib/browser/index.d.ts @@ -0,0 +1,69 @@ +export { H as HttpRequestEventMap, I as IS_PATCHED_MODULE, R as RequestController, a as RequestCredentials } from './glossary-6564c252.js'; +import { I as Interceptor, E as ExtractEventNames } from './Interceptor-af98b768.js'; +export { c as INTERNAL_REQUEST_ID_HEADER_NAME, a as InterceptorEventMap, e as InterceptorReadyState, b as InterceptorSubscription, d as deleteGlobalSymbol, g as getGlobalSymbol } from './Interceptor-af98b768.js'; +import { EventMap, Listener } from 'strict-event-emitter'; +import '@open-draft/deferred-promise'; +import '@open-draft/logger'; + +interface BatchInterceptorOptions>> { + name: string; + interceptors: InterceptorList; +} +type ExtractEventMapType>> = InterceptorList extends ReadonlyArray ? InterceptorType extends Interceptor ? EventMap : never : never; +/** + * A batch interceptor that exposes a single interface + * to apply and operate with multiple interceptors at once. + */ +declare class BatchInterceptor>, Events extends EventMap = ExtractEventMapType> extends Interceptor { + static symbol: symbol; + private interceptors; + constructor(options: BatchInterceptorOptions); + protected setup(): void; + on>(event: EventName, listener: Listener): this; + once>(event: EventName, listener: Listener): this; + off>(event: EventName, listener: Listener): this; + removeAllListeners>(event?: EventName | undefined): this; +} + +/** + * Generate a random ID string to represent a request. + * @example + * createRequestId() + * // "f774b6c9c600f" + */ +declare function createRequestId(): string; + +/** + * Removes query parameters and hashes from a given URL. + */ +declare function getCleanUrl(url: URL, isAbsolute?: boolean): string; + +declare function encodeBuffer(text: string): Uint8Array; +declare function decodeBuffer(buffer: ArrayBuffer, encoding?: string): string; + +interface FetchResponseInit extends ResponseInit { + url?: string; +} +declare class FetchResponse extends Response { + /** + * Response status codes for responses that cannot have body. + * @see https://fetch.spec.whatwg.org/#statuses + */ + static readonly STATUS_CODES_WITHOUT_BODY: number[]; + static readonly STATUS_CODES_WITH_REDIRECT: number[]; + static isConfigurableStatusCode(status: number): boolean; + static isRedirectResponse(status: number): boolean; + /** + * Returns a boolean indicating whether the given response status + * code represents a response that can have a body. + */ + static isResponseWithBody(status: number): boolean; + static setUrl(url: string | undefined, response: Response): void; + /** + * Parses the given raw HTTP headers into a Fetch API `Headers` instance. + */ + static parseRawHeaders(rawHeaders: Array): Headers; + constructor(body?: BodyInit | null, init?: FetchResponseInit); +} + +export { BatchInterceptor, BatchInterceptorOptions, ExtractEventMapType, ExtractEventNames, FetchResponse, Interceptor, createRequestId, decodeBuffer, encodeBuffer, getCleanUrl }; diff --git a/node_modules/@mswjs/interceptors/lib/browser/index.js b/node_modules/@mswjs/interceptors/lib/browser/index.js new file mode 100644 index 0000000000000000000000000000000000000000..a8aaa1208af2c7687a5804d97dad835b6b6809f7 --- /dev/null +++ b/node_modules/@mswjs/interceptors/lib/browser/index.js @@ -0,0 +1,79 @@ +"use strict";Object.defineProperty(exports, "__esModule", {value: true}); + + +var _chunkLK6DILFKjs = require('./chunk-LK6DILFK.js'); + + + +var _chunkBC2BLJQNjs = require('./chunk-BC2BLJQN.js'); + + + + + + + +var _chunkTIPR373Rjs = require('./chunk-TIPR373R.js'); + +// src/BatchInterceptor.ts +var BatchInterceptor = class extends _chunkTIPR373Rjs.Interceptor { + constructor(options) { + BatchInterceptor.symbol = Symbol(options.name); + super(BatchInterceptor.symbol); + this.interceptors = options.interceptors; + } + setup() { + const logger = this.logger.extend("setup"); + logger.info("applying all %d interceptors...", this.interceptors.length); + for (const interceptor of this.interceptors) { + logger.info('applying "%s" interceptor...', interceptor.constructor.name); + interceptor.apply(); + logger.info("adding interceptor dispose subscription"); + this.subscriptions.push(() => interceptor.dispose()); + } + } + on(event, listener) { + for (const interceptor of this.interceptors) { + interceptor.on(event, listener); + } + return this; + } + once(event, listener) { + for (const interceptor of this.interceptors) { + interceptor.once(event, listener); + } + return this; + } + off(event, listener) { + for (const interceptor of this.interceptors) { + interceptor.off(event, listener); + } + return this; + } + removeAllListeners(event) { + for (const interceptors of this.interceptors) { + interceptors.removeAllListeners(event); + } + return this; + } +}; + +// src/utils/getCleanUrl.ts +function getCleanUrl(url, isAbsolute = true) { + return [isAbsolute && url.origin, url.pathname].filter(Boolean).join(""); +} + + + + + + + + + + + + + +exports.BatchInterceptor = BatchInterceptor; exports.FetchResponse = _chunkBC2BLJQNjs.FetchResponse; exports.INTERNAL_REQUEST_ID_HEADER_NAME = _chunkTIPR373Rjs.INTERNAL_REQUEST_ID_HEADER_NAME; exports.IS_PATCHED_MODULE = _chunkBC2BLJQNjs.IS_PATCHED_MODULE; exports.Interceptor = _chunkTIPR373Rjs.Interceptor; exports.InterceptorReadyState = _chunkTIPR373Rjs.InterceptorReadyState; exports.createRequestId = _chunkTIPR373Rjs.createRequestId; exports.decodeBuffer = _chunkLK6DILFKjs.decodeBuffer; exports.deleteGlobalSymbol = _chunkTIPR373Rjs.deleteGlobalSymbol; exports.encodeBuffer = _chunkLK6DILFKjs.encodeBuffer; exports.getCleanUrl = getCleanUrl; exports.getGlobalSymbol = _chunkTIPR373Rjs.getGlobalSymbol; +//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/node_modules/@mswjs/interceptors/lib/browser/index.js.map b/node_modules/@mswjs/interceptors/lib/browser/index.js.map new file mode 100644 index 0000000000000000000000000000000000000000..34e4b31b1d249cbb7ca34026baa30d81f8aadedd --- /dev/null +++ b/node_modules/@mswjs/interceptors/lib/browser/index.js.map @@ -0,0 +1 @@ +{"version":3,"sources":["../../src/BatchInterceptor.ts","../../src/utils/getCleanUrl.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;AAsBO,IAAM,mBAAN,cAGG,YAAoB;AAAA,EAK5B,YAAY,SAAmD;AAC7D,qBAAiB,SAAS,OAAO,QAAQ,IAAI;AAC7C,UAAM,iBAAiB,MAAM;AAC7B,SAAK,eAAe,QAAQ;AAAA,EAC9B;AAAA,EAEU,QAAQ;AAChB,UAAM,SAAS,KAAK,OAAO,OAAO,OAAO;AAEzC,WAAO,KAAK,mCAAmC,KAAK,aAAa,MAAM;AAEvE,eAAW,eAAe,KAAK,cAAc;AAC3C,aAAO,KAAK,gCAAgC,YAAY,YAAY,IAAI;AACxE,kBAAY,MAAM;AAElB,aAAO,KAAK,yCAAyC;AACrD,WAAK,cAAc,KAAK,MAAM,YAAY,QAAQ,CAAC;AAAA,IACrD;AAAA,EACF;AAAA,EAEO,GACL,OACA,UACM;AAGN,eAAW,eAAe,KAAK,cAAc;AAC3C,kBAAY,GAAG,OAAO,QAAQ;AAAA,IAChC;AAEA,WAAO;AAAA,EACT;AAAA,EAEO,KACL,OACA,UACM;AACN,eAAW,eAAe,KAAK,cAAc;AAC3C,kBAAY,KAAK,OAAO,QAAQ;AAAA,IAClC;AAEA,WAAO;AAAA,EACT;AAAA,EAEO,IACL,OACA,UACM;AACN,eAAW,eAAe,KAAK,cAAc;AAC3C,kBAAY,IAAI,OAAO,QAAQ;AAAA,IACjC;AAEA,WAAO;AAAA,EACT;AAAA,EAEO,mBACL,OACM;AACN,eAAW,gBAAgB,KAAK,cAAc;AAC5C,mBAAa,mBAAmB,KAAK;AAAA,IACvC;AAEA,WAAO;AAAA,EACT;AACF;;;AC3FO,SAAS,YAAY,KAAU,aAAsB,MAAc;AACxE,SAAO,CAAC,cAAc,IAAI,QAAQ,IAAI,QAAQ,EAAE,OAAO,OAAO,EAAE,KAAK,EAAE;AACzE","sourcesContent":["import { EventMap, Listener } from 'strict-event-emitter'\nimport { Interceptor, ExtractEventNames } from './Interceptor'\n\nexport interface BatchInterceptorOptions<\n InterceptorList extends ReadonlyArray>\n> {\n name: string\n interceptors: InterceptorList\n}\n\nexport type ExtractEventMapType<\n InterceptorList extends ReadonlyArray>\n> = InterceptorList extends ReadonlyArray\n ? InterceptorType extends Interceptor\n ? EventMap\n : never\n : never\n\n/**\n * A batch interceptor that exposes a single interface\n * to apply and operate with multiple interceptors at once.\n */\nexport class BatchInterceptor<\n InterceptorList extends ReadonlyArray>,\n Events extends EventMap = ExtractEventMapType\n> extends Interceptor {\n static symbol: symbol\n\n private interceptors: InterceptorList\n\n constructor(options: BatchInterceptorOptions) {\n BatchInterceptor.symbol = Symbol(options.name)\n super(BatchInterceptor.symbol)\n this.interceptors = options.interceptors\n }\n\n protected setup() {\n const logger = this.logger.extend('setup')\n\n logger.info('applying all %d interceptors...', this.interceptors.length)\n\n for (const interceptor of this.interceptors) {\n logger.info('applying \"%s\" interceptor...', interceptor.constructor.name)\n interceptor.apply()\n\n logger.info('adding interceptor dispose subscription')\n this.subscriptions.push(() => interceptor.dispose())\n }\n }\n\n public on>(\n event: EventName,\n listener: Listener\n ): this {\n // Instead of adding a listener to the batch interceptor,\n // propagate the listener to each of the individual interceptors.\n for (const interceptor of this.interceptors) {\n interceptor.on(event, listener)\n }\n\n return this\n }\n\n public once>(\n event: EventName,\n listener: Listener\n ): this {\n for (const interceptor of this.interceptors) {\n interceptor.once(event, listener)\n }\n\n return this\n }\n\n public off>(\n event: EventName,\n listener: Listener\n ): this {\n for (const interceptor of this.interceptors) {\n interceptor.off(event, listener)\n }\n\n return this\n }\n\n public removeAllListeners>(\n event?: EventName | undefined\n ): this {\n for (const interceptors of this.interceptors) {\n interceptors.removeAllListeners(event)\n }\n\n return this\n }\n}\n","/**\n * Removes query parameters and hashes from a given URL.\n */\nexport function getCleanUrl(url: URL, isAbsolute: boolean = true): string {\n return [isAbsolute && url.origin, url.pathname].filter(Boolean).join('')\n}\n"]} \ No newline at end of file diff --git a/node_modules/@mswjs/interceptors/lib/browser/index.mjs b/node_modules/@mswjs/interceptors/lib/browser/index.mjs new file mode 100644 index 0000000000000000000000000000000000000000..77c7a04bc94664b09af647b14a781da899fb1657 --- /dev/null +++ b/node_modules/@mswjs/interceptors/lib/browser/index.mjs @@ -0,0 +1,79 @@ +import { + decodeBuffer, + encodeBuffer +} from "./chunk-6HYIRFX2.mjs"; +import { + FetchResponse, + IS_PATCHED_MODULE +} from "./chunk-5UK33FSU.mjs"; +import { + INTERNAL_REQUEST_ID_HEADER_NAME, + Interceptor, + InterceptorReadyState, + createRequestId, + deleteGlobalSymbol, + getGlobalSymbol +} from "./chunk-QED3Q6Z2.mjs"; + +// src/BatchInterceptor.ts +var BatchInterceptor = class extends Interceptor { + constructor(options) { + BatchInterceptor.symbol = Symbol(options.name); + super(BatchInterceptor.symbol); + this.interceptors = options.interceptors; + } + setup() { + const logger = this.logger.extend("setup"); + logger.info("applying all %d interceptors...", this.interceptors.length); + for (const interceptor of this.interceptors) { + logger.info('applying "%s" interceptor...', interceptor.constructor.name); + interceptor.apply(); + logger.info("adding interceptor dispose subscription"); + this.subscriptions.push(() => interceptor.dispose()); + } + } + on(event, listener) { + for (const interceptor of this.interceptors) { + interceptor.on(event, listener); + } + return this; + } + once(event, listener) { + for (const interceptor of this.interceptors) { + interceptor.once(event, listener); + } + return this; + } + off(event, listener) { + for (const interceptor of this.interceptors) { + interceptor.off(event, listener); + } + return this; + } + removeAllListeners(event) { + for (const interceptors of this.interceptors) { + interceptors.removeAllListeners(event); + } + return this; + } +}; + +// src/utils/getCleanUrl.ts +function getCleanUrl(url, isAbsolute = true) { + return [isAbsolute && url.origin, url.pathname].filter(Boolean).join(""); +} +export { + BatchInterceptor, + FetchResponse, + INTERNAL_REQUEST_ID_HEADER_NAME, + IS_PATCHED_MODULE, + Interceptor, + InterceptorReadyState, + createRequestId, + decodeBuffer, + deleteGlobalSymbol, + encodeBuffer, + getCleanUrl, + getGlobalSymbol +}; +//# sourceMappingURL=index.mjs.map \ No newline at end of file diff --git a/node_modules/@mswjs/interceptors/lib/browser/index.mjs.map b/node_modules/@mswjs/interceptors/lib/browser/index.mjs.map new file mode 100644 index 0000000000000000000000000000000000000000..4cc8acce11e1956ea8e80b2245200503af23f1d7 --- /dev/null +++ b/node_modules/@mswjs/interceptors/lib/browser/index.mjs.map @@ -0,0 +1 @@ +{"version":3,"sources":["../../src/BatchInterceptor.ts","../../src/utils/getCleanUrl.ts"],"sourcesContent":["import { EventMap, Listener } from 'strict-event-emitter'\nimport { Interceptor, ExtractEventNames } from './Interceptor'\n\nexport interface BatchInterceptorOptions<\n InterceptorList extends ReadonlyArray>\n> {\n name: string\n interceptors: InterceptorList\n}\n\nexport type ExtractEventMapType<\n InterceptorList extends ReadonlyArray>\n> = InterceptorList extends ReadonlyArray\n ? InterceptorType extends Interceptor\n ? EventMap\n : never\n : never\n\n/**\n * A batch interceptor that exposes a single interface\n * to apply and operate with multiple interceptors at once.\n */\nexport class BatchInterceptor<\n InterceptorList extends ReadonlyArray>,\n Events extends EventMap = ExtractEventMapType\n> extends Interceptor {\n static symbol: symbol\n\n private interceptors: InterceptorList\n\n constructor(options: BatchInterceptorOptions) {\n BatchInterceptor.symbol = Symbol(options.name)\n super(BatchInterceptor.symbol)\n this.interceptors = options.interceptors\n }\n\n protected setup() {\n const logger = this.logger.extend('setup')\n\n logger.info('applying all %d interceptors...', this.interceptors.length)\n\n for (const interceptor of this.interceptors) {\n logger.info('applying \"%s\" interceptor...', interceptor.constructor.name)\n interceptor.apply()\n\n logger.info('adding interceptor dispose subscription')\n this.subscriptions.push(() => interceptor.dispose())\n }\n }\n\n public on>(\n event: EventName,\n listener: Listener\n ): this {\n // Instead of adding a listener to the batch interceptor,\n // propagate the listener to each of the individual interceptors.\n for (const interceptor of this.interceptors) {\n interceptor.on(event, listener)\n }\n\n return this\n }\n\n public once>(\n event: EventName,\n listener: Listener\n ): this {\n for (const interceptor of this.interceptors) {\n interceptor.once(event, listener)\n }\n\n return this\n }\n\n public off>(\n event: EventName,\n listener: Listener\n ): this {\n for (const interceptor of this.interceptors) {\n interceptor.off(event, listener)\n }\n\n return this\n }\n\n public removeAllListeners>(\n event?: EventName | undefined\n ): this {\n for (const interceptors of this.interceptors) {\n interceptors.removeAllListeners(event)\n }\n\n return this\n }\n}\n","/**\n * Removes query parameters and hashes from a given URL.\n */\nexport function getCleanUrl(url: URL, isAbsolute: boolean = true): string {\n return [isAbsolute && url.origin, url.pathname].filter(Boolean).join('')\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAsBO,IAAM,mBAAN,cAGG,YAAoB;AAAA,EAK5B,YAAY,SAAmD;AAC7D,qBAAiB,SAAS,OAAO,QAAQ,IAAI;AAC7C,UAAM,iBAAiB,MAAM;AAC7B,SAAK,eAAe,QAAQ;AAAA,EAC9B;AAAA,EAEU,QAAQ;AAChB,UAAM,SAAS,KAAK,OAAO,OAAO,OAAO;AAEzC,WAAO,KAAK,mCAAmC,KAAK,aAAa,MAAM;AAEvE,eAAW,eAAe,KAAK,cAAc;AAC3C,aAAO,KAAK,gCAAgC,YAAY,YAAY,IAAI;AACxE,kBAAY,MAAM;AAElB,aAAO,KAAK,yCAAyC;AACrD,WAAK,cAAc,KAAK,MAAM,YAAY,QAAQ,CAAC;AAAA,IACrD;AAAA,EACF;AAAA,EAEO,GACL,OACA,UACM;AAGN,eAAW,eAAe,KAAK,cAAc;AAC3C,kBAAY,GAAG,OAAO,QAAQ;AAAA,IAChC;AAEA,WAAO;AAAA,EACT;AAAA,EAEO,KACL,OACA,UACM;AACN,eAAW,eAAe,KAAK,cAAc;AAC3C,kBAAY,KAAK,OAAO,QAAQ;AAAA,IAClC;AAEA,WAAO;AAAA,EACT;AAAA,EAEO,IACL,OACA,UACM;AACN,eAAW,eAAe,KAAK,cAAc;AAC3C,kBAAY,IAAI,OAAO,QAAQ;AAAA,IACjC;AAEA,WAAO;AAAA,EACT;AAAA,EAEO,mBACL,OACM;AACN,eAAW,gBAAgB,KAAK,cAAc;AAC5C,mBAAa,mBAAmB,KAAK;AAAA,IACvC;AAEA,WAAO;AAAA,EACT;AACF;;;AC3FO,SAAS,YAAY,KAAU,aAAsB,MAAc;AACxE,SAAO,CAAC,cAAc,IAAI,QAAQ,IAAI,QAAQ,EAAE,OAAO,OAAO,EAAE,KAAK,EAAE;AACzE;","names":[]} \ No newline at end of file diff --git a/node_modules/@mswjs/interceptors/lib/browser/interceptors/WebSocket/index.d.ts b/node_modules/@mswjs/interceptors/lib/browser/interceptors/WebSocket/index.d.ts new file mode 100644 index 0000000000000000000000000000000000000000..d6ab505119bf83e7561f29646f23702f1842e64b --- /dev/null +++ b/node_modules/@mswjs/interceptors/lib/browser/interceptors/WebSocket/index.d.ts @@ -0,0 +1,233 @@ +import { I as Interceptor } from '../../Interceptor-af98b768.js'; +import '@open-draft/logger'; +import 'strict-event-emitter'; + +interface CloseEventInit extends EventInit { + code?: number; + reason?: string; + wasClean?: boolean; +} +declare class CloseEvent extends Event { + code: number; + reason: string; + wasClean: boolean; + constructor(type: string, init?: CloseEventInit); +} + +type WebSocketData = string | ArrayBufferLike | Blob | ArrayBufferView; +type WebSocketTransportEventMap = { + incoming: MessageEvent; + outgoing: MessageEvent; + close: CloseEvent; +}; +type StrictEventListenerOrEventListenerObject = ((this: WebSocket, event: EventType) => void) | { + handleEvent(this: WebSocket, event: EventType): void; +}; +interface WebSocketTransport { + addEventListener(event: EventType, listener: StrictEventListenerOrEventListenerObject | null, options?: boolean | AddEventListenerOptions): void; + dispatchEvent(event: WebSocketTransportEventMap[EventType]): boolean; + /** + * Send the data from the server to this client. + */ + send(data: WebSocketData): void; + /** + * Close the client connection. + */ + close(code?: number, reason?: string): void; +} + +type WebSocketEventListener = (this: WebSocket, event: EventType) => void; +declare const kPassthroughPromise: unique symbol; +declare const kOnSend: unique symbol; +declare const kClose: unique symbol; +declare class WebSocketOverride extends EventTarget implements WebSocket { + static readonly CONNECTING = 0; + static readonly OPEN = 1; + static readonly CLOSING = 2; + static readonly CLOSED = 3; + readonly CONNECTING = 0; + readonly OPEN = 1; + readonly CLOSING = 2; + readonly CLOSED = 3; + url: string; + protocol: string; + extensions: string; + binaryType: BinaryType; + readyState: number; + bufferedAmount: number; + private _onopen; + private _onmessage; + private _onerror; + private _onclose; + private [kPassthroughPromise]; + private [kOnSend]?; + constructor(url: string | URL, protocols?: string | Array); + set onopen(listener: WebSocketEventListener | null); + get onopen(): WebSocketEventListener | null; + set onmessage(listener: WebSocketEventListener> | null); + get onmessage(): WebSocketEventListener> | null; + set onerror(listener: WebSocketEventListener | null); + get onerror(): WebSocketEventListener | null; + set onclose(listener: WebSocketEventListener | null); + get onclose(): WebSocketEventListener | null; + /** + * @see https://websockets.spec.whatwg.org/#ref-for-dom-websocket-send%E2%91%A0 + */ + send(data: WebSocketData): void; + close(code?: number, reason?: string): void; + private [kClose]; + addEventListener(type: K, listener: (this: WebSocket, event: WebSocketEventMap[K]) => void, options?: boolean | AddEventListenerOptions): void; + addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void; + removeEventListener(type: K, callback: EventListenerOrEventListenerObject | null, options?: boolean | EventListenerOptions): void; +} + +declare const kEmitter$1: unique symbol; +interface WebSocketClientEventMap { + message: MessageEvent; + close: CloseEvent; +} +interface WebSocketClientConnectionProtocol { + id: string; + url: URL; + send(data: WebSocketData): void; + close(code?: number, reason?: string): void; +} +/** + * The WebSocket client instance represents an incoming + * client connection. The user can control the connection, + * send and receive events. + */ +declare class WebSocketClientConnection implements WebSocketClientConnectionProtocol { + readonly socket: WebSocket; + private readonly transport; + readonly id: string; + readonly url: URL; + private [kEmitter$1]; + constructor(socket: WebSocket, transport: WebSocketTransport); + /** + * Listen for the outgoing events from the connected WebSocket client. + */ + addEventListener(type: EventType, listener: WebSocketEventListener, options?: AddEventListenerOptions | boolean): void; + /** + * Removes the listener for the given event. + */ + removeEventListener(event: EventType, listener: WebSocketEventListener, options?: EventListenerOptions | boolean): void; + /** + * Send data to the connected client. + */ + send(data: WebSocketData): void; + /** + * Close the WebSocket connection. + * @param {number} code A status code (see https://www.rfc-editor.org/rfc/rfc6455#section-7.4.1). + * @param {string} reason A custom connection close reason. + */ + close(code?: number, reason?: string): void; +} + +/** + * Abstraction over the given mock `WebSocket` instance that allows + * for controlling that instance (e.g. sending and receiving messages). + */ +declare class WebSocketClassTransport extends EventTarget implements WebSocketTransport { + protected readonly socket: WebSocketOverride; + constructor(socket: WebSocketOverride); + addEventListener(type: EventType, callback: StrictEventListenerOrEventListenerObject | null, options?: boolean | AddEventListenerOptions): void; + dispatchEvent(event: WebSocketTransportEventMap[EventType]): boolean; + send(data: WebSocketData): void; + close(code: number, reason?: string): void; +} + +declare const kEmitter: unique symbol; +declare const kSend: unique symbol; +interface WebSocketServerEventMap { + open: Event; + message: MessageEvent; + error: Event; + close: CloseEvent; +} +/** + * The WebSocket server instance represents the actual production + * WebSocket server connection. It's idle by default but you can + * establish it by calling `server.connect()`. + */ +declare class WebSocketServerConnection { + private readonly client; + private readonly transport; + private readonly createConnection; + /** + * A WebSocket instance connected to the original server. + */ + private realWebSocket?; + private mockCloseController; + private realCloseController; + private [kEmitter]; + constructor(client: WebSocketOverride, transport: WebSocketClassTransport, createConnection: () => WebSocket); + /** + * The `WebSocket` instance connected to the original server. + * Accessing this before calling `server.connect()` will throw. + */ + get socket(): WebSocket; + /** + * Open connection to the original WebSocket server. + */ + connect(): void; + /** + * Listen for the incoming events from the original WebSocket server. + */ + addEventListener(event: EventType, listener: WebSocketEventListener, options?: AddEventListenerOptions | boolean): void; + /** + * Remove the listener for the given event. + */ + removeEventListener(event: EventType, listener: WebSocketEventListener, options?: EventListenerOptions | boolean): void; + /** + * Send data to the original WebSocket server. + * @example + * server.send('hello') + * server.send(new Blob(['hello'])) + * server.send(new TextEncoder().encode('hello')) + */ + send(data: WebSocketData): void; + private [kSend]; + /** + * Close the actual server connection. + */ + close(): void; + private handleIncomingMessage; + private handleMockClose; + private handleRealClose; +} + +type WebSocketEventMap$1 = { + connection: [args: WebSocketConnectionData]; +}; +type WebSocketConnectionData = { + /** + * The incoming WebSocket client connection. + */ + client: WebSocketClientConnection; + /** + * The original WebSocket server connection. + */ + server: WebSocketServerConnection; + /** + * The connection information. + */ + info: { + /** + * The protocols supported by the WebSocket client. + */ + protocols: string | Array | undefined; + }; +}; +/** + * Intercept the outgoing WebSocket connections created using + * the global `WebSocket` class. + */ +declare class WebSocketInterceptor extends Interceptor { + static symbol: symbol; + constructor(); + protected checkEnvironment(): boolean; + protected setup(): void; +} + +export { WebSocketClientConnection, WebSocketClientConnectionProtocol, WebSocketConnectionData, WebSocketData, WebSocketEventMap$1 as WebSocketEventMap, WebSocketInterceptor, WebSocketServerConnection, WebSocketTransport }; diff --git a/node_modules/@mswjs/interceptors/lib/browser/interceptors/WebSocket/index.js b/node_modules/@mswjs/interceptors/lib/browser/interceptors/WebSocket/index.js new file mode 100644 index 0000000000000000000000000000000000000000..b0462ac1260cc8553a398d171726bb1bccc2d499 --- /dev/null +++ b/node_modules/@mswjs/interceptors/lib/browser/interceptors/WebSocket/index.js @@ -0,0 +1,710 @@ +"use strict";Object.defineProperty(exports, "__esModule", {value: true}); + +var _chunkPFGO5BSMjs = require('../../chunk-PFGO5BSM.js'); + + + +var _chunkTIPR373Rjs = require('../../chunk-TIPR373R.js'); + +// src/interceptors/WebSocket/utils/bindEvent.ts +function bindEvent(target, event) { + Object.defineProperties(event, { + target: { + value: target, + enumerable: true, + writable: true + }, + currentTarget: { + value: target, + enumerable: true, + writable: true + } + }); + return event; +} + +// src/interceptors/WebSocket/utils/events.ts +var kCancelable = Symbol("kCancelable"); +var kDefaultPrevented = Symbol("kDefaultPrevented"); +var CancelableMessageEvent = class extends MessageEvent { + constructor(type, init) { + super(type, init); + this[kCancelable] = !!init.cancelable; + this[kDefaultPrevented] = false; + } + get cancelable() { + return this[kCancelable]; + } + set cancelable(nextCancelable) { + this[kCancelable] = nextCancelable; + } + get defaultPrevented() { + return this[kDefaultPrevented]; + } + set defaultPrevented(nextDefaultPrevented) { + this[kDefaultPrevented] = nextDefaultPrevented; + } + preventDefault() { + if (this.cancelable && !this[kDefaultPrevented]) { + this[kDefaultPrevented] = true; + } + } +}; +kCancelable, kDefaultPrevented; +var CloseEvent = class extends Event { + constructor(type, init = {}) { + super(type, init); + this.code = init.code === void 0 ? 0 : init.code; + this.reason = init.reason === void 0 ? "" : init.reason; + this.wasClean = init.wasClean === void 0 ? false : init.wasClean; + } +}; +var CancelableCloseEvent = class extends CloseEvent { + constructor(type, init = {}) { + super(type, init); + this[kCancelable] = !!init.cancelable; + this[kDefaultPrevented] = false; + } + get cancelable() { + return this[kCancelable]; + } + set cancelable(nextCancelable) { + this[kCancelable] = nextCancelable; + } + get defaultPrevented() { + return this[kDefaultPrevented]; + } + set defaultPrevented(nextDefaultPrevented) { + this[kDefaultPrevented] = nextDefaultPrevented; + } + preventDefault() { + if (this.cancelable && !this[kDefaultPrevented]) { + this[kDefaultPrevented] = true; + } + } +}; +kCancelable, kDefaultPrevented; + +// src/interceptors/WebSocket/WebSocketClientConnection.ts +var kEmitter = Symbol("kEmitter"); +var kBoundListener = Symbol("kBoundListener"); +var WebSocketClientConnection = class { + constructor(socket, transport) { + this.socket = socket; + this.transport = transport; + this.id = _chunkTIPR373Rjs.createRequestId.call(void 0, ); + this.url = new URL(socket.url); + this[kEmitter] = new EventTarget(); + this.transport.addEventListener("outgoing", (event) => { + const message = bindEvent( + this.socket, + new CancelableMessageEvent("message", { + data: event.data, + origin: event.origin, + cancelable: true + }) + ); + this[kEmitter].dispatchEvent(message); + if (message.defaultPrevented) { + event.preventDefault(); + } + }); + this.transport.addEventListener("close", (event) => { + this[kEmitter].dispatchEvent( + bindEvent(this.socket, new CloseEvent("close", event)) + ); + }); + } + /** + * Listen for the outgoing events from the connected WebSocket client. + */ + addEventListener(type, listener, options) { + if (!Reflect.has(listener, kBoundListener)) { + const boundListener = listener.bind(this.socket); + Object.defineProperty(listener, kBoundListener, { + value: boundListener, + enumerable: false, + configurable: false + }); + } + this[kEmitter].addEventListener( + type, + Reflect.get(listener, kBoundListener), + options + ); + } + /** + * Removes the listener for the given event. + */ + removeEventListener(event, listener, options) { + this[kEmitter].removeEventListener( + event, + Reflect.get(listener, kBoundListener), + options + ); + } + /** + * Send data to the connected client. + */ + send(data) { + this.transport.send(data); + } + /** + * Close the WebSocket connection. + * @param {number} code A status code (see https://www.rfc-editor.org/rfc/rfc6455#section-7.4.1). + * @param {string} reason A custom connection close reason. + */ + close(code, reason) { + this.transport.close(code, reason); + } +}; +kEmitter; + +// src/interceptors/WebSocket/WebSocketServerConnection.ts +var _outvariant = require('outvariant'); + +// src/interceptors/WebSocket/WebSocketOverride.ts + +var _deferredpromise = require('@open-draft/deferred-promise'); +var WEBSOCKET_CLOSE_CODE_RANGE_ERROR = "InvalidAccessError: close code out of user configurable range"; +var kPassthroughPromise = Symbol("kPassthroughPromise"); +var kOnSend = Symbol("kOnSend"); +var kClose = Symbol("kClose"); +var WebSocketOverride = class extends EventTarget { + constructor(url, protocols) { + super(); + this.CONNECTING = 0; + this.OPEN = 1; + this.CLOSING = 2; + this.CLOSED = 3; + this._onopen = null; + this._onmessage = null; + this._onerror = null; + this._onclose = null; + this.url = url.toString(); + this.protocol = ""; + this.extensions = ""; + this.binaryType = "blob"; + this.readyState = this.CONNECTING; + this.bufferedAmount = 0; + this[kPassthroughPromise] = new (0, _deferredpromise.DeferredPromise)(); + queueMicrotask(async () => { + if (await this[kPassthroughPromise]) { + return; + } + this.protocol = typeof protocols === "string" ? protocols : Array.isArray(protocols) && protocols.length > 0 ? protocols[0] : ""; + if (this.readyState === this.CONNECTING) { + this.readyState = this.OPEN; + this.dispatchEvent(bindEvent(this, new Event("open"))); + } + }); + } + set onopen(listener) { + this.removeEventListener("open", this._onopen); + this._onopen = listener; + if (listener !== null) { + this.addEventListener("open", listener); + } + } + get onopen() { + return this._onopen; + } + set onmessage(listener) { + this.removeEventListener( + "message", + this._onmessage + ); + this._onmessage = listener; + if (listener !== null) { + this.addEventListener("message", listener); + } + } + get onmessage() { + return this._onmessage; + } + set onerror(listener) { + this.removeEventListener("error", this._onerror); + this._onerror = listener; + if (listener !== null) { + this.addEventListener("error", listener); + } + } + get onerror() { + return this._onerror; + } + set onclose(listener) { + this.removeEventListener("close", this._onclose); + this._onclose = listener; + if (listener !== null) { + this.addEventListener("close", listener); + } + } + get onclose() { + return this._onclose; + } + /** + * @see https://websockets.spec.whatwg.org/#ref-for-dom-websocket-send%E2%91%A0 + */ + send(data) { + if (this.readyState === this.CONNECTING) { + this.close(); + throw new DOMException("InvalidStateError"); + } + if (this.readyState === this.CLOSING || this.readyState === this.CLOSED) { + return; + } + this.bufferedAmount += getDataSize(data); + queueMicrotask(() => { + var _a; + this.bufferedAmount = 0; + (_a = this[kOnSend]) == null ? void 0 : _a.call(this, data); + }); + } + close(code = 1e3, reason) { + _outvariant.invariant.call(void 0, code, WEBSOCKET_CLOSE_CODE_RANGE_ERROR); + _outvariant.invariant.call(void 0, + code === 1e3 || code >= 3e3 && code <= 4999, + WEBSOCKET_CLOSE_CODE_RANGE_ERROR + ); + this[kClose](code, reason); + } + [(kPassthroughPromise, kOnSend, kClose)](code = 1e3, reason, wasClean = true) { + if (this.readyState === this.CLOSING || this.readyState === this.CLOSED) { + return; + } + this.readyState = this.CLOSING; + queueMicrotask(() => { + this.readyState = this.CLOSED; + this.dispatchEvent( + bindEvent( + this, + new CloseEvent("close", { + code, + reason, + wasClean + }) + ) + ); + this._onopen = null; + this._onmessage = null; + this._onerror = null; + this._onclose = null; + }); + } + addEventListener(type, listener, options) { + return super.addEventListener( + type, + listener, + options + ); + } + removeEventListener(type, callback, options) { + return super.removeEventListener(type, callback, options); + } +}; +WebSocketOverride.CONNECTING = 0; +WebSocketOverride.OPEN = 1; +WebSocketOverride.CLOSING = 2; +WebSocketOverride.CLOSED = 3; +function getDataSize(data) { + if (typeof data === "string") { + return data.length; + } + if (data instanceof Blob) { + return data.size; + } + return data.byteLength; +} + +// src/interceptors/WebSocket/WebSocketServerConnection.ts +var kEmitter2 = Symbol("kEmitter"); +var kBoundListener2 = Symbol("kBoundListener"); +var kSend = Symbol("kSend"); +var WebSocketServerConnection = class { + constructor(client, transport, createConnection) { + this.client = client; + this.transport = transport; + this.createConnection = createConnection; + this[kEmitter2] = new EventTarget(); + this.mockCloseController = new AbortController(); + this.realCloseController = new AbortController(); + this.transport.addEventListener("outgoing", (event) => { + if (typeof this.realWebSocket === "undefined") { + return; + } + queueMicrotask(() => { + if (!event.defaultPrevented) { + this[kSend](event.data); + } + }); + }); + this.transport.addEventListener( + "incoming", + this.handleIncomingMessage.bind(this) + ); + } + /** + * The `WebSocket` instance connected to the original server. + * Accessing this before calling `server.connect()` will throw. + */ + get socket() { + _outvariant.invariant.call(void 0, + this.realWebSocket, + 'Cannot access "socket" on the original WebSocket server object: the connection is not open. Did you forget to call `server.connect()`?' + ); + return this.realWebSocket; + } + /** + * Open connection to the original WebSocket server. + */ + connect() { + _outvariant.invariant.call(void 0, + !this.realWebSocket || this.realWebSocket.readyState !== WebSocket.OPEN, + 'Failed to call "connect()" on the original WebSocket instance: the connection already open' + ); + const realWebSocket = this.createConnection(); + realWebSocket.binaryType = this.client.binaryType; + realWebSocket.addEventListener( + "open", + (event) => { + this[kEmitter2].dispatchEvent( + bindEvent(this.realWebSocket, new Event("open", event)) + ); + }, + { once: true } + ); + realWebSocket.addEventListener("message", (event) => { + this.transport.dispatchEvent( + bindEvent( + this.realWebSocket, + new MessageEvent("incoming", { + data: event.data, + origin: event.origin + }) + ) + ); + }); + this.client.addEventListener( + "close", + (event) => { + this.handleMockClose(event); + }, + { + signal: this.mockCloseController.signal + } + ); + realWebSocket.addEventListener( + "close", + (event) => { + this.handleRealClose(event); + }, + { + signal: this.realCloseController.signal + } + ); + realWebSocket.addEventListener("error", () => { + const errorEvent = bindEvent( + realWebSocket, + new Event("error", { cancelable: true }) + ); + this[kEmitter2].dispatchEvent(errorEvent); + if (!errorEvent.defaultPrevented) { + this.client.dispatchEvent(bindEvent(this.client, new Event("error"))); + } + }); + this.realWebSocket = realWebSocket; + } + /** + * Listen for the incoming events from the original WebSocket server. + */ + addEventListener(event, listener, options) { + if (!Reflect.has(listener, kBoundListener2)) { + const boundListener = listener.bind(this.client); + Object.defineProperty(listener, kBoundListener2, { + value: boundListener, + enumerable: false + }); + } + this[kEmitter2].addEventListener( + event, + Reflect.get(listener, kBoundListener2), + options + ); + } + /** + * Remove the listener for the given event. + */ + removeEventListener(event, listener, options) { + this[kEmitter2].removeEventListener( + event, + Reflect.get(listener, kBoundListener2), + options + ); + } + /** + * Send data to the original WebSocket server. + * @example + * server.send('hello') + * server.send(new Blob(['hello'])) + * server.send(new TextEncoder().encode('hello')) + */ + send(data) { + this[kSend](data); + } + [(kEmitter2, kSend)](data) { + const { realWebSocket } = this; + _outvariant.invariant.call(void 0, + realWebSocket, + 'Failed to call "server.send()" for "%s": the connection is not open. Did you forget to call "server.connect()"?', + this.client.url + ); + if (realWebSocket.readyState === WebSocket.CLOSING || realWebSocket.readyState === WebSocket.CLOSED) { + return; + } + if (realWebSocket.readyState === WebSocket.CONNECTING) { + realWebSocket.addEventListener( + "open", + () => { + realWebSocket.send(data); + }, + { once: true } + ); + return; + } + realWebSocket.send(data); + } + /** + * Close the actual server connection. + */ + close() { + const { realWebSocket } = this; + _outvariant.invariant.call(void 0, + realWebSocket, + 'Failed to close server connection for "%s": the connection is not open. Did you forget to call "server.connect()"?', + this.client.url + ); + this.realCloseController.abort(); + if (realWebSocket.readyState === WebSocket.CLOSING || realWebSocket.readyState === WebSocket.CLOSED) { + return; + } + realWebSocket.close(); + queueMicrotask(() => { + this[kEmitter2].dispatchEvent( + bindEvent( + this.realWebSocket, + new CancelableCloseEvent("close", { + /** + * @note `server.close()` in the interceptor + * always results in clean closures. + */ + code: 1e3, + cancelable: true + }) + ) + ); + }); + } + handleIncomingMessage(event) { + const messageEvent = bindEvent( + event.target, + new CancelableMessageEvent("message", { + data: event.data, + origin: event.origin, + cancelable: true + }) + ); + this[kEmitter2].dispatchEvent(messageEvent); + if (!messageEvent.defaultPrevented) { + this.client.dispatchEvent( + bindEvent( + /** + * @note Bind the forwarded original server events + * to the mock WebSocket instance so it would + * dispatch them straight away. + */ + this.client, + // Clone the message event again to prevent + // the "already being dispatched" exception. + new MessageEvent("message", { + data: event.data, + origin: event.origin + }) + ) + ); + } + } + handleMockClose(_event) { + if (this.realWebSocket) { + this.realWebSocket.close(); + } + } + handleRealClose(event) { + this.mockCloseController.abort(); + const closeEvent = bindEvent( + this.realWebSocket, + new CancelableCloseEvent("close", { + code: event.code, + reason: event.reason, + wasClean: event.wasClean, + cancelable: true + }) + ); + this[kEmitter2].dispatchEvent(closeEvent); + if (!closeEvent.defaultPrevented) { + this.client[kClose](event.code, event.reason); + } + } +}; + +// src/interceptors/WebSocket/WebSocketClassTransport.ts +var WebSocketClassTransport = class extends EventTarget { + constructor(socket) { + super(); + this.socket = socket; + this.socket.addEventListener("close", (event) => { + this.dispatchEvent(bindEvent(this.socket, new CloseEvent("close", event))); + }); + this.socket[kOnSend] = (data) => { + this.dispatchEvent( + bindEvent( + this.socket, + // Dispatch this as cancelable because "client" connection + // re-creates this message event (cannot dispatch the same event). + new CancelableMessageEvent("outgoing", { + data, + origin: this.socket.url, + cancelable: true + }) + ) + ); + }; + } + addEventListener(type, callback, options) { + return super.addEventListener(type, callback, options); + } + dispatchEvent(event) { + return super.dispatchEvent(event); + } + send(data) { + queueMicrotask(() => { + if (this.socket.readyState === this.socket.CLOSING || this.socket.readyState === this.socket.CLOSED) { + return; + } + const dispatchEvent = () => { + this.socket.dispatchEvent( + bindEvent( + /** + * @note Setting this event's "target" to the + * WebSocket override instance is important. + * This way it can tell apart original incoming events + * (must be forwarded to the transport) from the + * mocked message events like the one below + * (must be dispatched on the client instance). + */ + this.socket, + new MessageEvent("message", { + data, + origin: this.socket.url + }) + ) + ); + }; + if (this.socket.readyState === this.socket.CONNECTING) { + this.socket.addEventListener( + "open", + () => { + dispatchEvent(); + }, + { once: true } + ); + } else { + dispatchEvent(); + } + }); + } + close(code, reason) { + this.socket[kClose](code, reason); + } +}; + +// src/interceptors/WebSocket/index.ts +var _WebSocketInterceptor = class extends _chunkTIPR373Rjs.Interceptor { + constructor() { + super(_WebSocketInterceptor.symbol); + } + checkEnvironment() { + return _chunkPFGO5BSMjs.hasConfigurableGlobal.call(void 0, "WebSocket"); + } + setup() { + const originalWebSocketDescriptor = Object.getOwnPropertyDescriptor( + globalThis, + "WebSocket" + ); + const WebSocketProxy = new Proxy(globalThis.WebSocket, { + construct: (target, args, newTarget) => { + const [url, protocols] = args; + const createConnection = () => { + return Reflect.construct(target, args, newTarget); + }; + const socket = new WebSocketOverride(url, protocols); + const transport = new WebSocketClassTransport(socket); + queueMicrotask(() => { + try { + const server = new WebSocketServerConnection( + socket, + transport, + createConnection + ); + const hasConnectionListeners = this.emitter.emit("connection", { + client: new WebSocketClientConnection(socket, transport), + server, + info: { + protocols + } + }); + if (hasConnectionListeners) { + socket[kPassthroughPromise].resolve(false); + } else { + socket[kPassthroughPromise].resolve(true); + server.connect(); + server.addEventListener("open", () => { + socket.dispatchEvent(bindEvent(socket, new Event("open"))); + if (server["realWebSocket"]) { + socket.protocol = server["realWebSocket"].protocol; + } + }); + } + } catch (error) { + if (error instanceof Error) { + socket.dispatchEvent(new Event("error")); + if (socket.readyState !== WebSocket.CLOSING && socket.readyState !== WebSocket.CLOSED) { + socket[kClose](1011, error.message, false); + } + console.error(error); + } + } + }); + return socket; + } + }); + Object.defineProperty(globalThis, "WebSocket", { + value: WebSocketProxy, + configurable: true + }); + this.subscriptions.push(() => { + Object.defineProperty( + globalThis, + "WebSocket", + originalWebSocketDescriptor + ); + }); + } +}; +var WebSocketInterceptor = _WebSocketInterceptor; +WebSocketInterceptor.symbol = Symbol("websocket"); + + + + +exports.WebSocketClientConnection = WebSocketClientConnection; exports.WebSocketInterceptor = WebSocketInterceptor; exports.WebSocketServerConnection = WebSocketServerConnection; +//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/node_modules/@mswjs/interceptors/lib/browser/interceptors/WebSocket/index.js.map b/node_modules/@mswjs/interceptors/lib/browser/interceptors/WebSocket/index.js.map new file mode 100644 index 0000000000000000000000000000000000000000..755f2f1b092cfeb12485dedf9c05151325b8314c --- /dev/null +++ b/node_modules/@mswjs/interceptors/lib/browser/interceptors/WebSocket/index.js.map @@ -0,0 +1 @@ +{"version":3,"sources":["../../../../src/interceptors/WebSocket/utils/bindEvent.ts","../../../../src/interceptors/WebSocket/utils/events.ts","../../../../src/interceptors/WebSocket/WebSocketClientConnection.ts","../../../../src/interceptors/WebSocket/WebSocketServerConnection.ts","../../../../src/interceptors/WebSocket/WebSocketOverride.ts","../../../../src/interceptors/WebSocket/WebSocketClassTransport.ts","../../../../src/interceptors/WebSocket/index.ts"],"names":["invariant","kEmitter","kBoundListener"],"mappings":"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","sourcesContent":["type EventWithTarget = E & { target: T }\n\nexport function bindEvent(\n target: T,\n event: E\n): EventWithTarget {\n Object.defineProperties(event, {\n target: {\n value: target,\n enumerable: true,\n writable: true,\n },\n currentTarget: {\n value: target,\n enumerable: true,\n writable: true,\n },\n })\n\n return event as EventWithTarget\n}\n","const kCancelable = Symbol('kCancelable')\nconst kDefaultPrevented = Symbol('kDefaultPrevented')\n\n/**\n * A `MessageEvent` superset that supports event cancellation\n * in Node.js. It's rather non-intrusive so it can be safely\n * used in the browser as well.\n *\n * @see https://github.com/nodejs/node/issues/51767\n */\nexport class CancelableMessageEvent extends MessageEvent {\n [kCancelable]: boolean;\n [kDefaultPrevented]: boolean\n\n constructor(type: string, init: MessageEventInit) {\n super(type, init)\n this[kCancelable] = !!init.cancelable\n this[kDefaultPrevented] = false\n }\n\n get cancelable() {\n return this[kCancelable]\n }\n\n set cancelable(nextCancelable) {\n this[kCancelable] = nextCancelable\n }\n\n get defaultPrevented() {\n return this[kDefaultPrevented]\n }\n\n set defaultPrevented(nextDefaultPrevented) {\n this[kDefaultPrevented] = nextDefaultPrevented\n }\n\n public preventDefault(): void {\n if (this.cancelable && !this[kDefaultPrevented]) {\n this[kDefaultPrevented] = true\n }\n }\n}\n\ninterface CloseEventInit extends EventInit {\n code?: number\n reason?: string\n wasClean?: boolean\n}\n\nexport class CloseEvent extends Event {\n public code: number\n public reason: string\n public wasClean: boolean\n\n constructor(type: string, init: CloseEventInit = {}) {\n super(type, init)\n this.code = init.code === undefined ? 0 : init.code\n this.reason = init.reason === undefined ? '' : init.reason\n this.wasClean = init.wasClean === undefined ? false : init.wasClean\n }\n}\n\nexport class CancelableCloseEvent extends CloseEvent {\n [kCancelable]: boolean;\n [kDefaultPrevented]: boolean\n\n constructor(type: string, init: CloseEventInit = {}) {\n super(type, init)\n this[kCancelable] = !!init.cancelable\n this[kDefaultPrevented] = false\n }\n\n get cancelable() {\n return this[kCancelable]\n }\n\n set cancelable(nextCancelable) {\n this[kCancelable] = nextCancelable\n }\n\n get defaultPrevented() {\n return this[kDefaultPrevented]\n }\n\n set defaultPrevented(nextDefaultPrevented) {\n this[kDefaultPrevented] = nextDefaultPrevented\n }\n\n public preventDefault(): void {\n if (this.cancelable && !this[kDefaultPrevented]) {\n this[kDefaultPrevented] = true\n }\n }\n}\n","import type { WebSocketData, WebSocketTransport } from './WebSocketTransport'\nimport type { WebSocketEventListener } from './WebSocketOverride'\nimport { bindEvent } from './utils/bindEvent'\nimport { CancelableMessageEvent, CloseEvent } from './utils/events'\nimport { createRequestId } from '../../createRequestId'\n\nconst kEmitter = Symbol('kEmitter')\nconst kBoundListener = Symbol('kBoundListener')\n\ninterface WebSocketClientEventMap {\n message: MessageEvent\n close: CloseEvent\n}\n\nexport interface WebSocketClientConnectionProtocol {\n id: string\n url: URL\n send(data: WebSocketData): void\n close(code?: number, reason?: string): void\n}\n\n/**\n * The WebSocket client instance represents an incoming\n * client connection. The user can control the connection,\n * send and receive events.\n */\nexport class WebSocketClientConnection\n implements WebSocketClientConnectionProtocol\n{\n public readonly id: string\n public readonly url: URL\n\n private [kEmitter]: EventTarget\n\n constructor(\n public readonly socket: WebSocket,\n private readonly transport: WebSocketTransport\n ) {\n this.id = createRequestId()\n this.url = new URL(socket.url)\n this[kEmitter] = new EventTarget()\n\n // Emit outgoing client data (\"ws.send()\") as \"message\"\n // events on the \"client\" connection.\n this.transport.addEventListener('outgoing', (event) => {\n const message = bindEvent(\n this.socket,\n new CancelableMessageEvent('message', {\n data: event.data,\n origin: event.origin,\n cancelable: true,\n })\n )\n\n this[kEmitter].dispatchEvent(message)\n\n // This is a bit silly but forward the cancellation state\n // of the \"client\" message event to the \"outgoing\" transport event.\n // This way, other agens (like \"server\" connection) can know\n // whether the client listener has pervented the default.\n if (message.defaultPrevented) {\n event.preventDefault()\n }\n })\n\n /**\n * Emit the \"close\" event on the \"client\" connection\n * whenever the underlying transport is closed.\n * @note \"client.close()\" does NOT dispatch the \"close\"\n * event on the WebSocket because it uses non-configurable\n * close status code. Thus, we listen to the transport\n * instead of the WebSocket's \"close\" event.\n */\n this.transport.addEventListener('close', (event) => {\n this[kEmitter].dispatchEvent(\n bindEvent(this.socket, new CloseEvent('close', event))\n )\n })\n }\n\n /**\n * Listen for the outgoing events from the connected WebSocket client.\n */\n public addEventListener(\n type: EventType,\n listener: WebSocketEventListener,\n options?: AddEventListenerOptions | boolean\n ): void {\n if (!Reflect.has(listener, kBoundListener)) {\n const boundListener = listener.bind(this.socket)\n\n // Store the bound listener on the original listener\n // so the exact bound function can be accessed in \"removeEventListener()\".\n Object.defineProperty(listener, kBoundListener, {\n value: boundListener,\n enumerable: false,\n configurable: false,\n })\n }\n\n this[kEmitter].addEventListener(\n type,\n Reflect.get(listener, kBoundListener) as EventListener,\n options\n )\n }\n\n /**\n * Removes the listener for the given event.\n */\n public removeEventListener(\n event: EventType,\n listener: WebSocketEventListener,\n options?: EventListenerOptions | boolean\n ): void {\n this[kEmitter].removeEventListener(\n event,\n Reflect.get(listener, kBoundListener) as EventListener,\n options\n )\n }\n\n /**\n * Send data to the connected client.\n */\n public send(data: WebSocketData): void {\n this.transport.send(data)\n }\n\n /**\n * Close the WebSocket connection.\n * @param {number} code A status code (see https://www.rfc-editor.org/rfc/rfc6455#section-7.4.1).\n * @param {string} reason A custom connection close reason.\n */\n public close(code?: number, reason?: string): void {\n this.transport.close(code, reason)\n }\n}\n","import { invariant } from 'outvariant'\nimport {\n kClose,\n WebSocketEventListener,\n WebSocketOverride,\n} from './WebSocketOverride'\nimport type { WebSocketData } from './WebSocketTransport'\nimport type { WebSocketClassTransport } from './WebSocketClassTransport'\nimport { bindEvent } from './utils/bindEvent'\nimport {\n CancelableMessageEvent,\n CancelableCloseEvent,\n CloseEvent,\n} from './utils/events'\n\nconst kEmitter = Symbol('kEmitter')\nconst kBoundListener = Symbol('kBoundListener')\nconst kSend = Symbol('kSend')\n\ninterface WebSocketServerEventMap {\n open: Event\n message: MessageEvent\n error: Event\n close: CloseEvent\n}\n\n/**\n * The WebSocket server instance represents the actual production\n * WebSocket server connection. It's idle by default but you can\n * establish it by calling `server.connect()`.\n */\nexport class WebSocketServerConnection {\n /**\n * A WebSocket instance connected to the original server.\n */\n private realWebSocket?: WebSocket\n private mockCloseController: AbortController\n private realCloseController: AbortController\n private [kEmitter]: EventTarget\n\n constructor(\n private readonly client: WebSocketOverride,\n private readonly transport: WebSocketClassTransport,\n private readonly createConnection: () => WebSocket\n ) {\n this[kEmitter] = new EventTarget()\n this.mockCloseController = new AbortController()\n this.realCloseController = new AbortController()\n\n // Automatically forward outgoing client events\n // to the actual server unless the outgoing message event\n // has been prevented. The \"outgoing\" transport event it\n // dispatched by the \"client\" connection.\n this.transport.addEventListener('outgoing', (event) => {\n // Ignore client messages if the server connection\n // hasn't been established yet. Nowhere to forward.\n if (typeof this.realWebSocket === 'undefined') {\n return\n }\n\n // Every outgoing client message can prevent this forwarding\n // by preventing the default of the outgoing message event.\n // This listener will be added before user-defined listeners,\n // so execute the logic on the next tick.\n queueMicrotask(() => {\n if (!event.defaultPrevented) {\n /**\n * @note Use the internal send mechanism so consumers can tell\n * apart direct user calls to `server.send()` and internal calls.\n * E.g. MSW has to ignore this internal call to log out messages correctly.\n */\n this[kSend](event.data)\n }\n })\n })\n\n this.transport.addEventListener(\n 'incoming',\n this.handleIncomingMessage.bind(this)\n )\n }\n\n /**\n * The `WebSocket` instance connected to the original server.\n * Accessing this before calling `server.connect()` will throw.\n */\n public get socket(): WebSocket {\n invariant(\n this.realWebSocket,\n 'Cannot access \"socket\" on the original WebSocket server object: the connection is not open. Did you forget to call `server.connect()`?'\n )\n\n return this.realWebSocket\n }\n\n /**\n * Open connection to the original WebSocket server.\n */\n public connect(): void {\n invariant(\n !this.realWebSocket || this.realWebSocket.readyState !== WebSocket.OPEN,\n 'Failed to call \"connect()\" on the original WebSocket instance: the connection already open'\n )\n\n const realWebSocket = this.createConnection()\n\n // Inherit the binary type from the mock WebSocket client.\n realWebSocket.binaryType = this.client.binaryType\n\n // Allow the interceptor to listen to when the server connection\n // has been established. This isn't necessary to operate with the connection\n // but may be beneficial in some cases (like conditionally adding logging).\n realWebSocket.addEventListener(\n 'open',\n (event) => {\n this[kEmitter].dispatchEvent(\n bindEvent(this.realWebSocket!, new Event('open', event))\n )\n },\n { once: true }\n )\n\n realWebSocket.addEventListener('message', (event) => {\n // Dispatch the \"incoming\" transport event instead of\n // invoking the internal handler directly. This way,\n // anyone can listen to the \"incoming\" event but this\n // class is the one resulting in it.\n this.transport.dispatchEvent(\n bindEvent(\n this.realWebSocket!,\n new MessageEvent('incoming', {\n data: event.data,\n origin: event.origin,\n })\n )\n )\n })\n\n // Close the original connection when the mock client closes.\n // E.g. \"client.close()\" was called. This is never forwarded anywhere.\n this.client.addEventListener(\n 'close',\n (event) => {\n this.handleMockClose(event)\n },\n {\n signal: this.mockCloseController.signal,\n }\n )\n\n // Forward the \"close\" event to let the interceptor handle\n // closures initiated by the original server.\n realWebSocket.addEventListener(\n 'close',\n (event) => {\n this.handleRealClose(event)\n },\n {\n signal: this.realCloseController.signal,\n }\n )\n\n realWebSocket.addEventListener('error', () => {\n const errorEvent = bindEvent(\n realWebSocket,\n new Event('error', { cancelable: true })\n )\n\n // Emit the \"error\" event on the `server` connection\n // to let the interceptor react to original server errors.\n this[kEmitter].dispatchEvent(errorEvent)\n\n // If the error event from the original server hasn't been prevented,\n // forward it to the underlying client.\n if (!errorEvent.defaultPrevented) {\n this.client.dispatchEvent(bindEvent(this.client, new Event('error')))\n }\n })\n\n this.realWebSocket = realWebSocket\n }\n\n /**\n * Listen for the incoming events from the original WebSocket server.\n */\n public addEventListener(\n event: EventType,\n listener: WebSocketEventListener,\n options?: AddEventListenerOptions | boolean\n ): void {\n if (!Reflect.has(listener, kBoundListener)) {\n const boundListener = listener.bind(this.client)\n\n // Store the bound listener on the original listener\n // so the exact bound function can be accessed in \"removeEventListener()\".\n Object.defineProperty(listener, kBoundListener, {\n value: boundListener,\n enumerable: false,\n })\n }\n\n this[kEmitter].addEventListener(\n event,\n Reflect.get(listener, kBoundListener) as EventListener,\n options\n )\n }\n\n /**\n * Remove the listener for the given event.\n */\n public removeEventListener(\n event: EventType,\n listener: WebSocketEventListener,\n options?: EventListenerOptions | boolean\n ): void {\n this[kEmitter].removeEventListener(\n event,\n Reflect.get(listener, kBoundListener) as EventListener,\n options\n )\n }\n\n /**\n * Send data to the original WebSocket server.\n * @example\n * server.send('hello')\n * server.send(new Blob(['hello']))\n * server.send(new TextEncoder().encode('hello'))\n */\n public send(data: WebSocketData): void {\n this[kSend](data)\n }\n\n private [kSend](data: WebSocketData): void {\n const { realWebSocket } = this\n\n invariant(\n realWebSocket,\n 'Failed to call \"server.send()\" for \"%s\": the connection is not open. Did you forget to call \"server.connect()\"?',\n this.client.url\n )\n\n // Silently ignore writes on the closed original WebSocket.\n if (\n realWebSocket.readyState === WebSocket.CLOSING ||\n realWebSocket.readyState === WebSocket.CLOSED\n ) {\n return\n }\n\n // Delegate the send to when the original connection is open.\n // Unlike the mock, connecting to the original server may take time\n // so we cannot call this on the next tick.\n if (realWebSocket.readyState === WebSocket.CONNECTING) {\n realWebSocket.addEventListener(\n 'open',\n () => {\n realWebSocket.send(data)\n },\n { once: true }\n )\n return\n }\n\n // Send the data to the original WebSocket server.\n realWebSocket.send(data)\n }\n\n /**\n * Close the actual server connection.\n */\n public close(): void {\n const { realWebSocket } = this\n\n invariant(\n realWebSocket,\n 'Failed to close server connection for \"%s\": the connection is not open. Did you forget to call \"server.connect()\"?',\n this.client.url\n )\n\n // Remove the \"close\" event listener from the server\n // so it doesn't close the underlying WebSocket client\n // when you call \"server.close()\". This also prevents the\n // `close` event on the `server` connection from being dispatched twice.\n this.realCloseController.abort()\n\n if (\n realWebSocket.readyState === WebSocket.CLOSING ||\n realWebSocket.readyState === WebSocket.CLOSED\n ) {\n return\n }\n\n // Close the actual client connection.\n realWebSocket.close()\n\n // Dispatch the \"close\" event on the `server` connection.\n queueMicrotask(() => {\n this[kEmitter].dispatchEvent(\n bindEvent(\n this.realWebSocket,\n new CancelableCloseEvent('close', {\n /**\n * @note `server.close()` in the interceptor\n * always results in clean closures.\n */\n code: 1000,\n cancelable: true,\n })\n )\n )\n })\n }\n\n private handleIncomingMessage(event: MessageEvent): void {\n // Clone the event to dispatch it on this class\n // once again and prevent the \"already being dispatched\"\n // exception. Clone it here so we can observe this event\n // being prevented in the \"server.on()\" listeners.\n const messageEvent = bindEvent(\n event.target,\n new CancelableMessageEvent('message', {\n data: event.data,\n origin: event.origin,\n cancelable: true,\n })\n )\n\n /**\n * @note Emit \"message\" event on the server connection\n * instance to let the interceptor know about these\n * incoming events from the original server. In that listener,\n * the interceptor can modify or skip the event forwarding\n * to the mock WebSocket instance.\n */\n this[kEmitter].dispatchEvent(messageEvent)\n\n /**\n * @note Forward the incoming server events to the client.\n * Preventing the default on the message event stops this.\n */\n if (!messageEvent.defaultPrevented) {\n this.client.dispatchEvent(\n bindEvent(\n /**\n * @note Bind the forwarded original server events\n * to the mock WebSocket instance so it would\n * dispatch them straight away.\n */\n this.client,\n // Clone the message event again to prevent\n // the \"already being dispatched\" exception.\n new MessageEvent('message', {\n data: event.data,\n origin: event.origin,\n })\n )\n )\n }\n }\n\n private handleMockClose(_event: Event): void {\n // Close the original connection if the mock client closes.\n if (this.realWebSocket) {\n this.realWebSocket.close()\n }\n }\n\n private handleRealClose(event: CloseEvent): void {\n // For closures originating from the original server,\n // remove the \"close\" listener from the mock client.\n // original close -> (?) client[kClose]() --X--> \"close\" (again).\n this.mockCloseController.abort()\n\n const closeEvent = bindEvent(\n this.realWebSocket,\n new CancelableCloseEvent('close', {\n code: event.code,\n reason: event.reason,\n wasClean: event.wasClean,\n cancelable: true,\n })\n )\n\n this[kEmitter].dispatchEvent(closeEvent)\n\n // If the close event from the server hasn't been prevented,\n // forward the closure to the mock client.\n if (!closeEvent.defaultPrevented) {\n // Close the intercepted client forcefully to\n // allow non-configurable status codes from the server.\n // If the socket has been closed by now, no harm calling\n // this again—it will have no effect.\n this.client[kClose](event.code, event.reason)\n }\n }\n}\n","import { invariant } from 'outvariant'\nimport type { WebSocketData } from './WebSocketTransport'\nimport { bindEvent } from './utils/bindEvent'\nimport { CloseEvent } from './utils/events'\nimport { DeferredPromise } from '@open-draft/deferred-promise'\n\nexport type WebSocketEventListener<\n EventType extends WebSocketEventMap[keyof WebSocketEventMap] = Event\n> = (this: WebSocket, event: EventType) => void\n\nconst WEBSOCKET_CLOSE_CODE_RANGE_ERROR =\n 'InvalidAccessError: close code out of user configurable range'\n\nexport const kPassthroughPromise = Symbol('kPassthroughPromise')\nexport const kOnSend = Symbol('kOnSend')\nexport const kClose = Symbol('kClose')\n\nexport class WebSocketOverride extends EventTarget implements WebSocket {\n static readonly CONNECTING = 0\n static readonly OPEN = 1\n static readonly CLOSING = 2\n static readonly CLOSED = 3\n readonly CONNECTING = 0\n readonly OPEN = 1\n readonly CLOSING = 2\n readonly CLOSED = 3\n\n public url: string\n public protocol: string\n public extensions: string\n public binaryType: BinaryType\n public readyState: number\n public bufferedAmount: number\n\n private _onopen: WebSocketEventListener | null = null\n private _onmessage: WebSocketEventListener<\n MessageEvent\n > | null = null\n private _onerror: WebSocketEventListener | null = null\n private _onclose: WebSocketEventListener | null = null\n\n private [kPassthroughPromise]: DeferredPromise\n private [kOnSend]?: (data: WebSocketData) => void\n\n constructor(url: string | URL, protocols?: string | Array) {\n super()\n this.url = url.toString()\n this.protocol = ''\n this.extensions = ''\n this.binaryType = 'blob'\n this.readyState = this.CONNECTING\n this.bufferedAmount = 0\n\n this[kPassthroughPromise] = new DeferredPromise()\n\n queueMicrotask(async () => {\n if (await this[kPassthroughPromise]) {\n return\n }\n\n this.protocol =\n typeof protocols === 'string'\n ? protocols\n : Array.isArray(protocols) && protocols.length > 0\n ? protocols[0]\n : ''\n\n /**\n * @note Check that nothing has prevented this connection\n * (e.g. called `client.close()` in the connection listener).\n * If the connection has been prevented, never dispatch the open event,.\n */\n if (this.readyState === this.CONNECTING) {\n this.readyState = this.OPEN\n this.dispatchEvent(bindEvent(this, new Event('open')))\n }\n })\n }\n\n set onopen(listener: WebSocketEventListener | null) {\n this.removeEventListener('open', this._onopen)\n this._onopen = listener\n if (listener !== null) {\n this.addEventListener('open', listener)\n }\n }\n get onopen(): WebSocketEventListener | null {\n return this._onopen\n }\n\n set onmessage(\n listener: WebSocketEventListener> | null\n ) {\n this.removeEventListener(\n 'message',\n this._onmessage as WebSocketEventListener\n )\n this._onmessage = listener\n if (listener !== null) {\n this.addEventListener('message', listener)\n }\n }\n get onmessage(): WebSocketEventListener> | null {\n return this._onmessage\n }\n\n set onerror(listener: WebSocketEventListener | null) {\n this.removeEventListener('error', this._onerror)\n this._onerror = listener\n if (listener !== null) {\n this.addEventListener('error', listener)\n }\n }\n get onerror(): WebSocketEventListener | null {\n return this._onerror\n }\n\n set onclose(listener: WebSocketEventListener | null) {\n this.removeEventListener('close', this._onclose as WebSocketEventListener)\n this._onclose = listener\n if (listener !== null) {\n this.addEventListener('close', listener)\n }\n }\n get onclose(): WebSocketEventListener | null {\n return this._onclose\n }\n\n /**\n * @see https://websockets.spec.whatwg.org/#ref-for-dom-websocket-send%E2%91%A0\n */\n public send(data: WebSocketData): void {\n if (this.readyState === this.CONNECTING) {\n this.close()\n throw new DOMException('InvalidStateError')\n }\n\n // Sending when the socket is about to close\n // discards the sent data.\n if (this.readyState === this.CLOSING || this.readyState === this.CLOSED) {\n return\n }\n\n // Buffer the data to send in this even loop\n // but send it in the next.\n this.bufferedAmount += getDataSize(data)\n\n queueMicrotask(() => {\n // This is a bit optimistic but since no actual data transfer\n // is involved, all the data will be \"sent\" on the next tick.\n this.bufferedAmount = 0\n\n /**\n * @note Notify the parent about outgoing data.\n * This notifies the transport and the connection\n * listens to the outgoing data to emit the \"message\" event.\n */\n this[kOnSend]?.(data)\n })\n }\n\n public close(code: number = 1000, reason?: string): void {\n invariant(code, WEBSOCKET_CLOSE_CODE_RANGE_ERROR)\n invariant(\n code === 1000 || (code >= 3000 && code <= 4999),\n WEBSOCKET_CLOSE_CODE_RANGE_ERROR\n )\n\n this[kClose](code, reason)\n }\n\n private [kClose](\n code: number = 1000,\n reason?: string,\n wasClean = true\n ): void {\n /**\n * @note Move this check here so that even internall closures,\n * like those triggered by the `server` connection, are not\n * performed twice.\n */\n if (this.readyState === this.CLOSING || this.readyState === this.CLOSED) {\n return\n }\n\n this.readyState = this.CLOSING\n\n queueMicrotask(() => {\n this.readyState = this.CLOSED\n\n this.dispatchEvent(\n bindEvent(\n this,\n new CloseEvent('close', {\n code,\n reason,\n wasClean,\n })\n )\n )\n\n // Remove all event listeners once the socket is closed.\n this._onopen = null\n this._onmessage = null\n this._onerror = null\n this._onclose = null\n })\n }\n\n public addEventListener(\n type: K,\n listener: (this: WebSocket, event: WebSocketEventMap[K]) => void,\n options?: boolean | AddEventListenerOptions\n ): void\n public addEventListener(\n type: string,\n listener: EventListenerOrEventListenerObject,\n options?: boolean | AddEventListenerOptions\n ): void\n public addEventListener(\n type: unknown,\n listener: unknown,\n options?: unknown\n ): void {\n return super.addEventListener(\n type as string,\n listener as EventListener,\n options as AddEventListenerOptions\n )\n }\n\n removeEventListener(\n type: K,\n callback: EventListenerOrEventListenerObject | null,\n options?: boolean | EventListenerOptions\n ): void {\n return super.removeEventListener(type, callback, options)\n }\n}\n\nfunction getDataSize(data: WebSocketData): number {\n if (typeof data === 'string') {\n return data.length\n }\n\n if (data instanceof Blob) {\n return data.size\n }\n\n return data.byteLength\n}\n","import { bindEvent } from './utils/bindEvent'\nimport {\n StrictEventListenerOrEventListenerObject,\n WebSocketData,\n WebSocketTransport,\n WebSocketTransportEventMap,\n} from './WebSocketTransport'\nimport { kOnSend, kClose, WebSocketOverride } from './WebSocketOverride'\nimport { CancelableMessageEvent, CloseEvent } from './utils/events'\n\n/**\n * Abstraction over the given mock `WebSocket` instance that allows\n * for controlling that instance (e.g. sending and receiving messages).\n */\nexport class WebSocketClassTransport\n extends EventTarget\n implements WebSocketTransport\n{\n constructor(protected readonly socket: WebSocketOverride) {\n super()\n\n // Emit the \"close\" event on the transport if the close\n // originates from the WebSocket client. E.g. the application\n // calls \"ws.close()\", not the interceptor.\n this.socket.addEventListener('close', (event) => {\n this.dispatchEvent(bindEvent(this.socket, new CloseEvent('close', event)))\n })\n\n /**\n * Emit the \"outgoing\" event on the transport\n * whenever the WebSocket client sends data (\"ws.send()\").\n */\n this.socket[kOnSend] = (data) => {\n this.dispatchEvent(\n bindEvent(\n this.socket,\n // Dispatch this as cancelable because \"client\" connection\n // re-creates this message event (cannot dispatch the same event).\n new CancelableMessageEvent('outgoing', {\n data,\n origin: this.socket.url,\n cancelable: true,\n })\n )\n )\n }\n }\n\n public addEventListener(\n type: EventType,\n callback: StrictEventListenerOrEventListenerObject<\n WebSocketTransportEventMap[EventType]\n > | null,\n options?: boolean | AddEventListenerOptions\n ): void {\n return super.addEventListener(type, callback as EventListener, options)\n }\n\n public dispatchEvent(\n event: WebSocketTransportEventMap[EventType]\n ): boolean {\n return super.dispatchEvent(event)\n }\n\n public send(data: WebSocketData): void {\n queueMicrotask(() => {\n if (\n this.socket.readyState === this.socket.CLOSING ||\n this.socket.readyState === this.socket.CLOSED\n ) {\n return\n }\n\n const dispatchEvent = () => {\n this.socket.dispatchEvent(\n bindEvent(\n /**\n * @note Setting this event's \"target\" to the\n * WebSocket override instance is important.\n * This way it can tell apart original incoming events\n * (must be forwarded to the transport) from the\n * mocked message events like the one below\n * (must be dispatched on the client instance).\n */\n this.socket,\n new MessageEvent('message', {\n data,\n origin: this.socket.url,\n })\n )\n )\n }\n\n if (this.socket.readyState === this.socket.CONNECTING) {\n this.socket.addEventListener(\n 'open',\n () => {\n dispatchEvent()\n },\n { once: true }\n )\n } else {\n dispatchEvent()\n }\n })\n }\n\n public close(code: number, reason?: string): void {\n /**\n * @note Call the internal close method directly\n * to allow closing the connection with the status codes\n * that are non-configurable by the user (> 1000 <= 1015).\n */\n this.socket[kClose](code, reason)\n }\n}\n","import { Interceptor } from '../../Interceptor'\nimport {\n type WebSocketClientConnectionProtocol,\n WebSocketClientConnection,\n} from './WebSocketClientConnection'\nimport { WebSocketServerConnection } from './WebSocketServerConnection'\nimport { WebSocketClassTransport } from './WebSocketClassTransport'\nimport {\n kClose,\n kPassthroughPromise,\n WebSocketOverride,\n} from './WebSocketOverride'\nimport { bindEvent } from './utils/bindEvent'\nimport { hasConfigurableGlobal } from '../../utils/hasConfigurableGlobal'\n\nexport { type WebSocketData, WebSocketTransport } from './WebSocketTransport'\nexport {\n WebSocketClientConnection,\n WebSocketClientConnectionProtocol,\n WebSocketServerConnection,\n}\n\nexport type WebSocketEventMap = {\n connection: [args: WebSocketConnectionData]\n}\n\nexport type WebSocketConnectionData = {\n /**\n * The incoming WebSocket client connection.\n */\n client: WebSocketClientConnection\n\n /**\n * The original WebSocket server connection.\n */\n server: WebSocketServerConnection\n\n /**\n * The connection information.\n */\n info: {\n /**\n * The protocols supported by the WebSocket client.\n */\n protocols: string | Array | undefined\n }\n}\n\n/**\n * Intercept the outgoing WebSocket connections created using\n * the global `WebSocket` class.\n */\nexport class WebSocketInterceptor extends Interceptor {\n static symbol = Symbol('websocket')\n\n constructor() {\n super(WebSocketInterceptor.symbol)\n }\n\n protected checkEnvironment(): boolean {\n return hasConfigurableGlobal('WebSocket')\n }\n\n protected setup(): void {\n const originalWebSocketDescriptor = Object.getOwnPropertyDescriptor(\n globalThis,\n 'WebSocket'\n )\n\n const WebSocketProxy = new Proxy(globalThis.WebSocket, {\n construct: (\n target,\n args: ConstructorParameters,\n newTarget\n ) => {\n const [url, protocols] = args\n\n const createConnection = (): WebSocket => {\n return Reflect.construct(target, args, newTarget)\n }\n\n // All WebSocket instances are mocked and don't forward\n // any events to the original server (no connection established).\n // To forward the events, the user must use the \"server.send()\" API.\n const socket = new WebSocketOverride(url, protocols)\n const transport = new WebSocketClassTransport(socket)\n\n // Emit the \"connection\" event to the interceptor on the next tick\n // so the client can modify WebSocket options, like \"binaryType\"\n // while the connection is already pending.\n queueMicrotask(() => {\n try {\n const server = new WebSocketServerConnection(\n socket,\n transport,\n createConnection\n )\n\n // The \"globalThis.WebSocket\" class stands for\n // the client-side connection. Assume it's established\n // as soon as the WebSocket instance is constructed.\n const hasConnectionListeners = this.emitter.emit('connection', {\n client: new WebSocketClientConnection(socket, transport),\n server,\n info: {\n protocols,\n },\n })\n\n if (hasConnectionListeners) {\n socket[kPassthroughPromise].resolve(false)\n } else {\n socket[kPassthroughPromise].resolve(true)\n\n server.connect()\n\n // Forward the \"open\" event from the original server\n // to the mock WebSocket client in the case of a passthrough connection.\n server.addEventListener('open', () => {\n socket.dispatchEvent(bindEvent(socket, new Event('open')))\n\n // Forward the original connection protocol to the\n // mock WebSocket client.\n if (server['realWebSocket']) {\n socket.protocol = server['realWebSocket'].protocol\n }\n })\n }\n } catch (error) {\n /**\n * @note Translate unhandled exceptions during the connection\n * handling (i.e. interceptor exceptions) as WebSocket connection\n * closures with error. This prevents from the exceptions occurring\n * in `queueMicrotask` from being process-wide and uncatchable.\n */\n if (error instanceof Error) {\n socket.dispatchEvent(new Event('error'))\n\n // No need to close the connection if it's already being closed.\n // E.g. the interceptor called `client.close()` and then threw an error.\n if (\n socket.readyState !== WebSocket.CLOSING &&\n socket.readyState !== WebSocket.CLOSED\n ) {\n socket[kClose](1011, error.message, false)\n }\n\n console.error(error)\n }\n }\n })\n\n return socket\n },\n })\n\n Object.defineProperty(globalThis, 'WebSocket', {\n value: WebSocketProxy,\n configurable: true,\n })\n\n this.subscriptions.push(() => {\n Object.defineProperty(\n globalThis,\n 'WebSocket',\n originalWebSocketDescriptor!\n )\n })\n }\n}\n"]} \ No newline at end of file diff --git a/node_modules/@mswjs/interceptors/lib/browser/interceptors/WebSocket/index.mjs b/node_modules/@mswjs/interceptors/lib/browser/interceptors/WebSocket/index.mjs new file mode 100644 index 0000000000000000000000000000000000000000..23e52ec202ed40109654189fa9f721968b430a49 --- /dev/null +++ b/node_modules/@mswjs/interceptors/lib/browser/interceptors/WebSocket/index.mjs @@ -0,0 +1,710 @@ +import { + hasConfigurableGlobal +} from "../../chunk-TX5GBTFY.mjs"; +import { + Interceptor, + createRequestId +} from "../../chunk-QED3Q6Z2.mjs"; + +// src/interceptors/WebSocket/utils/bindEvent.ts +function bindEvent(target, event) { + Object.defineProperties(event, { + target: { + value: target, + enumerable: true, + writable: true + }, + currentTarget: { + value: target, + enumerable: true, + writable: true + } + }); + return event; +} + +// src/interceptors/WebSocket/utils/events.ts +var kCancelable = Symbol("kCancelable"); +var kDefaultPrevented = Symbol("kDefaultPrevented"); +var CancelableMessageEvent = class extends MessageEvent { + constructor(type, init) { + super(type, init); + this[kCancelable] = !!init.cancelable; + this[kDefaultPrevented] = false; + } + get cancelable() { + return this[kCancelable]; + } + set cancelable(nextCancelable) { + this[kCancelable] = nextCancelable; + } + get defaultPrevented() { + return this[kDefaultPrevented]; + } + set defaultPrevented(nextDefaultPrevented) { + this[kDefaultPrevented] = nextDefaultPrevented; + } + preventDefault() { + if (this.cancelable && !this[kDefaultPrevented]) { + this[kDefaultPrevented] = true; + } + } +}; +kCancelable, kDefaultPrevented; +var CloseEvent = class extends Event { + constructor(type, init = {}) { + super(type, init); + this.code = init.code === void 0 ? 0 : init.code; + this.reason = init.reason === void 0 ? "" : init.reason; + this.wasClean = init.wasClean === void 0 ? false : init.wasClean; + } +}; +var CancelableCloseEvent = class extends CloseEvent { + constructor(type, init = {}) { + super(type, init); + this[kCancelable] = !!init.cancelable; + this[kDefaultPrevented] = false; + } + get cancelable() { + return this[kCancelable]; + } + set cancelable(nextCancelable) { + this[kCancelable] = nextCancelable; + } + get defaultPrevented() { + return this[kDefaultPrevented]; + } + set defaultPrevented(nextDefaultPrevented) { + this[kDefaultPrevented] = nextDefaultPrevented; + } + preventDefault() { + if (this.cancelable && !this[kDefaultPrevented]) { + this[kDefaultPrevented] = true; + } + } +}; +kCancelable, kDefaultPrevented; + +// src/interceptors/WebSocket/WebSocketClientConnection.ts +var kEmitter = Symbol("kEmitter"); +var kBoundListener = Symbol("kBoundListener"); +var WebSocketClientConnection = class { + constructor(socket, transport) { + this.socket = socket; + this.transport = transport; + this.id = createRequestId(); + this.url = new URL(socket.url); + this[kEmitter] = new EventTarget(); + this.transport.addEventListener("outgoing", (event) => { + const message = bindEvent( + this.socket, + new CancelableMessageEvent("message", { + data: event.data, + origin: event.origin, + cancelable: true + }) + ); + this[kEmitter].dispatchEvent(message); + if (message.defaultPrevented) { + event.preventDefault(); + } + }); + this.transport.addEventListener("close", (event) => { + this[kEmitter].dispatchEvent( + bindEvent(this.socket, new CloseEvent("close", event)) + ); + }); + } + /** + * Listen for the outgoing events from the connected WebSocket client. + */ + addEventListener(type, listener, options) { + if (!Reflect.has(listener, kBoundListener)) { + const boundListener = listener.bind(this.socket); + Object.defineProperty(listener, kBoundListener, { + value: boundListener, + enumerable: false, + configurable: false + }); + } + this[kEmitter].addEventListener( + type, + Reflect.get(listener, kBoundListener), + options + ); + } + /** + * Removes the listener for the given event. + */ + removeEventListener(event, listener, options) { + this[kEmitter].removeEventListener( + event, + Reflect.get(listener, kBoundListener), + options + ); + } + /** + * Send data to the connected client. + */ + send(data) { + this.transport.send(data); + } + /** + * Close the WebSocket connection. + * @param {number} code A status code (see https://www.rfc-editor.org/rfc/rfc6455#section-7.4.1). + * @param {string} reason A custom connection close reason. + */ + close(code, reason) { + this.transport.close(code, reason); + } +}; +kEmitter; + +// src/interceptors/WebSocket/WebSocketServerConnection.ts +import { invariant as invariant2 } from "outvariant"; + +// src/interceptors/WebSocket/WebSocketOverride.ts +import { invariant } from "outvariant"; +import { DeferredPromise } from "@open-draft/deferred-promise"; +var WEBSOCKET_CLOSE_CODE_RANGE_ERROR = "InvalidAccessError: close code out of user configurable range"; +var kPassthroughPromise = Symbol("kPassthroughPromise"); +var kOnSend = Symbol("kOnSend"); +var kClose = Symbol("kClose"); +var WebSocketOverride = class extends EventTarget { + constructor(url, protocols) { + super(); + this.CONNECTING = 0; + this.OPEN = 1; + this.CLOSING = 2; + this.CLOSED = 3; + this._onopen = null; + this._onmessage = null; + this._onerror = null; + this._onclose = null; + this.url = url.toString(); + this.protocol = ""; + this.extensions = ""; + this.binaryType = "blob"; + this.readyState = this.CONNECTING; + this.bufferedAmount = 0; + this[kPassthroughPromise] = new DeferredPromise(); + queueMicrotask(async () => { + if (await this[kPassthroughPromise]) { + return; + } + this.protocol = typeof protocols === "string" ? protocols : Array.isArray(protocols) && protocols.length > 0 ? protocols[0] : ""; + if (this.readyState === this.CONNECTING) { + this.readyState = this.OPEN; + this.dispatchEvent(bindEvent(this, new Event("open"))); + } + }); + } + set onopen(listener) { + this.removeEventListener("open", this._onopen); + this._onopen = listener; + if (listener !== null) { + this.addEventListener("open", listener); + } + } + get onopen() { + return this._onopen; + } + set onmessage(listener) { + this.removeEventListener( + "message", + this._onmessage + ); + this._onmessage = listener; + if (listener !== null) { + this.addEventListener("message", listener); + } + } + get onmessage() { + return this._onmessage; + } + set onerror(listener) { + this.removeEventListener("error", this._onerror); + this._onerror = listener; + if (listener !== null) { + this.addEventListener("error", listener); + } + } + get onerror() { + return this._onerror; + } + set onclose(listener) { + this.removeEventListener("close", this._onclose); + this._onclose = listener; + if (listener !== null) { + this.addEventListener("close", listener); + } + } + get onclose() { + return this._onclose; + } + /** + * @see https://websockets.spec.whatwg.org/#ref-for-dom-websocket-send%E2%91%A0 + */ + send(data) { + if (this.readyState === this.CONNECTING) { + this.close(); + throw new DOMException("InvalidStateError"); + } + if (this.readyState === this.CLOSING || this.readyState === this.CLOSED) { + return; + } + this.bufferedAmount += getDataSize(data); + queueMicrotask(() => { + var _a; + this.bufferedAmount = 0; + (_a = this[kOnSend]) == null ? void 0 : _a.call(this, data); + }); + } + close(code = 1e3, reason) { + invariant(code, WEBSOCKET_CLOSE_CODE_RANGE_ERROR); + invariant( + code === 1e3 || code >= 3e3 && code <= 4999, + WEBSOCKET_CLOSE_CODE_RANGE_ERROR + ); + this[kClose](code, reason); + } + [(kPassthroughPromise, kOnSend, kClose)](code = 1e3, reason, wasClean = true) { + if (this.readyState === this.CLOSING || this.readyState === this.CLOSED) { + return; + } + this.readyState = this.CLOSING; + queueMicrotask(() => { + this.readyState = this.CLOSED; + this.dispatchEvent( + bindEvent( + this, + new CloseEvent("close", { + code, + reason, + wasClean + }) + ) + ); + this._onopen = null; + this._onmessage = null; + this._onerror = null; + this._onclose = null; + }); + } + addEventListener(type, listener, options) { + return super.addEventListener( + type, + listener, + options + ); + } + removeEventListener(type, callback, options) { + return super.removeEventListener(type, callback, options); + } +}; +WebSocketOverride.CONNECTING = 0; +WebSocketOverride.OPEN = 1; +WebSocketOverride.CLOSING = 2; +WebSocketOverride.CLOSED = 3; +function getDataSize(data) { + if (typeof data === "string") { + return data.length; + } + if (data instanceof Blob) { + return data.size; + } + return data.byteLength; +} + +// src/interceptors/WebSocket/WebSocketServerConnection.ts +var kEmitter2 = Symbol("kEmitter"); +var kBoundListener2 = Symbol("kBoundListener"); +var kSend = Symbol("kSend"); +var WebSocketServerConnection = class { + constructor(client, transport, createConnection) { + this.client = client; + this.transport = transport; + this.createConnection = createConnection; + this[kEmitter2] = new EventTarget(); + this.mockCloseController = new AbortController(); + this.realCloseController = new AbortController(); + this.transport.addEventListener("outgoing", (event) => { + if (typeof this.realWebSocket === "undefined") { + return; + } + queueMicrotask(() => { + if (!event.defaultPrevented) { + this[kSend](event.data); + } + }); + }); + this.transport.addEventListener( + "incoming", + this.handleIncomingMessage.bind(this) + ); + } + /** + * The `WebSocket` instance connected to the original server. + * Accessing this before calling `server.connect()` will throw. + */ + get socket() { + invariant2( + this.realWebSocket, + 'Cannot access "socket" on the original WebSocket server object: the connection is not open. Did you forget to call `server.connect()`?' + ); + return this.realWebSocket; + } + /** + * Open connection to the original WebSocket server. + */ + connect() { + invariant2( + !this.realWebSocket || this.realWebSocket.readyState !== WebSocket.OPEN, + 'Failed to call "connect()" on the original WebSocket instance: the connection already open' + ); + const realWebSocket = this.createConnection(); + realWebSocket.binaryType = this.client.binaryType; + realWebSocket.addEventListener( + "open", + (event) => { + this[kEmitter2].dispatchEvent( + bindEvent(this.realWebSocket, new Event("open", event)) + ); + }, + { once: true } + ); + realWebSocket.addEventListener("message", (event) => { + this.transport.dispatchEvent( + bindEvent( + this.realWebSocket, + new MessageEvent("incoming", { + data: event.data, + origin: event.origin + }) + ) + ); + }); + this.client.addEventListener( + "close", + (event) => { + this.handleMockClose(event); + }, + { + signal: this.mockCloseController.signal + } + ); + realWebSocket.addEventListener( + "close", + (event) => { + this.handleRealClose(event); + }, + { + signal: this.realCloseController.signal + } + ); + realWebSocket.addEventListener("error", () => { + const errorEvent = bindEvent( + realWebSocket, + new Event("error", { cancelable: true }) + ); + this[kEmitter2].dispatchEvent(errorEvent); + if (!errorEvent.defaultPrevented) { + this.client.dispatchEvent(bindEvent(this.client, new Event("error"))); + } + }); + this.realWebSocket = realWebSocket; + } + /** + * Listen for the incoming events from the original WebSocket server. + */ + addEventListener(event, listener, options) { + if (!Reflect.has(listener, kBoundListener2)) { + const boundListener = listener.bind(this.client); + Object.defineProperty(listener, kBoundListener2, { + value: boundListener, + enumerable: false + }); + } + this[kEmitter2].addEventListener( + event, + Reflect.get(listener, kBoundListener2), + options + ); + } + /** + * Remove the listener for the given event. + */ + removeEventListener(event, listener, options) { + this[kEmitter2].removeEventListener( + event, + Reflect.get(listener, kBoundListener2), + options + ); + } + /** + * Send data to the original WebSocket server. + * @example + * server.send('hello') + * server.send(new Blob(['hello'])) + * server.send(new TextEncoder().encode('hello')) + */ + send(data) { + this[kSend](data); + } + [(kEmitter2, kSend)](data) { + const { realWebSocket } = this; + invariant2( + realWebSocket, + 'Failed to call "server.send()" for "%s": the connection is not open. Did you forget to call "server.connect()"?', + this.client.url + ); + if (realWebSocket.readyState === WebSocket.CLOSING || realWebSocket.readyState === WebSocket.CLOSED) { + return; + } + if (realWebSocket.readyState === WebSocket.CONNECTING) { + realWebSocket.addEventListener( + "open", + () => { + realWebSocket.send(data); + }, + { once: true } + ); + return; + } + realWebSocket.send(data); + } + /** + * Close the actual server connection. + */ + close() { + const { realWebSocket } = this; + invariant2( + realWebSocket, + 'Failed to close server connection for "%s": the connection is not open. Did you forget to call "server.connect()"?', + this.client.url + ); + this.realCloseController.abort(); + if (realWebSocket.readyState === WebSocket.CLOSING || realWebSocket.readyState === WebSocket.CLOSED) { + return; + } + realWebSocket.close(); + queueMicrotask(() => { + this[kEmitter2].dispatchEvent( + bindEvent( + this.realWebSocket, + new CancelableCloseEvent("close", { + /** + * @note `server.close()` in the interceptor + * always results in clean closures. + */ + code: 1e3, + cancelable: true + }) + ) + ); + }); + } + handleIncomingMessage(event) { + const messageEvent = bindEvent( + event.target, + new CancelableMessageEvent("message", { + data: event.data, + origin: event.origin, + cancelable: true + }) + ); + this[kEmitter2].dispatchEvent(messageEvent); + if (!messageEvent.defaultPrevented) { + this.client.dispatchEvent( + bindEvent( + /** + * @note Bind the forwarded original server events + * to the mock WebSocket instance so it would + * dispatch them straight away. + */ + this.client, + // Clone the message event again to prevent + // the "already being dispatched" exception. + new MessageEvent("message", { + data: event.data, + origin: event.origin + }) + ) + ); + } + } + handleMockClose(_event) { + if (this.realWebSocket) { + this.realWebSocket.close(); + } + } + handleRealClose(event) { + this.mockCloseController.abort(); + const closeEvent = bindEvent( + this.realWebSocket, + new CancelableCloseEvent("close", { + code: event.code, + reason: event.reason, + wasClean: event.wasClean, + cancelable: true + }) + ); + this[kEmitter2].dispatchEvent(closeEvent); + if (!closeEvent.defaultPrevented) { + this.client[kClose](event.code, event.reason); + } + } +}; + +// src/interceptors/WebSocket/WebSocketClassTransport.ts +var WebSocketClassTransport = class extends EventTarget { + constructor(socket) { + super(); + this.socket = socket; + this.socket.addEventListener("close", (event) => { + this.dispatchEvent(bindEvent(this.socket, new CloseEvent("close", event))); + }); + this.socket[kOnSend] = (data) => { + this.dispatchEvent( + bindEvent( + this.socket, + // Dispatch this as cancelable because "client" connection + // re-creates this message event (cannot dispatch the same event). + new CancelableMessageEvent("outgoing", { + data, + origin: this.socket.url, + cancelable: true + }) + ) + ); + }; + } + addEventListener(type, callback, options) { + return super.addEventListener(type, callback, options); + } + dispatchEvent(event) { + return super.dispatchEvent(event); + } + send(data) { + queueMicrotask(() => { + if (this.socket.readyState === this.socket.CLOSING || this.socket.readyState === this.socket.CLOSED) { + return; + } + const dispatchEvent = () => { + this.socket.dispatchEvent( + bindEvent( + /** + * @note Setting this event's "target" to the + * WebSocket override instance is important. + * This way it can tell apart original incoming events + * (must be forwarded to the transport) from the + * mocked message events like the one below + * (must be dispatched on the client instance). + */ + this.socket, + new MessageEvent("message", { + data, + origin: this.socket.url + }) + ) + ); + }; + if (this.socket.readyState === this.socket.CONNECTING) { + this.socket.addEventListener( + "open", + () => { + dispatchEvent(); + }, + { once: true } + ); + } else { + dispatchEvent(); + } + }); + } + close(code, reason) { + this.socket[kClose](code, reason); + } +}; + +// src/interceptors/WebSocket/index.ts +var _WebSocketInterceptor = class extends Interceptor { + constructor() { + super(_WebSocketInterceptor.symbol); + } + checkEnvironment() { + return hasConfigurableGlobal("WebSocket"); + } + setup() { + const originalWebSocketDescriptor = Object.getOwnPropertyDescriptor( + globalThis, + "WebSocket" + ); + const WebSocketProxy = new Proxy(globalThis.WebSocket, { + construct: (target, args, newTarget) => { + const [url, protocols] = args; + const createConnection = () => { + return Reflect.construct(target, args, newTarget); + }; + const socket = new WebSocketOverride(url, protocols); + const transport = new WebSocketClassTransport(socket); + queueMicrotask(() => { + try { + const server = new WebSocketServerConnection( + socket, + transport, + createConnection + ); + const hasConnectionListeners = this.emitter.emit("connection", { + client: new WebSocketClientConnection(socket, transport), + server, + info: { + protocols + } + }); + if (hasConnectionListeners) { + socket[kPassthroughPromise].resolve(false); + } else { + socket[kPassthroughPromise].resolve(true); + server.connect(); + server.addEventListener("open", () => { + socket.dispatchEvent(bindEvent(socket, new Event("open"))); + if (server["realWebSocket"]) { + socket.protocol = server["realWebSocket"].protocol; + } + }); + } + } catch (error) { + if (error instanceof Error) { + socket.dispatchEvent(new Event("error")); + if (socket.readyState !== WebSocket.CLOSING && socket.readyState !== WebSocket.CLOSED) { + socket[kClose](1011, error.message, false); + } + console.error(error); + } + } + }); + return socket; + } + }); + Object.defineProperty(globalThis, "WebSocket", { + value: WebSocketProxy, + configurable: true + }); + this.subscriptions.push(() => { + Object.defineProperty( + globalThis, + "WebSocket", + originalWebSocketDescriptor + ); + }); + } +}; +var WebSocketInterceptor = _WebSocketInterceptor; +WebSocketInterceptor.symbol = Symbol("websocket"); +export { + WebSocketClientConnection, + WebSocketInterceptor, + WebSocketServerConnection +}; +//# sourceMappingURL=index.mjs.map \ No newline at end of file diff --git a/node_modules/@mswjs/interceptors/lib/browser/interceptors/WebSocket/index.mjs.map b/node_modules/@mswjs/interceptors/lib/browser/interceptors/WebSocket/index.mjs.map new file mode 100644 index 0000000000000000000000000000000000000000..328d20569dcaa50bca132f4c87c41b003f591591 --- /dev/null +++ b/node_modules/@mswjs/interceptors/lib/browser/interceptors/WebSocket/index.mjs.map @@ -0,0 +1 @@ +{"version":3,"sources":["../../../../src/interceptors/WebSocket/utils/bindEvent.ts","../../../../src/interceptors/WebSocket/utils/events.ts","../../../../src/interceptors/WebSocket/WebSocketClientConnection.ts","../../../../src/interceptors/WebSocket/WebSocketServerConnection.ts","../../../../src/interceptors/WebSocket/WebSocketOverride.ts","../../../../src/interceptors/WebSocket/WebSocketClassTransport.ts","../../../../src/interceptors/WebSocket/index.ts"],"sourcesContent":["type EventWithTarget = E & { target: T }\n\nexport function bindEvent(\n target: T,\n event: E\n): EventWithTarget {\n Object.defineProperties(event, {\n target: {\n value: target,\n enumerable: true,\n writable: true,\n },\n currentTarget: {\n value: target,\n enumerable: true,\n writable: true,\n },\n })\n\n return event as EventWithTarget\n}\n","const kCancelable = Symbol('kCancelable')\nconst kDefaultPrevented = Symbol('kDefaultPrevented')\n\n/**\n * A `MessageEvent` superset that supports event cancellation\n * in Node.js. It's rather non-intrusive so it can be safely\n * used in the browser as well.\n *\n * @see https://github.com/nodejs/node/issues/51767\n */\nexport class CancelableMessageEvent extends MessageEvent {\n [kCancelable]: boolean;\n [kDefaultPrevented]: boolean\n\n constructor(type: string, init: MessageEventInit) {\n super(type, init)\n this[kCancelable] = !!init.cancelable\n this[kDefaultPrevented] = false\n }\n\n get cancelable() {\n return this[kCancelable]\n }\n\n set cancelable(nextCancelable) {\n this[kCancelable] = nextCancelable\n }\n\n get defaultPrevented() {\n return this[kDefaultPrevented]\n }\n\n set defaultPrevented(nextDefaultPrevented) {\n this[kDefaultPrevented] = nextDefaultPrevented\n }\n\n public preventDefault(): void {\n if (this.cancelable && !this[kDefaultPrevented]) {\n this[kDefaultPrevented] = true\n }\n }\n}\n\ninterface CloseEventInit extends EventInit {\n code?: number\n reason?: string\n wasClean?: boolean\n}\n\nexport class CloseEvent extends Event {\n public code: number\n public reason: string\n public wasClean: boolean\n\n constructor(type: string, init: CloseEventInit = {}) {\n super(type, init)\n this.code = init.code === undefined ? 0 : init.code\n this.reason = init.reason === undefined ? '' : init.reason\n this.wasClean = init.wasClean === undefined ? false : init.wasClean\n }\n}\n\nexport class CancelableCloseEvent extends CloseEvent {\n [kCancelable]: boolean;\n [kDefaultPrevented]: boolean\n\n constructor(type: string, init: CloseEventInit = {}) {\n super(type, init)\n this[kCancelable] = !!init.cancelable\n this[kDefaultPrevented] = false\n }\n\n get cancelable() {\n return this[kCancelable]\n }\n\n set cancelable(nextCancelable) {\n this[kCancelable] = nextCancelable\n }\n\n get defaultPrevented() {\n return this[kDefaultPrevented]\n }\n\n set defaultPrevented(nextDefaultPrevented) {\n this[kDefaultPrevented] = nextDefaultPrevented\n }\n\n public preventDefault(): void {\n if (this.cancelable && !this[kDefaultPrevented]) {\n this[kDefaultPrevented] = true\n }\n }\n}\n","import type { WebSocketData, WebSocketTransport } from './WebSocketTransport'\nimport type { WebSocketEventListener } from './WebSocketOverride'\nimport { bindEvent } from './utils/bindEvent'\nimport { CancelableMessageEvent, CloseEvent } from './utils/events'\nimport { createRequestId } from '../../createRequestId'\n\nconst kEmitter = Symbol('kEmitter')\nconst kBoundListener = Symbol('kBoundListener')\n\ninterface WebSocketClientEventMap {\n message: MessageEvent\n close: CloseEvent\n}\n\nexport interface WebSocketClientConnectionProtocol {\n id: string\n url: URL\n send(data: WebSocketData): void\n close(code?: number, reason?: string): void\n}\n\n/**\n * The WebSocket client instance represents an incoming\n * client connection. The user can control the connection,\n * send and receive events.\n */\nexport class WebSocketClientConnection\n implements WebSocketClientConnectionProtocol\n{\n public readonly id: string\n public readonly url: URL\n\n private [kEmitter]: EventTarget\n\n constructor(\n public readonly socket: WebSocket,\n private readonly transport: WebSocketTransport\n ) {\n this.id = createRequestId()\n this.url = new URL(socket.url)\n this[kEmitter] = new EventTarget()\n\n // Emit outgoing client data (\"ws.send()\") as \"message\"\n // events on the \"client\" connection.\n this.transport.addEventListener('outgoing', (event) => {\n const message = bindEvent(\n this.socket,\n new CancelableMessageEvent('message', {\n data: event.data,\n origin: event.origin,\n cancelable: true,\n })\n )\n\n this[kEmitter].dispatchEvent(message)\n\n // This is a bit silly but forward the cancellation state\n // of the \"client\" message event to the \"outgoing\" transport event.\n // This way, other agens (like \"server\" connection) can know\n // whether the client listener has pervented the default.\n if (message.defaultPrevented) {\n event.preventDefault()\n }\n })\n\n /**\n * Emit the \"close\" event on the \"client\" connection\n * whenever the underlying transport is closed.\n * @note \"client.close()\" does NOT dispatch the \"close\"\n * event on the WebSocket because it uses non-configurable\n * close status code. Thus, we listen to the transport\n * instead of the WebSocket's \"close\" event.\n */\n this.transport.addEventListener('close', (event) => {\n this[kEmitter].dispatchEvent(\n bindEvent(this.socket, new CloseEvent('close', event))\n )\n })\n }\n\n /**\n * Listen for the outgoing events from the connected WebSocket client.\n */\n public addEventListener(\n type: EventType,\n listener: WebSocketEventListener,\n options?: AddEventListenerOptions | boolean\n ): void {\n if (!Reflect.has(listener, kBoundListener)) {\n const boundListener = listener.bind(this.socket)\n\n // Store the bound listener on the original listener\n // so the exact bound function can be accessed in \"removeEventListener()\".\n Object.defineProperty(listener, kBoundListener, {\n value: boundListener,\n enumerable: false,\n configurable: false,\n })\n }\n\n this[kEmitter].addEventListener(\n type,\n Reflect.get(listener, kBoundListener) as EventListener,\n options\n )\n }\n\n /**\n * Removes the listener for the given event.\n */\n public removeEventListener(\n event: EventType,\n listener: WebSocketEventListener,\n options?: EventListenerOptions | boolean\n ): void {\n this[kEmitter].removeEventListener(\n event,\n Reflect.get(listener, kBoundListener) as EventListener,\n options\n )\n }\n\n /**\n * Send data to the connected client.\n */\n public send(data: WebSocketData): void {\n this.transport.send(data)\n }\n\n /**\n * Close the WebSocket connection.\n * @param {number} code A status code (see https://www.rfc-editor.org/rfc/rfc6455#section-7.4.1).\n * @param {string} reason A custom connection close reason.\n */\n public close(code?: number, reason?: string): void {\n this.transport.close(code, reason)\n }\n}\n","import { invariant } from 'outvariant'\nimport {\n kClose,\n WebSocketEventListener,\n WebSocketOverride,\n} from './WebSocketOverride'\nimport type { WebSocketData } from './WebSocketTransport'\nimport type { WebSocketClassTransport } from './WebSocketClassTransport'\nimport { bindEvent } from './utils/bindEvent'\nimport {\n CancelableMessageEvent,\n CancelableCloseEvent,\n CloseEvent,\n} from './utils/events'\n\nconst kEmitter = Symbol('kEmitter')\nconst kBoundListener = Symbol('kBoundListener')\nconst kSend = Symbol('kSend')\n\ninterface WebSocketServerEventMap {\n open: Event\n message: MessageEvent\n error: Event\n close: CloseEvent\n}\n\n/**\n * The WebSocket server instance represents the actual production\n * WebSocket server connection. It's idle by default but you can\n * establish it by calling `server.connect()`.\n */\nexport class WebSocketServerConnection {\n /**\n * A WebSocket instance connected to the original server.\n */\n private realWebSocket?: WebSocket\n private mockCloseController: AbortController\n private realCloseController: AbortController\n private [kEmitter]: EventTarget\n\n constructor(\n private readonly client: WebSocketOverride,\n private readonly transport: WebSocketClassTransport,\n private readonly createConnection: () => WebSocket\n ) {\n this[kEmitter] = new EventTarget()\n this.mockCloseController = new AbortController()\n this.realCloseController = new AbortController()\n\n // Automatically forward outgoing client events\n // to the actual server unless the outgoing message event\n // has been prevented. The \"outgoing\" transport event it\n // dispatched by the \"client\" connection.\n this.transport.addEventListener('outgoing', (event) => {\n // Ignore client messages if the server connection\n // hasn't been established yet. Nowhere to forward.\n if (typeof this.realWebSocket === 'undefined') {\n return\n }\n\n // Every outgoing client message can prevent this forwarding\n // by preventing the default of the outgoing message event.\n // This listener will be added before user-defined listeners,\n // so execute the logic on the next tick.\n queueMicrotask(() => {\n if (!event.defaultPrevented) {\n /**\n * @note Use the internal send mechanism so consumers can tell\n * apart direct user calls to `server.send()` and internal calls.\n * E.g. MSW has to ignore this internal call to log out messages correctly.\n */\n this[kSend](event.data)\n }\n })\n })\n\n this.transport.addEventListener(\n 'incoming',\n this.handleIncomingMessage.bind(this)\n )\n }\n\n /**\n * The `WebSocket` instance connected to the original server.\n * Accessing this before calling `server.connect()` will throw.\n */\n public get socket(): WebSocket {\n invariant(\n this.realWebSocket,\n 'Cannot access \"socket\" on the original WebSocket server object: the connection is not open. Did you forget to call `server.connect()`?'\n )\n\n return this.realWebSocket\n }\n\n /**\n * Open connection to the original WebSocket server.\n */\n public connect(): void {\n invariant(\n !this.realWebSocket || this.realWebSocket.readyState !== WebSocket.OPEN,\n 'Failed to call \"connect()\" on the original WebSocket instance: the connection already open'\n )\n\n const realWebSocket = this.createConnection()\n\n // Inherit the binary type from the mock WebSocket client.\n realWebSocket.binaryType = this.client.binaryType\n\n // Allow the interceptor to listen to when the server connection\n // has been established. This isn't necessary to operate with the connection\n // but may be beneficial in some cases (like conditionally adding logging).\n realWebSocket.addEventListener(\n 'open',\n (event) => {\n this[kEmitter].dispatchEvent(\n bindEvent(this.realWebSocket!, new Event('open', event))\n )\n },\n { once: true }\n )\n\n realWebSocket.addEventListener('message', (event) => {\n // Dispatch the \"incoming\" transport event instead of\n // invoking the internal handler directly. This way,\n // anyone can listen to the \"incoming\" event but this\n // class is the one resulting in it.\n this.transport.dispatchEvent(\n bindEvent(\n this.realWebSocket!,\n new MessageEvent('incoming', {\n data: event.data,\n origin: event.origin,\n })\n )\n )\n })\n\n // Close the original connection when the mock client closes.\n // E.g. \"client.close()\" was called. This is never forwarded anywhere.\n this.client.addEventListener(\n 'close',\n (event) => {\n this.handleMockClose(event)\n },\n {\n signal: this.mockCloseController.signal,\n }\n )\n\n // Forward the \"close\" event to let the interceptor handle\n // closures initiated by the original server.\n realWebSocket.addEventListener(\n 'close',\n (event) => {\n this.handleRealClose(event)\n },\n {\n signal: this.realCloseController.signal,\n }\n )\n\n realWebSocket.addEventListener('error', () => {\n const errorEvent = bindEvent(\n realWebSocket,\n new Event('error', { cancelable: true })\n )\n\n // Emit the \"error\" event on the `server` connection\n // to let the interceptor react to original server errors.\n this[kEmitter].dispatchEvent(errorEvent)\n\n // If the error event from the original server hasn't been prevented,\n // forward it to the underlying client.\n if (!errorEvent.defaultPrevented) {\n this.client.dispatchEvent(bindEvent(this.client, new Event('error')))\n }\n })\n\n this.realWebSocket = realWebSocket\n }\n\n /**\n * Listen for the incoming events from the original WebSocket server.\n */\n public addEventListener(\n event: EventType,\n listener: WebSocketEventListener,\n options?: AddEventListenerOptions | boolean\n ): void {\n if (!Reflect.has(listener, kBoundListener)) {\n const boundListener = listener.bind(this.client)\n\n // Store the bound listener on the original listener\n // so the exact bound function can be accessed in \"removeEventListener()\".\n Object.defineProperty(listener, kBoundListener, {\n value: boundListener,\n enumerable: false,\n })\n }\n\n this[kEmitter].addEventListener(\n event,\n Reflect.get(listener, kBoundListener) as EventListener,\n options\n )\n }\n\n /**\n * Remove the listener for the given event.\n */\n public removeEventListener(\n event: EventType,\n listener: WebSocketEventListener,\n options?: EventListenerOptions | boolean\n ): void {\n this[kEmitter].removeEventListener(\n event,\n Reflect.get(listener, kBoundListener) as EventListener,\n options\n )\n }\n\n /**\n * Send data to the original WebSocket server.\n * @example\n * server.send('hello')\n * server.send(new Blob(['hello']))\n * server.send(new TextEncoder().encode('hello'))\n */\n public send(data: WebSocketData): void {\n this[kSend](data)\n }\n\n private [kSend](data: WebSocketData): void {\n const { realWebSocket } = this\n\n invariant(\n realWebSocket,\n 'Failed to call \"server.send()\" for \"%s\": the connection is not open. Did you forget to call \"server.connect()\"?',\n this.client.url\n )\n\n // Silently ignore writes on the closed original WebSocket.\n if (\n realWebSocket.readyState === WebSocket.CLOSING ||\n realWebSocket.readyState === WebSocket.CLOSED\n ) {\n return\n }\n\n // Delegate the send to when the original connection is open.\n // Unlike the mock, connecting to the original server may take time\n // so we cannot call this on the next tick.\n if (realWebSocket.readyState === WebSocket.CONNECTING) {\n realWebSocket.addEventListener(\n 'open',\n () => {\n realWebSocket.send(data)\n },\n { once: true }\n )\n return\n }\n\n // Send the data to the original WebSocket server.\n realWebSocket.send(data)\n }\n\n /**\n * Close the actual server connection.\n */\n public close(): void {\n const { realWebSocket } = this\n\n invariant(\n realWebSocket,\n 'Failed to close server connection for \"%s\": the connection is not open. Did you forget to call \"server.connect()\"?',\n this.client.url\n )\n\n // Remove the \"close\" event listener from the server\n // so it doesn't close the underlying WebSocket client\n // when you call \"server.close()\". This also prevents the\n // `close` event on the `server` connection from being dispatched twice.\n this.realCloseController.abort()\n\n if (\n realWebSocket.readyState === WebSocket.CLOSING ||\n realWebSocket.readyState === WebSocket.CLOSED\n ) {\n return\n }\n\n // Close the actual client connection.\n realWebSocket.close()\n\n // Dispatch the \"close\" event on the `server` connection.\n queueMicrotask(() => {\n this[kEmitter].dispatchEvent(\n bindEvent(\n this.realWebSocket,\n new CancelableCloseEvent('close', {\n /**\n * @note `server.close()` in the interceptor\n * always results in clean closures.\n */\n code: 1000,\n cancelable: true,\n })\n )\n )\n })\n }\n\n private handleIncomingMessage(event: MessageEvent): void {\n // Clone the event to dispatch it on this class\n // once again and prevent the \"already being dispatched\"\n // exception. Clone it here so we can observe this event\n // being prevented in the \"server.on()\" listeners.\n const messageEvent = bindEvent(\n event.target,\n new CancelableMessageEvent('message', {\n data: event.data,\n origin: event.origin,\n cancelable: true,\n })\n )\n\n /**\n * @note Emit \"message\" event on the server connection\n * instance to let the interceptor know about these\n * incoming events from the original server. In that listener,\n * the interceptor can modify or skip the event forwarding\n * to the mock WebSocket instance.\n */\n this[kEmitter].dispatchEvent(messageEvent)\n\n /**\n * @note Forward the incoming server events to the client.\n * Preventing the default on the message event stops this.\n */\n if (!messageEvent.defaultPrevented) {\n this.client.dispatchEvent(\n bindEvent(\n /**\n * @note Bind the forwarded original server events\n * to the mock WebSocket instance so it would\n * dispatch them straight away.\n */\n this.client,\n // Clone the message event again to prevent\n // the \"already being dispatched\" exception.\n new MessageEvent('message', {\n data: event.data,\n origin: event.origin,\n })\n )\n )\n }\n }\n\n private handleMockClose(_event: Event): void {\n // Close the original connection if the mock client closes.\n if (this.realWebSocket) {\n this.realWebSocket.close()\n }\n }\n\n private handleRealClose(event: CloseEvent): void {\n // For closures originating from the original server,\n // remove the \"close\" listener from the mock client.\n // original close -> (?) client[kClose]() --X--> \"close\" (again).\n this.mockCloseController.abort()\n\n const closeEvent = bindEvent(\n this.realWebSocket,\n new CancelableCloseEvent('close', {\n code: event.code,\n reason: event.reason,\n wasClean: event.wasClean,\n cancelable: true,\n })\n )\n\n this[kEmitter].dispatchEvent(closeEvent)\n\n // If the close event from the server hasn't been prevented,\n // forward the closure to the mock client.\n if (!closeEvent.defaultPrevented) {\n // Close the intercepted client forcefully to\n // allow non-configurable status codes from the server.\n // If the socket has been closed by now, no harm calling\n // this again—it will have no effect.\n this.client[kClose](event.code, event.reason)\n }\n }\n}\n","import { invariant } from 'outvariant'\nimport type { WebSocketData } from './WebSocketTransport'\nimport { bindEvent } from './utils/bindEvent'\nimport { CloseEvent } from './utils/events'\nimport { DeferredPromise } from '@open-draft/deferred-promise'\n\nexport type WebSocketEventListener<\n EventType extends WebSocketEventMap[keyof WebSocketEventMap] = Event\n> = (this: WebSocket, event: EventType) => void\n\nconst WEBSOCKET_CLOSE_CODE_RANGE_ERROR =\n 'InvalidAccessError: close code out of user configurable range'\n\nexport const kPassthroughPromise = Symbol('kPassthroughPromise')\nexport const kOnSend = Symbol('kOnSend')\nexport const kClose = Symbol('kClose')\n\nexport class WebSocketOverride extends EventTarget implements WebSocket {\n static readonly CONNECTING = 0\n static readonly OPEN = 1\n static readonly CLOSING = 2\n static readonly CLOSED = 3\n readonly CONNECTING = 0\n readonly OPEN = 1\n readonly CLOSING = 2\n readonly CLOSED = 3\n\n public url: string\n public protocol: string\n public extensions: string\n public binaryType: BinaryType\n public readyState: number\n public bufferedAmount: number\n\n private _onopen: WebSocketEventListener | null = null\n private _onmessage: WebSocketEventListener<\n MessageEvent\n > | null = null\n private _onerror: WebSocketEventListener | null = null\n private _onclose: WebSocketEventListener | null = null\n\n private [kPassthroughPromise]: DeferredPromise\n private [kOnSend]?: (data: WebSocketData) => void\n\n constructor(url: string | URL, protocols?: string | Array) {\n super()\n this.url = url.toString()\n this.protocol = ''\n this.extensions = ''\n this.binaryType = 'blob'\n this.readyState = this.CONNECTING\n this.bufferedAmount = 0\n\n this[kPassthroughPromise] = new DeferredPromise()\n\n queueMicrotask(async () => {\n if (await this[kPassthroughPromise]) {\n return\n }\n\n this.protocol =\n typeof protocols === 'string'\n ? protocols\n : Array.isArray(protocols) && protocols.length > 0\n ? protocols[0]\n : ''\n\n /**\n * @note Check that nothing has prevented this connection\n * (e.g. called `client.close()` in the connection listener).\n * If the connection has been prevented, never dispatch the open event,.\n */\n if (this.readyState === this.CONNECTING) {\n this.readyState = this.OPEN\n this.dispatchEvent(bindEvent(this, new Event('open')))\n }\n })\n }\n\n set onopen(listener: WebSocketEventListener | null) {\n this.removeEventListener('open', this._onopen)\n this._onopen = listener\n if (listener !== null) {\n this.addEventListener('open', listener)\n }\n }\n get onopen(): WebSocketEventListener | null {\n return this._onopen\n }\n\n set onmessage(\n listener: WebSocketEventListener> | null\n ) {\n this.removeEventListener(\n 'message',\n this._onmessage as WebSocketEventListener\n )\n this._onmessage = listener\n if (listener !== null) {\n this.addEventListener('message', listener)\n }\n }\n get onmessage(): WebSocketEventListener> | null {\n return this._onmessage\n }\n\n set onerror(listener: WebSocketEventListener | null) {\n this.removeEventListener('error', this._onerror)\n this._onerror = listener\n if (listener !== null) {\n this.addEventListener('error', listener)\n }\n }\n get onerror(): WebSocketEventListener | null {\n return this._onerror\n }\n\n set onclose(listener: WebSocketEventListener | null) {\n this.removeEventListener('close', this._onclose as WebSocketEventListener)\n this._onclose = listener\n if (listener !== null) {\n this.addEventListener('close', listener)\n }\n }\n get onclose(): WebSocketEventListener | null {\n return this._onclose\n }\n\n /**\n * @see https://websockets.spec.whatwg.org/#ref-for-dom-websocket-send%E2%91%A0\n */\n public send(data: WebSocketData): void {\n if (this.readyState === this.CONNECTING) {\n this.close()\n throw new DOMException('InvalidStateError')\n }\n\n // Sending when the socket is about to close\n // discards the sent data.\n if (this.readyState === this.CLOSING || this.readyState === this.CLOSED) {\n return\n }\n\n // Buffer the data to send in this even loop\n // but send it in the next.\n this.bufferedAmount += getDataSize(data)\n\n queueMicrotask(() => {\n // This is a bit optimistic but since no actual data transfer\n // is involved, all the data will be \"sent\" on the next tick.\n this.bufferedAmount = 0\n\n /**\n * @note Notify the parent about outgoing data.\n * This notifies the transport and the connection\n * listens to the outgoing data to emit the \"message\" event.\n */\n this[kOnSend]?.(data)\n })\n }\n\n public close(code: number = 1000, reason?: string): void {\n invariant(code, WEBSOCKET_CLOSE_CODE_RANGE_ERROR)\n invariant(\n code === 1000 || (code >= 3000 && code <= 4999),\n WEBSOCKET_CLOSE_CODE_RANGE_ERROR\n )\n\n this[kClose](code, reason)\n }\n\n private [kClose](\n code: number = 1000,\n reason?: string,\n wasClean = true\n ): void {\n /**\n * @note Move this check here so that even internall closures,\n * like those triggered by the `server` connection, are not\n * performed twice.\n */\n if (this.readyState === this.CLOSING || this.readyState === this.CLOSED) {\n return\n }\n\n this.readyState = this.CLOSING\n\n queueMicrotask(() => {\n this.readyState = this.CLOSED\n\n this.dispatchEvent(\n bindEvent(\n this,\n new CloseEvent('close', {\n code,\n reason,\n wasClean,\n })\n )\n )\n\n // Remove all event listeners once the socket is closed.\n this._onopen = null\n this._onmessage = null\n this._onerror = null\n this._onclose = null\n })\n }\n\n public addEventListener(\n type: K,\n listener: (this: WebSocket, event: WebSocketEventMap[K]) => void,\n options?: boolean | AddEventListenerOptions\n ): void\n public addEventListener(\n type: string,\n listener: EventListenerOrEventListenerObject,\n options?: boolean | AddEventListenerOptions\n ): void\n public addEventListener(\n type: unknown,\n listener: unknown,\n options?: unknown\n ): void {\n return super.addEventListener(\n type as string,\n listener as EventListener,\n options as AddEventListenerOptions\n )\n }\n\n removeEventListener(\n type: K,\n callback: EventListenerOrEventListenerObject | null,\n options?: boolean | EventListenerOptions\n ): void {\n return super.removeEventListener(type, callback, options)\n }\n}\n\nfunction getDataSize(data: WebSocketData): number {\n if (typeof data === 'string') {\n return data.length\n }\n\n if (data instanceof Blob) {\n return data.size\n }\n\n return data.byteLength\n}\n","import { bindEvent } from './utils/bindEvent'\nimport {\n StrictEventListenerOrEventListenerObject,\n WebSocketData,\n WebSocketTransport,\n WebSocketTransportEventMap,\n} from './WebSocketTransport'\nimport { kOnSend, kClose, WebSocketOverride } from './WebSocketOverride'\nimport { CancelableMessageEvent, CloseEvent } from './utils/events'\n\n/**\n * Abstraction over the given mock `WebSocket` instance that allows\n * for controlling that instance (e.g. sending and receiving messages).\n */\nexport class WebSocketClassTransport\n extends EventTarget\n implements WebSocketTransport\n{\n constructor(protected readonly socket: WebSocketOverride) {\n super()\n\n // Emit the \"close\" event on the transport if the close\n // originates from the WebSocket client. E.g. the application\n // calls \"ws.close()\", not the interceptor.\n this.socket.addEventListener('close', (event) => {\n this.dispatchEvent(bindEvent(this.socket, new CloseEvent('close', event)))\n })\n\n /**\n * Emit the \"outgoing\" event on the transport\n * whenever the WebSocket client sends data (\"ws.send()\").\n */\n this.socket[kOnSend] = (data) => {\n this.dispatchEvent(\n bindEvent(\n this.socket,\n // Dispatch this as cancelable because \"client\" connection\n // re-creates this message event (cannot dispatch the same event).\n new CancelableMessageEvent('outgoing', {\n data,\n origin: this.socket.url,\n cancelable: true,\n })\n )\n )\n }\n }\n\n public addEventListener(\n type: EventType,\n callback: StrictEventListenerOrEventListenerObject<\n WebSocketTransportEventMap[EventType]\n > | null,\n options?: boolean | AddEventListenerOptions\n ): void {\n return super.addEventListener(type, callback as EventListener, options)\n }\n\n public dispatchEvent(\n event: WebSocketTransportEventMap[EventType]\n ): boolean {\n return super.dispatchEvent(event)\n }\n\n public send(data: WebSocketData): void {\n queueMicrotask(() => {\n if (\n this.socket.readyState === this.socket.CLOSING ||\n this.socket.readyState === this.socket.CLOSED\n ) {\n return\n }\n\n const dispatchEvent = () => {\n this.socket.dispatchEvent(\n bindEvent(\n /**\n * @note Setting this event's \"target\" to the\n * WebSocket override instance is important.\n * This way it can tell apart original incoming events\n * (must be forwarded to the transport) from the\n * mocked message events like the one below\n * (must be dispatched on the client instance).\n */\n this.socket,\n new MessageEvent('message', {\n data,\n origin: this.socket.url,\n })\n )\n )\n }\n\n if (this.socket.readyState === this.socket.CONNECTING) {\n this.socket.addEventListener(\n 'open',\n () => {\n dispatchEvent()\n },\n { once: true }\n )\n } else {\n dispatchEvent()\n }\n })\n }\n\n public close(code: number, reason?: string): void {\n /**\n * @note Call the internal close method directly\n * to allow closing the connection with the status codes\n * that are non-configurable by the user (> 1000 <= 1015).\n */\n this.socket[kClose](code, reason)\n }\n}\n","import { Interceptor } from '../../Interceptor'\nimport {\n type WebSocketClientConnectionProtocol,\n WebSocketClientConnection,\n} from './WebSocketClientConnection'\nimport { WebSocketServerConnection } from './WebSocketServerConnection'\nimport { WebSocketClassTransport } from './WebSocketClassTransport'\nimport {\n kClose,\n kPassthroughPromise,\n WebSocketOverride,\n} from './WebSocketOverride'\nimport { bindEvent } from './utils/bindEvent'\nimport { hasConfigurableGlobal } from '../../utils/hasConfigurableGlobal'\n\nexport { type WebSocketData, WebSocketTransport } from './WebSocketTransport'\nexport {\n WebSocketClientConnection,\n WebSocketClientConnectionProtocol,\n WebSocketServerConnection,\n}\n\nexport type WebSocketEventMap = {\n connection: [args: WebSocketConnectionData]\n}\n\nexport type WebSocketConnectionData = {\n /**\n * The incoming WebSocket client connection.\n */\n client: WebSocketClientConnection\n\n /**\n * The original WebSocket server connection.\n */\n server: WebSocketServerConnection\n\n /**\n * The connection information.\n */\n info: {\n /**\n * The protocols supported by the WebSocket client.\n */\n protocols: string | Array | undefined\n }\n}\n\n/**\n * Intercept the outgoing WebSocket connections created using\n * the global `WebSocket` class.\n */\nexport class WebSocketInterceptor extends Interceptor {\n static symbol = Symbol('websocket')\n\n constructor() {\n super(WebSocketInterceptor.symbol)\n }\n\n protected checkEnvironment(): boolean {\n return hasConfigurableGlobal('WebSocket')\n }\n\n protected setup(): void {\n const originalWebSocketDescriptor = Object.getOwnPropertyDescriptor(\n globalThis,\n 'WebSocket'\n )\n\n const WebSocketProxy = new Proxy(globalThis.WebSocket, {\n construct: (\n target,\n args: ConstructorParameters,\n newTarget\n ) => {\n const [url, protocols] = args\n\n const createConnection = (): WebSocket => {\n return Reflect.construct(target, args, newTarget)\n }\n\n // All WebSocket instances are mocked and don't forward\n // any events to the original server (no connection established).\n // To forward the events, the user must use the \"server.send()\" API.\n const socket = new WebSocketOverride(url, protocols)\n const transport = new WebSocketClassTransport(socket)\n\n // Emit the \"connection\" event to the interceptor on the next tick\n // so the client can modify WebSocket options, like \"binaryType\"\n // while the connection is already pending.\n queueMicrotask(() => {\n try {\n const server = new WebSocketServerConnection(\n socket,\n transport,\n createConnection\n )\n\n // The \"globalThis.WebSocket\" class stands for\n // the client-side connection. Assume it's established\n // as soon as the WebSocket instance is constructed.\n const hasConnectionListeners = this.emitter.emit('connection', {\n client: new WebSocketClientConnection(socket, transport),\n server,\n info: {\n protocols,\n },\n })\n\n if (hasConnectionListeners) {\n socket[kPassthroughPromise].resolve(false)\n } else {\n socket[kPassthroughPromise].resolve(true)\n\n server.connect()\n\n // Forward the \"open\" event from the original server\n // to the mock WebSocket client in the case of a passthrough connection.\n server.addEventListener('open', () => {\n socket.dispatchEvent(bindEvent(socket, new Event('open')))\n\n // Forward the original connection protocol to the\n // mock WebSocket client.\n if (server['realWebSocket']) {\n socket.protocol = server['realWebSocket'].protocol\n }\n })\n }\n } catch (error) {\n /**\n * @note Translate unhandled exceptions during the connection\n * handling (i.e. interceptor exceptions) as WebSocket connection\n * closures with error. This prevents from the exceptions occurring\n * in `queueMicrotask` from being process-wide and uncatchable.\n */\n if (error instanceof Error) {\n socket.dispatchEvent(new Event('error'))\n\n // No need to close the connection if it's already being closed.\n // E.g. the interceptor called `client.close()` and then threw an error.\n if (\n socket.readyState !== WebSocket.CLOSING &&\n socket.readyState !== WebSocket.CLOSED\n ) {\n socket[kClose](1011, error.message, false)\n }\n\n console.error(error)\n }\n }\n })\n\n return socket\n },\n })\n\n Object.defineProperty(globalThis, 'WebSocket', {\n value: WebSocketProxy,\n configurable: true,\n })\n\n this.subscriptions.push(() => {\n Object.defineProperty(\n globalThis,\n 'WebSocket',\n originalWebSocketDescriptor!\n )\n })\n }\n}\n"],"mappings":"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","names":["invariant","kEmitter","kBoundListener","invariant"]} \ No newline at end of file diff --git a/node_modules/@mswjs/interceptors/lib/browser/interceptors/XMLHttpRequest/index.d.ts b/node_modules/@mswjs/interceptors/lib/browser/interceptors/XMLHttpRequest/index.d.ts new file mode 100644 index 0000000000000000000000000000000000000000..477a2a659ce0ee19c90001cc596bbd733c09452e --- /dev/null +++ b/node_modules/@mswjs/interceptors/lib/browser/interceptors/XMLHttpRequest/index.d.ts @@ -0,0 +1,15 @@ +import { Emitter } from 'strict-event-emitter'; +import { H as HttpRequestEventMap } from '../../glossary-6564c252.js'; +import { I as Interceptor } from '../../Interceptor-af98b768.js'; +import '@open-draft/deferred-promise'; +import '@open-draft/logger'; + +type XMLHttpRequestEmitter = Emitter; +declare class XMLHttpRequestInterceptor extends Interceptor { + static interceptorSymbol: symbol; + constructor(); + protected checkEnvironment(): boolean; + protected setup(): void; +} + +export { XMLHttpRequestEmitter, XMLHttpRequestInterceptor }; diff --git a/node_modules/@mswjs/interceptors/lib/browser/interceptors/XMLHttpRequest/index.js b/node_modules/@mswjs/interceptors/lib/browser/interceptors/XMLHttpRequest/index.js new file mode 100644 index 0000000000000000000000000000000000000000..4ff356c93d28039371b60672393e32df93e934fb --- /dev/null +++ b/node_modules/@mswjs/interceptors/lib/browser/interceptors/XMLHttpRequest/index.js @@ -0,0 +1,12 @@ +"use strict";Object.defineProperty(exports, "__esModule", {value: true}); + +var _chunkZIT2QX7Djs = require('../../chunk-ZIT2QX7D.js'); +require('../../chunk-LK6DILFK.js'); +require('../../chunk-FGSEOIC4.js'); +require('../../chunk-BC2BLJQN.js'); +require('../../chunk-PFGO5BSM.js'); +require('../../chunk-TIPR373R.js'); + + +exports.XMLHttpRequestInterceptor = _chunkZIT2QX7Djs.XMLHttpRequestInterceptor; +//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/node_modules/@mswjs/interceptors/lib/browser/interceptors/XMLHttpRequest/index.js.map b/node_modules/@mswjs/interceptors/lib/browser/interceptors/XMLHttpRequest/index.js.map new file mode 100644 index 0000000000000000000000000000000000000000..a464c6732ec9fa9ef5cf78917d42f90f2200eb58 --- /dev/null +++ b/node_modules/@mswjs/interceptors/lib/browser/interceptors/XMLHttpRequest/index.js.map @@ -0,0 +1 @@ +{"version":3,"sources":[],"names":[],"mappings":""} \ No newline at end of file diff --git a/node_modules/@mswjs/interceptors/lib/browser/interceptors/XMLHttpRequest/index.mjs b/node_modules/@mswjs/interceptors/lib/browser/interceptors/XMLHttpRequest/index.mjs new file mode 100644 index 0000000000000000000000000000000000000000..f2d02410cb18a5e6287e7482a46829c9c5ed0814 --- /dev/null +++ b/node_modules/@mswjs/interceptors/lib/browser/interceptors/XMLHttpRequest/index.mjs @@ -0,0 +1,12 @@ +import { + XMLHttpRequestInterceptor +} from "../../chunk-DODHRDV6.mjs"; +import "../../chunk-6HYIRFX2.mjs"; +import "../../chunk-H5O73WD2.mjs"; +import "../../chunk-5UK33FSU.mjs"; +import "../../chunk-TX5GBTFY.mjs"; +import "../../chunk-QED3Q6Z2.mjs"; +export { + XMLHttpRequestInterceptor +}; +//# sourceMappingURL=index.mjs.map \ No newline at end of file diff --git a/node_modules/@mswjs/interceptors/lib/browser/interceptors/XMLHttpRequest/index.mjs.map b/node_modules/@mswjs/interceptors/lib/browser/interceptors/XMLHttpRequest/index.mjs.map new file mode 100644 index 0000000000000000000000000000000000000000..84c51b288c478ac0d18748007ccfb8cddc797f3a --- /dev/null +++ b/node_modules/@mswjs/interceptors/lib/browser/interceptors/XMLHttpRequest/index.mjs.map @@ -0,0 +1 @@ +{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]} \ No newline at end of file diff --git a/node_modules/@mswjs/interceptors/lib/browser/interceptors/fetch/index.d.ts b/node_modules/@mswjs/interceptors/lib/browser/interceptors/fetch/index.d.ts new file mode 100644 index 0000000000000000000000000000000000000000..ef276846a8aa4fab50e495eb69c5d2de2eae68fa --- /dev/null +++ b/node_modules/@mswjs/interceptors/lib/browser/interceptors/fetch/index.d.ts @@ -0,0 +1,14 @@ +import { H as HttpRequestEventMap } from '../../glossary-6564c252.js'; +import { I as Interceptor } from '../../Interceptor-af98b768.js'; +import '@open-draft/deferred-promise'; +import '@open-draft/logger'; +import 'strict-event-emitter'; + +declare class FetchInterceptor extends Interceptor { + static symbol: symbol; + constructor(); + protected checkEnvironment(): boolean; + protected setup(): Promise; +} + +export { FetchInterceptor }; diff --git a/node_modules/@mswjs/interceptors/lib/browser/interceptors/fetch/index.js b/node_modules/@mswjs/interceptors/lib/browser/interceptors/fetch/index.js new file mode 100644 index 0000000000000000000000000000000000000000..00603361cbcc58c0dcf90abfd815f5f2922ff6b3 --- /dev/null +++ b/node_modules/@mswjs/interceptors/lib/browser/interceptors/fetch/index.js @@ -0,0 +1,11 @@ +"use strict";Object.defineProperty(exports, "__esModule", {value: true}); + +var _chunkQVOTKFTBjs = require('../../chunk-QVOTKFTB.js'); +require('../../chunk-FGSEOIC4.js'); +require('../../chunk-BC2BLJQN.js'); +require('../../chunk-PFGO5BSM.js'); +require('../../chunk-TIPR373R.js'); + + +exports.FetchInterceptor = _chunkQVOTKFTBjs.FetchInterceptor; +//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/node_modules/@mswjs/interceptors/lib/browser/interceptors/fetch/index.js.map b/node_modules/@mswjs/interceptors/lib/browser/interceptors/fetch/index.js.map new file mode 100644 index 0000000000000000000000000000000000000000..a464c6732ec9fa9ef5cf78917d42f90f2200eb58 --- /dev/null +++ b/node_modules/@mswjs/interceptors/lib/browser/interceptors/fetch/index.js.map @@ -0,0 +1 @@ +{"version":3,"sources":[],"names":[],"mappings":""} \ No newline at end of file diff --git a/node_modules/@mswjs/interceptors/lib/browser/interceptors/fetch/index.mjs b/node_modules/@mswjs/interceptors/lib/browser/interceptors/fetch/index.mjs new file mode 100644 index 0000000000000000000000000000000000000000..a8673043d5c2ed576cf5ca904644c84336c001fb --- /dev/null +++ b/node_modules/@mswjs/interceptors/lib/browser/interceptors/fetch/index.mjs @@ -0,0 +1,11 @@ +import { + FetchInterceptor +} from "../../chunk-XTX2SIN6.mjs"; +import "../../chunk-H5O73WD2.mjs"; +import "../../chunk-5UK33FSU.mjs"; +import "../../chunk-TX5GBTFY.mjs"; +import "../../chunk-QED3Q6Z2.mjs"; +export { + FetchInterceptor +}; +//# sourceMappingURL=index.mjs.map \ No newline at end of file diff --git a/node_modules/@mswjs/interceptors/lib/browser/interceptors/fetch/index.mjs.map b/node_modules/@mswjs/interceptors/lib/browser/interceptors/fetch/index.mjs.map new file mode 100644 index 0000000000000000000000000000000000000000..84c51b288c478ac0d18748007ccfb8cddc797f3a --- /dev/null +++ b/node_modules/@mswjs/interceptors/lib/browser/interceptors/fetch/index.mjs.map @@ -0,0 +1 @@ +{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]} \ No newline at end of file diff --git a/node_modules/@mswjs/interceptors/lib/browser/presets/browser.d.ts b/node_modules/@mswjs/interceptors/lib/browser/presets/browser.d.ts new file mode 100644 index 0000000000000000000000000000000000000000..fb4d2e49fbea78d7b8eb97fabe9538c72f449647 --- /dev/null +++ b/node_modules/@mswjs/interceptors/lib/browser/presets/browser.d.ts @@ -0,0 +1,15 @@ +import { FetchInterceptor } from '../interceptors/fetch/index.js'; +import { XMLHttpRequestInterceptor } from '../interceptors/XMLHttpRequest/index.js'; +import '../glossary-6564c252.js'; +import '@open-draft/deferred-promise'; +import '../Interceptor-af98b768.js'; +import '@open-draft/logger'; +import 'strict-event-emitter'; + +/** + * The default preset provisions the interception of requests + * regardless of their type (fetch/XMLHttpRequest). + */ +declare const _default: readonly [FetchInterceptor, XMLHttpRequestInterceptor]; + +export { _default as default }; diff --git a/node_modules/@mswjs/interceptors/lib/browser/presets/browser.js b/node_modules/@mswjs/interceptors/lib/browser/presets/browser.js new file mode 100644 index 0000000000000000000000000000000000000000..e3b183fa343f755256ac08d72dda76b474577843 --- /dev/null +++ b/node_modules/@mswjs/interceptors/lib/browser/presets/browser.js @@ -0,0 +1,21 @@ +"use strict";Object.defineProperty(exports, "__esModule", {value: true}); + +var _chunkZIT2QX7Djs = require('../chunk-ZIT2QX7D.js'); +require('../chunk-LK6DILFK.js'); + + +var _chunkQVOTKFTBjs = require('../chunk-QVOTKFTB.js'); +require('../chunk-FGSEOIC4.js'); +require('../chunk-BC2BLJQN.js'); +require('../chunk-PFGO5BSM.js'); +require('../chunk-TIPR373R.js'); + +// src/presets/browser.ts +var browser_default = [ + new (0, _chunkQVOTKFTBjs.FetchInterceptor)(), + new (0, _chunkZIT2QX7Djs.XMLHttpRequestInterceptor)() +]; + + +exports.default = browser_default; +//# sourceMappingURL=browser.js.map \ No newline at end of file diff --git a/node_modules/@mswjs/interceptors/lib/browser/presets/browser.js.map b/node_modules/@mswjs/interceptors/lib/browser/presets/browser.js.map new file mode 100644 index 0000000000000000000000000000000000000000..fc2cb3d5d7e8b4b41ee05c57bfed70b885ccca39 --- /dev/null +++ b/node_modules/@mswjs/interceptors/lib/browser/presets/browser.js.map @@ -0,0 +1 @@ +{"version":3,"sources":["../../../src/presets/browser.ts"],"names":[],"mappings":";;;;;;;;;;;;;AAOA,IAAO,kBAAQ;AAAA,EACb,IAAI,iBAAiB;AAAA,EACrB,IAAI,0BAA0B;AAChC","sourcesContent":["import { FetchInterceptor } from '../interceptors/fetch'\nimport { XMLHttpRequestInterceptor } from '../interceptors/XMLHttpRequest'\n\n/**\n * The default preset provisions the interception of requests\n * regardless of their type (fetch/XMLHttpRequest).\n */\nexport default [\n new FetchInterceptor(),\n new XMLHttpRequestInterceptor(),\n] as const\n"]} \ No newline at end of file diff --git a/node_modules/@mswjs/interceptors/lib/browser/presets/browser.mjs b/node_modules/@mswjs/interceptors/lib/browser/presets/browser.mjs new file mode 100644 index 0000000000000000000000000000000000000000..33ea87b52294db682cebc1a9c382452a655e6c03 --- /dev/null +++ b/node_modules/@mswjs/interceptors/lib/browser/presets/browser.mjs @@ -0,0 +1,21 @@ +import { + XMLHttpRequestInterceptor +} from "../chunk-DODHRDV6.mjs"; +import "../chunk-6HYIRFX2.mjs"; +import { + FetchInterceptor +} from "../chunk-XTX2SIN6.mjs"; +import "../chunk-H5O73WD2.mjs"; +import "../chunk-5UK33FSU.mjs"; +import "../chunk-TX5GBTFY.mjs"; +import "../chunk-QED3Q6Z2.mjs"; + +// src/presets/browser.ts +var browser_default = [ + new FetchInterceptor(), + new XMLHttpRequestInterceptor() +]; +export { + browser_default as default +}; +//# sourceMappingURL=browser.mjs.map \ No newline at end of file diff --git a/node_modules/@mswjs/interceptors/lib/browser/presets/browser.mjs.map b/node_modules/@mswjs/interceptors/lib/browser/presets/browser.mjs.map new file mode 100644 index 0000000000000000000000000000000000000000..05ee5a1e597e618dcb133d0637b2cb00a434279b --- /dev/null +++ b/node_modules/@mswjs/interceptors/lib/browser/presets/browser.mjs.map @@ -0,0 +1 @@ +{"version":3,"sources":["../../../src/presets/browser.ts"],"sourcesContent":["import { FetchInterceptor } from '../interceptors/fetch'\nimport { XMLHttpRequestInterceptor } from '../interceptors/XMLHttpRequest'\n\n/**\n * The default preset provisions the interception of requests\n * regardless of their type (fetch/XMLHttpRequest).\n */\nexport default [\n new FetchInterceptor(),\n new XMLHttpRequestInterceptor(),\n] as const\n"],"mappings":";;;;;;;;;;;;;AAOA,IAAO,kBAAQ;AAAA,EACb,IAAI,iBAAiB;AAAA,EACrB,IAAI,0BAA0B;AAChC;","names":[]} \ No newline at end of file diff --git a/node_modules/@mswjs/interceptors/lib/node/BatchInterceptor-67bf41ba.d.ts b/node_modules/@mswjs/interceptors/lib/node/BatchInterceptor-67bf41ba.d.ts new file mode 100644 index 0000000000000000000000000000000000000000..b90f91bc9a8738671ba170995129cc1afcbcc3ab --- /dev/null +++ b/node_modules/@mswjs/interceptors/lib/node/BatchInterceptor-67bf41ba.d.ts @@ -0,0 +1,24 @@ +import { EventMap, Listener } from 'strict-event-emitter'; +import { h as Interceptor, E as ExtractEventNames } from './Interceptor-436630be.js'; + +interface BatchInterceptorOptions>> { + name: string; + interceptors: InterceptorList; +} +type ExtractEventMapType>> = InterceptorList extends ReadonlyArray ? InterceptorType extends Interceptor ? EventMap : never : never; +/** + * A batch interceptor that exposes a single interface + * to apply and operate with multiple interceptors at once. + */ +declare class BatchInterceptor>, Events extends EventMap = ExtractEventMapType> extends Interceptor { + static symbol: symbol; + private interceptors; + constructor(options: BatchInterceptorOptions); + protected setup(): void; + on>(event: EventName, listener: Listener): this; + once>(event: EventName, listener: Listener): this; + off>(event: EventName, listener: Listener): this; + removeAllListeners>(event?: EventName | undefined): this; +} + +export { BatchInterceptorOptions as B, ExtractEventMapType as E, BatchInterceptor as a }; diff --git a/node_modules/@mswjs/interceptors/lib/node/Interceptor-436630be.d.ts b/node_modules/@mswjs/interceptors/lib/node/Interceptor-436630be.d.ts new file mode 100644 index 0000000000000000000000000000000000000000..08323b54c883700179f898c1547d8c54223ebe58 --- /dev/null +++ b/node_modules/@mswjs/interceptors/lib/node/Interceptor-436630be.d.ts @@ -0,0 +1,128 @@ +import { DeferredPromise } from '@open-draft/deferred-promise'; +import { Logger } from '@open-draft/logger'; +import { Emitter, Listener } from 'strict-event-emitter'; + +declare const kRequestHandled: unique symbol; +declare const kResponsePromise: unique symbol; +declare class RequestController { + private request; + /** + * Internal response promise. + * Available only for the library internals to grab the + * response instance provided by the developer. + * @note This promise cannot be rejected. It's either infinitely + * pending or resolved with whichever Response was passed to `respondWith()`. + */ + [kResponsePromise]: DeferredPromise; + /** + * Internal flag indicating if this request has been handled. + * @note The response promise becomes "fulfilled" on the next tick. + */ + [kRequestHandled]: boolean; + constructor(request: Request); + /** + * Respond to this request with the given `Response` instance. + * @example + * controller.respondWith(new Response()) + * controller.respondWith(Response.json({ id })) + * controller.respondWith(Response.error()) + */ + respondWith(response: Response): void; + /** + * Error this request with the given error. + * @example + * controller.errorWith() + * controller.errorWith(new Error('Oops!')) + */ + errorWith(error?: Error): void; +} + +declare const IS_PATCHED_MODULE: unique symbol; + +type RequestCredentials = 'omit' | 'include' | 'same-origin'; +type HttpRequestEventMap = { + request: [ + args: { + request: Request; + requestId: string; + controller: RequestController; + } + ]; + response: [ + args: { + response: Response; + isMockedResponse: boolean; + request: Request; + requestId: string; + } + ]; + unhandledException: [ + args: { + error: unknown; + request: Request; + requestId: string; + controller: RequestController; + } + ]; +}; + +type InterceptorEventMap = Record; +type InterceptorSubscription = () => void; +/** + * Request header name to detect when a single request + * is being handled by nested interceptors (XHR -> ClientRequest). + * Obscure by design to prevent collisions with user-defined headers. + * Ideally, come up with the Interceptor-level mechanism for this. + * @see https://github.com/mswjs/interceptors/issues/378 + */ +declare const INTERNAL_REQUEST_ID_HEADER_NAME = "x-interceptors-internal-request-id"; +declare function getGlobalSymbol(symbol: Symbol): V | undefined; +declare function deleteGlobalSymbol(symbol: Symbol): void; +declare enum InterceptorReadyState { + INACTIVE = "INACTIVE", + APPLYING = "APPLYING", + APPLIED = "APPLIED", + DISPOSING = "DISPOSING", + DISPOSED = "DISPOSED" +} +type ExtractEventNames> = Events extends Record ? EventName : never; +declare class Interceptor { + private readonly symbol; + protected emitter: Emitter; + protected subscriptions: Array; + protected logger: Logger; + readyState: InterceptorReadyState; + constructor(symbol: symbol); + /** + * Determine if this interceptor can be applied + * in the current environment. + */ + protected checkEnvironment(): boolean; + /** + * Apply this interceptor to the current process. + * Returns an already running interceptor instance if it's present. + */ + apply(): void; + /** + * Setup the module augments and stubs necessary for this interceptor. + * This method is not run if there's a running interceptor instance + * to prevent instantiating an interceptor multiple times. + */ + protected setup(): void; + /** + * Listen to the interceptor's public events. + */ + on>(event: EventName, listener: Listener): this; + once>(event: EventName, listener: Listener): this; + off>(event: EventName, listener: Listener): this; + removeAllListeners>(event?: EventName): this; + /** + * Disposes of any side-effects this interceptor has introduced. + */ + dispose(): void; + private getInstance; + private setInstance; + private clearInstance; +} + +export { ExtractEventNames as E, HttpRequestEventMap as H, IS_PATCHED_MODULE as I, RequestController as R, RequestCredentials as a, InterceptorEventMap as b, InterceptorSubscription as c, INTERNAL_REQUEST_ID_HEADER_NAME as d, deleteGlobalSymbol as e, InterceptorReadyState as f, getGlobalSymbol as g, Interceptor as h }; diff --git a/node_modules/@mswjs/interceptors/lib/node/RemoteHttpInterceptor.d.ts b/node_modules/@mswjs/interceptors/lib/node/RemoteHttpInterceptor.d.ts new file mode 100644 index 0000000000000000000000000000000000000000..67c0866cadb507c968dfdddac354c1bd1e98b127 --- /dev/null +++ b/node_modules/@mswjs/interceptors/lib/node/RemoteHttpInterceptor.d.ts @@ -0,0 +1,43 @@ +import { ChildProcess } from 'child_process'; +import { h as Interceptor, H as HttpRequestEventMap } from './Interceptor-436630be.js'; +import { a as BatchInterceptor } from './BatchInterceptor-67bf41ba.js'; +import { ClientRequestInterceptor } from './interceptors/ClientRequest/index.js'; +import { XMLHttpRequestInterceptor } from './interceptors/XMLHttpRequest/index.js'; +import '@open-draft/deferred-promise'; +import '@open-draft/logger'; +import 'strict-event-emitter'; +import 'node:net'; + +interface SerializedRequest { + id: string; + url: string; + method: string; + headers: Array<[string, string]>; + credentials: RequestCredentials; + body: string; +} +interface SerializedResponse { + status: number; + statusText: string; + headers: Array<[string, string]>; + body: string; +} +declare class RemoteHttpInterceptor extends BatchInterceptor<[ + ClientRequestInterceptor, + XMLHttpRequestInterceptor +]> { + constructor(); + protected setup(): void; +} +declare function requestReviver(key: string, value: any): any; +interface RemoveResolverOptions { + process: ChildProcess; +} +declare class RemoteHttpResolver extends Interceptor { + static symbol: symbol; + private process; + constructor(options: RemoveResolverOptions); + protected setup(): void; +} + +export { RemoteHttpInterceptor, RemoteHttpResolver, RemoveResolverOptions, SerializedRequest, SerializedResponse, requestReviver }; diff --git a/node_modules/@mswjs/interceptors/lib/node/RemoteHttpInterceptor.js b/node_modules/@mswjs/interceptors/lib/node/RemoteHttpInterceptor.js new file mode 100644 index 0000000000000000000000000000000000000000..aaf20028180266d72eefefe66f08c9ab324db9b9 --- /dev/null +++ b/node_modules/@mswjs/interceptors/lib/node/RemoteHttpInterceptor.js @@ -0,0 +1,187 @@ +"use strict";Object.defineProperty(exports, "__esModule", {value: true}); + +var _chunkYBN5MFAPjs = require('./chunk-YBN5MFAP.js'); + + +var _chunk3HCE66HZjs = require('./chunk-3HCE66HZ.js'); + + +var _chunkLCA4FKWYjs = require('./chunk-LCA4FKWY.js'); +require('./chunk-LK6DILFK.js'); +require('./chunk-PFGO5BSM.js'); +require('./chunk-73NOP3T5.js'); + + + +var _chunk6L3PFBGTjs = require('./chunk-6L3PFBGT.js'); + + + +var _chunkWZTE4PCOjs = require('./chunk-WZTE4PCO.js'); + +// src/RemoteHttpInterceptor.ts +var RemoteHttpInterceptor = class extends _chunkYBN5MFAPjs.BatchInterceptor { + constructor() { + super({ + name: "remote-interceptor", + interceptors: [ + new (0, _chunk3HCE66HZjs.ClientRequestInterceptor)(), + new (0, _chunkLCA4FKWYjs.XMLHttpRequestInterceptor)() + ] + }); + } + setup() { + super.setup(); + let handleParentMessage; + this.on("request", async ({ request, requestId, controller }) => { + var _a; + const serializedRequest = JSON.stringify({ + id: requestId, + method: request.method, + url: request.url, + headers: Array.from(request.headers.entries()), + credentials: request.credentials, + body: ["GET", "HEAD"].includes(request.method) ? null : await request.text() + }); + this.logger.info( + "sent serialized request to the child:", + serializedRequest + ); + (_a = process.send) == null ? void 0 : _a.call(process, `request:${serializedRequest}`); + const responsePromise = new Promise((resolve) => { + handleParentMessage = (message) => { + if (typeof message !== "string") { + return resolve(); + } + if (message.startsWith(`response:${requestId}`)) { + const [, serializedResponse] = message.match(/^response:.+?:(.+)$/) || []; + if (!serializedResponse) { + return resolve(); + } + const responseInit = JSON.parse( + serializedResponse + ); + const mockedResponse = new (0, _chunkWZTE4PCOjs.FetchResponse)(responseInit.body, { + url: request.url, + status: responseInit.status, + statusText: responseInit.statusText, + headers: responseInit.headers + }); + controller.respondWith(mockedResponse); + return resolve(); + } + }; + }); + this.logger.info( + 'add "message" listener to the parent process', + handleParentMessage + ); + process.addListener("message", handleParentMessage); + return responsePromise; + }); + this.subscriptions.push(() => { + process.removeListener("message", handleParentMessage); + }); + } +}; +function requestReviver(key, value) { + switch (key) { + case "url": + return new URL(value); + case "headers": + return new Headers(value); + default: + return value; + } +} +var _RemoteHttpResolver = class extends _chunkWZTE4PCOjs.Interceptor { + constructor(options) { + super(_RemoteHttpResolver.symbol); + this.process = options.process; + } + setup() { + const logger = this.logger.extend("setup"); + const handleChildMessage = async (message) => { + logger.info("received message from child!", message); + if (typeof message !== "string" || !message.startsWith("request:")) { + logger.info("unknown message, ignoring..."); + return; + } + const [, serializedRequest] = message.match(/^request:(.+)$/) || []; + if (!serializedRequest) { + return; + } + const requestJson = JSON.parse( + serializedRequest, + requestReviver + ); + logger.info("parsed intercepted request", requestJson); + const request = new Request(requestJson.url, { + method: requestJson.method, + headers: new Headers(requestJson.headers), + credentials: requestJson.credentials, + body: requestJson.body + }); + const controller = new (0, _chunk6L3PFBGTjs.RequestController)(request); + await _chunk6L3PFBGTjs.handleRequest.call(void 0, { + request, + requestId: requestJson.id, + controller, + emitter: this.emitter, + onResponse: async (response) => { + this.logger.info("received mocked response!", { response }); + const responseClone = response.clone(); + const responseText = await responseClone.text(); + const serializedResponse = JSON.stringify({ + status: response.status, + statusText: response.statusText, + headers: Array.from(response.headers.entries()), + body: responseText + }); + this.process.send( + `response:${requestJson.id}:${serializedResponse}`, + (error) => { + if (error) { + return; + } + this.emitter.emit("response", { + request, + requestId: requestJson.id, + response: responseClone, + isMockedResponse: true + }); + } + ); + logger.info( + "sent serialized mocked response to the parent:", + serializedResponse + ); + }, + onRequestError: (response) => { + this.logger.info("received a network error!", { response }); + throw new Error("Not implemented"); + }, + onError: (error) => { + this.logger.info("request has errored!", { error }); + throw new Error("Not implemented"); + } + }); + }; + this.subscriptions.push(() => { + this.process.removeListener("message", handleChildMessage); + logger.info('removed the "message" listener from the child process!'); + }); + logger.info('adding a "message" listener to the child process'); + this.process.addListener("message", handleChildMessage); + this.process.once("error", () => this.dispose()); + this.process.once("exit", () => this.dispose()); + } +}; +var RemoteHttpResolver = _RemoteHttpResolver; +RemoteHttpResolver.symbol = Symbol("remote-resolver"); + + + + +exports.RemoteHttpInterceptor = RemoteHttpInterceptor; exports.RemoteHttpResolver = RemoteHttpResolver; exports.requestReviver = requestReviver; +//# sourceMappingURL=RemoteHttpInterceptor.js.map \ No newline at end of file diff --git a/node_modules/@mswjs/interceptors/lib/node/RemoteHttpInterceptor.js.map b/node_modules/@mswjs/interceptors/lib/node/RemoteHttpInterceptor.js.map new file mode 100644 index 0000000000000000000000000000000000000000..f44fcd3058acf9d53dda7c99d9215b8a63619041 --- /dev/null +++ b/node_modules/@mswjs/interceptors/lib/node/RemoteHttpInterceptor.js.map @@ -0,0 +1 @@ +{"version":3,"sources":["../../src/RemoteHttpInterceptor.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;AA+BO,IAAM,wBAAN,cAAoC,iBAEzC;AAAA,EACA,cAAc;AACZ,UAAM;AAAA,MACJ,MAAM;AAAA,MACN,cAAc;AAAA,QACZ,IAAI,yBAAyB;AAAA,QAC7B,IAAI,0BAA0B;AAAA,MAChC;AAAA,IACF,CAAC;AAAA,EACH;AAAA,EAEU,QAAQ;AAChB,UAAM,MAAM;AAEZ,QAAI;AAEJ,SAAK,GAAG,WAAW,OAAO,EAAE,SAAS,WAAW,WAAW,MAAM;AAjDrE;AAoDM,YAAM,oBAAoB,KAAK,UAAU;AAAA,QACvC,IAAI;AAAA,QACJ,QAAQ,QAAQ;AAAA,QAChB,KAAK,QAAQ;AAAA,QACb,SAAS,MAAM,KAAK,QAAQ,QAAQ,QAAQ,CAAC;AAAA,QAC7C,aAAa,QAAQ;AAAA,QACrB,MAAM,CAAC,OAAO,MAAM,EAAE,SAAS,QAAQ,MAAM,IACzC,OACA,MAAM,QAAQ,KAAK;AAAA,MACzB,CAAsB;AAEtB,WAAK,OAAO;AAAA,QACV;AAAA,QACA;AAAA,MACF;AAEA,oBAAQ,SAAR,iCAAe,WAAW;AAE1B,YAAM,kBAAkB,IAAI,QAAc,CAAC,YAAY;AACrD,8BAAsB,CAAC,YAAY;AACjC,cAAI,OAAO,YAAY,UAAU;AAC/B,mBAAO,QAAQ;AAAA,UACjB;AAEA,cAAI,QAAQ,WAAW,YAAY,WAAW,GAAG;AAC/C,kBAAM,CAAC,EAAE,kBAAkB,IACzB,QAAQ,MAAM,qBAAqB,KAAK,CAAC;AAE3C,gBAAI,CAAC,oBAAoB;AACvB,qBAAO,QAAQ;AAAA,YACjB;AAEA,kBAAM,eAAe,KAAK;AAAA,cACxB;AAAA,YACF;AAEA,kBAAM,iBAAiB,IAAI,cAAc,aAAa,MAAM;AAAA,cAC1D,KAAK,QAAQ;AAAA,cACb,QAAQ,aAAa;AAAA,cACrB,YAAY,aAAa;AAAA,cACzB,SAAS,aAAa;AAAA,YACxB,CAAC;AAOD,uBAAW,YAAY,cAAc;AACrC,mBAAO,QAAQ;AAAA,UACjB;AAAA,QACF;AAAA,MACF,CAAC;AAGD,WAAK,OAAO;AAAA,QACV;AAAA,QACA;AAAA,MACF;AACA,cAAQ,YAAY,WAAW,mBAAmB;AAElD,aAAO;AAAA,IACT,CAAC;AAED,SAAK,cAAc,KAAK,MAAM;AAC5B,cAAQ,eAAe,WAAW,mBAAmB;AAAA,IACvD,CAAC;AAAA,EACH;AACF;AAEO,SAAS,eAAe,KAAa,OAAY;AACtD,UAAQ,KAAK;AAAA,IACX,KAAK;AACH,aAAO,IAAI,IAAI,KAAK;AAAA,IAEtB,KAAK;AACH,aAAO,IAAI,QAAQ,KAAK;AAAA,IAE1B;AACE,aAAO;AAAA,EACX;AACF;AAMO,IAAM,sBAAN,cAAiC,YAAiC;AAAA,EAIvE,YAAY,SAAgC;AAC1C,UAAM,oBAAmB,MAAM;AAC/B,SAAK,UAAU,QAAQ;AAAA,EACzB;AAAA,EAEU,QAAQ;AAChB,UAAM,SAAS,KAAK,OAAO,OAAO,OAAO;AAEzC,UAAM,qBAA6C,OAAO,YAAY;AACpE,aAAO,KAAK,gCAAgC,OAAO;AAEnD,UAAI,OAAO,YAAY,YAAY,CAAC,QAAQ,WAAW,UAAU,GAAG;AAClE,eAAO,KAAK,8BAA8B;AAC1C;AAAA,MACF;AAEA,YAAM,CAAC,EAAE,iBAAiB,IAAI,QAAQ,MAAM,gBAAgB,KAAK,CAAC;AAClE,UAAI,CAAC,mBAAmB;AACtB;AAAA,MACF;AAEA,YAAM,cAAc,KAAK;AAAA,QACvB;AAAA,QACA;AAAA,MACF;AAEA,aAAO,KAAK,8BAA8B,WAAW;AAErD,YAAM,UAAU,IAAI,QAAQ,YAAY,KAAK;AAAA,QAC3C,QAAQ,YAAY;AAAA,QACpB,SAAS,IAAI,QAAQ,YAAY,OAAO;AAAA,QACxC,aAAa,YAAY;AAAA,QACzB,MAAM,YAAY;AAAA,MACpB,CAAC;AAED,YAAM,aAAa,IAAI,kBAAkB,OAAO;AAChD,YAAM,cAAc;AAAA,QAClB;AAAA,QACA,WAAW,YAAY;AAAA,QACvB;AAAA,QACA,SAAS,KAAK;AAAA,QACd,YAAY,OAAO,aAAa;AAC9B,eAAK,OAAO,KAAK,6BAA6B,EAAE,SAAS,CAAC;AAE1D,gBAAM,gBAAgB,SAAS,MAAM;AACrC,gBAAM,eAAe,MAAM,cAAc,KAAK;AAG9C,gBAAM,qBAAqB,KAAK,UAAU;AAAA,YACxC,QAAQ,SAAS;AAAA,YACjB,YAAY,SAAS;AAAA,YACrB,SAAS,MAAM,KAAK,SAAS,QAAQ,QAAQ,CAAC;AAAA,YAC9C,MAAM;AAAA,UACR,CAAuB;AAEvB,eAAK,QAAQ;AAAA,YACX,YAAY,YAAY,MAAM;AAAA,YAC9B,CAAC,UAAU;AACT,kBAAI,OAAO;AACT;AAAA,cACF;AAIA,mBAAK,QAAQ,KAAK,YAAY;AAAA,gBAC5B;AAAA,gBACA,WAAW,YAAY;AAAA,gBACvB,UAAU;AAAA,gBACV,kBAAkB;AAAA,cACpB,CAAC;AAAA,YACH;AAAA,UACF;AAEA,iBAAO;AAAA,YACL;AAAA,YACA;AAAA,UACF;AAAA,QACF;AAAA,QACA,gBAAgB,CAAC,aAAa;AAC5B,eAAK,OAAO,KAAK,6BAA6B,EAAE,SAAS,CAAC;AAC1D,gBAAM,IAAI,MAAM,iBAAiB;AAAA,QACnC;AAAA,QACA,SAAS,CAAC,UAAU;AAClB,eAAK,OAAO,KAAK,wBAAwB,EAAE,MAAM,CAAC;AAClD,gBAAM,IAAI,MAAM,iBAAiB;AAAA,QACnC;AAAA,MACF,CAAC;AAAA,IACH;AAEA,SAAK,cAAc,KAAK,MAAM;AAC5B,WAAK,QAAQ,eAAe,WAAW,kBAAkB;AACzD,aAAO,KAAK,wDAAwD;AAAA,IACtE,CAAC;AAED,WAAO,KAAK,kDAAkD;AAC9D,SAAK,QAAQ,YAAY,WAAW,kBAAkB;AAEtD,SAAK,QAAQ,KAAK,SAAS,MAAM,KAAK,QAAQ,CAAC;AAC/C,SAAK,QAAQ,KAAK,QAAQ,MAAM,KAAK,QAAQ,CAAC;AAAA,EAChD;AACF;AAxGO,IAAM,qBAAN;AAAM,mBACJ,SAAS,OAAO,iBAAiB","sourcesContent":["import { ChildProcess } from 'child_process'\nimport { HttpRequestEventMap } from './glossary'\nimport { Interceptor } from './Interceptor'\nimport { BatchInterceptor } from './BatchInterceptor'\nimport { ClientRequestInterceptor } from './interceptors/ClientRequest'\nimport { XMLHttpRequestInterceptor } from './interceptors/XMLHttpRequest'\nimport { handleRequest } from './utils/handleRequest'\nimport { RequestController } from './RequestController'\nimport { FetchResponse } from './utils/fetchUtils'\n\nexport interface SerializedRequest {\n id: string\n url: string\n method: string\n headers: Array<[string, string]>\n credentials: RequestCredentials\n body: string\n}\n\ninterface RevivedRequest extends Omit {\n url: URL\n headers: Headers\n}\n\nexport interface SerializedResponse {\n status: number\n statusText: string\n headers: Array<[string, string]>\n body: string\n}\n\nexport class RemoteHttpInterceptor extends BatchInterceptor<\n [ClientRequestInterceptor, XMLHttpRequestInterceptor]\n> {\n constructor() {\n super({\n name: 'remote-interceptor',\n interceptors: [\n new ClientRequestInterceptor(),\n new XMLHttpRequestInterceptor(),\n ],\n })\n }\n\n protected setup() {\n super.setup()\n\n let handleParentMessage: NodeJS.MessageListener\n\n this.on('request', async ({ request, requestId, controller }) => {\n // Send the stringified intercepted request to\n // the parent process where the remote resolver is established.\n const serializedRequest = JSON.stringify({\n id: requestId,\n method: request.method,\n url: request.url,\n headers: Array.from(request.headers.entries()),\n credentials: request.credentials,\n body: ['GET', 'HEAD'].includes(request.method)\n ? null\n : await request.text(),\n } as SerializedRequest)\n\n this.logger.info(\n 'sent serialized request to the child:',\n serializedRequest\n )\n\n process.send?.(`request:${serializedRequest}`)\n\n const responsePromise = new Promise((resolve) => {\n handleParentMessage = (message) => {\n if (typeof message !== 'string') {\n return resolve()\n }\n\n if (message.startsWith(`response:${requestId}`)) {\n const [, serializedResponse] =\n message.match(/^response:.+?:(.+)$/) || []\n\n if (!serializedResponse) {\n return resolve()\n }\n\n const responseInit = JSON.parse(\n serializedResponse\n ) as SerializedResponse\n\n const mockedResponse = new FetchResponse(responseInit.body, {\n url: request.url,\n status: responseInit.status,\n statusText: responseInit.statusText,\n headers: responseInit.headers,\n })\n\n /**\n * @todo Support \"errorWith\" as well.\n * This response handling from the child is incomplete.\n */\n\n controller.respondWith(mockedResponse)\n return resolve()\n }\n }\n })\n\n // Listen for the mocked response message from the parent.\n this.logger.info(\n 'add \"message\" listener to the parent process',\n handleParentMessage\n )\n process.addListener('message', handleParentMessage)\n\n return responsePromise\n })\n\n this.subscriptions.push(() => {\n process.removeListener('message', handleParentMessage)\n })\n }\n}\n\nexport function requestReviver(key: string, value: any) {\n switch (key) {\n case 'url':\n return new URL(value)\n\n case 'headers':\n return new Headers(value)\n\n default:\n return value\n }\n}\n\nexport interface RemoveResolverOptions {\n process: ChildProcess\n}\n\nexport class RemoteHttpResolver extends Interceptor {\n static symbol = Symbol('remote-resolver')\n private process: ChildProcess\n\n constructor(options: RemoveResolverOptions) {\n super(RemoteHttpResolver.symbol)\n this.process = options.process\n }\n\n protected setup() {\n const logger = this.logger.extend('setup')\n\n const handleChildMessage: NodeJS.MessageListener = async (message) => {\n logger.info('received message from child!', message)\n\n if (typeof message !== 'string' || !message.startsWith('request:')) {\n logger.info('unknown message, ignoring...')\n return\n }\n\n const [, serializedRequest] = message.match(/^request:(.+)$/) || []\n if (!serializedRequest) {\n return\n }\n\n const requestJson = JSON.parse(\n serializedRequest,\n requestReviver\n ) as RevivedRequest\n\n logger.info('parsed intercepted request', requestJson)\n\n const request = new Request(requestJson.url, {\n method: requestJson.method,\n headers: new Headers(requestJson.headers),\n credentials: requestJson.credentials,\n body: requestJson.body,\n })\n\n const controller = new RequestController(request)\n await handleRequest({\n request,\n requestId: requestJson.id,\n controller,\n emitter: this.emitter,\n onResponse: async (response) => {\n this.logger.info('received mocked response!', { response })\n\n const responseClone = response.clone()\n const responseText = await responseClone.text()\n\n // // Send the mocked response to the child process.\n const serializedResponse = JSON.stringify({\n status: response.status,\n statusText: response.statusText,\n headers: Array.from(response.headers.entries()),\n body: responseText,\n } as SerializedResponse)\n\n this.process.send(\n `response:${requestJson.id}:${serializedResponse}`,\n (error) => {\n if (error) {\n return\n }\n\n // Emit an optimistic \"response\" event at this point,\n // not to rely on the back-and-forth signaling for the sake of the event.\n this.emitter.emit('response', {\n request,\n requestId: requestJson.id,\n response: responseClone,\n isMockedResponse: true,\n })\n }\n )\n\n logger.info(\n 'sent serialized mocked response to the parent:',\n serializedResponse\n )\n },\n onRequestError: (response) => {\n this.logger.info('received a network error!', { response })\n throw new Error('Not implemented')\n },\n onError: (error) => {\n this.logger.info('request has errored!', { error })\n throw new Error('Not implemented')\n },\n })\n }\n\n this.subscriptions.push(() => {\n this.process.removeListener('message', handleChildMessage)\n logger.info('removed the \"message\" listener from the child process!')\n })\n\n logger.info('adding a \"message\" listener to the child process')\n this.process.addListener('message', handleChildMessage)\n\n this.process.once('error', () => this.dispose())\n this.process.once('exit', () => this.dispose())\n }\n}\n"]} \ No newline at end of file diff --git a/node_modules/@mswjs/interceptors/lib/node/RemoteHttpInterceptor.mjs b/node_modules/@mswjs/interceptors/lib/node/RemoteHttpInterceptor.mjs new file mode 100644 index 0000000000000000000000000000000000000000..b0d806e319fbb5c76702ab0fb61a2a448f5db4f2 --- /dev/null +++ b/node_modules/@mswjs/interceptors/lib/node/RemoteHttpInterceptor.mjs @@ -0,0 +1,187 @@ +import { + BatchInterceptor +} from "./chunk-PJA4E426.mjs"; +import { + ClientRequestInterceptor +} from "./chunk-FWJSC2QD.mjs"; +import { + XMLHttpRequestInterceptor +} from "./chunk-OMWE7UVM.mjs"; +import "./chunk-6HYIRFX2.mjs"; +import "./chunk-TX5GBTFY.mjs"; +import "./chunk-6YM4PLBI.mjs"; +import { + RequestController, + handleRequest +} from "./chunk-5KMS5CTP.mjs"; +import { + FetchResponse, + Interceptor +} from "./chunk-I7HQIBT7.mjs"; + +// src/RemoteHttpInterceptor.ts +var RemoteHttpInterceptor = class extends BatchInterceptor { + constructor() { + super({ + name: "remote-interceptor", + interceptors: [ + new ClientRequestInterceptor(), + new XMLHttpRequestInterceptor() + ] + }); + } + setup() { + super.setup(); + let handleParentMessage; + this.on("request", async ({ request, requestId, controller }) => { + var _a; + const serializedRequest = JSON.stringify({ + id: requestId, + method: request.method, + url: request.url, + headers: Array.from(request.headers.entries()), + credentials: request.credentials, + body: ["GET", "HEAD"].includes(request.method) ? null : await request.text() + }); + this.logger.info( + "sent serialized request to the child:", + serializedRequest + ); + (_a = process.send) == null ? void 0 : _a.call(process, `request:${serializedRequest}`); + const responsePromise = new Promise((resolve) => { + handleParentMessage = (message) => { + if (typeof message !== "string") { + return resolve(); + } + if (message.startsWith(`response:${requestId}`)) { + const [, serializedResponse] = message.match(/^response:.+?:(.+)$/) || []; + if (!serializedResponse) { + return resolve(); + } + const responseInit = JSON.parse( + serializedResponse + ); + const mockedResponse = new FetchResponse(responseInit.body, { + url: request.url, + status: responseInit.status, + statusText: responseInit.statusText, + headers: responseInit.headers + }); + controller.respondWith(mockedResponse); + return resolve(); + } + }; + }); + this.logger.info( + 'add "message" listener to the parent process', + handleParentMessage + ); + process.addListener("message", handleParentMessage); + return responsePromise; + }); + this.subscriptions.push(() => { + process.removeListener("message", handleParentMessage); + }); + } +}; +function requestReviver(key, value) { + switch (key) { + case "url": + return new URL(value); + case "headers": + return new Headers(value); + default: + return value; + } +} +var _RemoteHttpResolver = class extends Interceptor { + constructor(options) { + super(_RemoteHttpResolver.symbol); + this.process = options.process; + } + setup() { + const logger = this.logger.extend("setup"); + const handleChildMessage = async (message) => { + logger.info("received message from child!", message); + if (typeof message !== "string" || !message.startsWith("request:")) { + logger.info("unknown message, ignoring..."); + return; + } + const [, serializedRequest] = message.match(/^request:(.+)$/) || []; + if (!serializedRequest) { + return; + } + const requestJson = JSON.parse( + serializedRequest, + requestReviver + ); + logger.info("parsed intercepted request", requestJson); + const request = new Request(requestJson.url, { + method: requestJson.method, + headers: new Headers(requestJson.headers), + credentials: requestJson.credentials, + body: requestJson.body + }); + const controller = new RequestController(request); + await handleRequest({ + request, + requestId: requestJson.id, + controller, + emitter: this.emitter, + onResponse: async (response) => { + this.logger.info("received mocked response!", { response }); + const responseClone = response.clone(); + const responseText = await responseClone.text(); + const serializedResponse = JSON.stringify({ + status: response.status, + statusText: response.statusText, + headers: Array.from(response.headers.entries()), + body: responseText + }); + this.process.send( + `response:${requestJson.id}:${serializedResponse}`, + (error) => { + if (error) { + return; + } + this.emitter.emit("response", { + request, + requestId: requestJson.id, + response: responseClone, + isMockedResponse: true + }); + } + ); + logger.info( + "sent serialized mocked response to the parent:", + serializedResponse + ); + }, + onRequestError: (response) => { + this.logger.info("received a network error!", { response }); + throw new Error("Not implemented"); + }, + onError: (error) => { + this.logger.info("request has errored!", { error }); + throw new Error("Not implemented"); + } + }); + }; + this.subscriptions.push(() => { + this.process.removeListener("message", handleChildMessage); + logger.info('removed the "message" listener from the child process!'); + }); + logger.info('adding a "message" listener to the child process'); + this.process.addListener("message", handleChildMessage); + this.process.once("error", () => this.dispose()); + this.process.once("exit", () => this.dispose()); + } +}; +var RemoteHttpResolver = _RemoteHttpResolver; +RemoteHttpResolver.symbol = Symbol("remote-resolver"); +export { + RemoteHttpInterceptor, + RemoteHttpResolver, + requestReviver +}; +//# sourceMappingURL=RemoteHttpInterceptor.mjs.map \ No newline at end of file diff --git a/node_modules/@mswjs/interceptors/lib/node/RemoteHttpInterceptor.mjs.map b/node_modules/@mswjs/interceptors/lib/node/RemoteHttpInterceptor.mjs.map new file mode 100644 index 0000000000000000000000000000000000000000..b8ef19807abafb09286330b341de84babdd2ea93 --- /dev/null +++ b/node_modules/@mswjs/interceptors/lib/node/RemoteHttpInterceptor.mjs.map @@ -0,0 +1 @@ +{"version":3,"sources":["../../src/RemoteHttpInterceptor.ts"],"sourcesContent":["import { ChildProcess } from 'child_process'\nimport { HttpRequestEventMap } from './glossary'\nimport { Interceptor } from './Interceptor'\nimport { BatchInterceptor } from './BatchInterceptor'\nimport { ClientRequestInterceptor } from './interceptors/ClientRequest'\nimport { XMLHttpRequestInterceptor } from './interceptors/XMLHttpRequest'\nimport { handleRequest } from './utils/handleRequest'\nimport { RequestController } from './RequestController'\nimport { FetchResponse } from './utils/fetchUtils'\n\nexport interface SerializedRequest {\n id: string\n url: string\n method: string\n headers: Array<[string, string]>\n credentials: RequestCredentials\n body: string\n}\n\ninterface RevivedRequest extends Omit {\n url: URL\n headers: Headers\n}\n\nexport interface SerializedResponse {\n status: number\n statusText: string\n headers: Array<[string, string]>\n body: string\n}\n\nexport class RemoteHttpInterceptor extends BatchInterceptor<\n [ClientRequestInterceptor, XMLHttpRequestInterceptor]\n> {\n constructor() {\n super({\n name: 'remote-interceptor',\n interceptors: [\n new ClientRequestInterceptor(),\n new XMLHttpRequestInterceptor(),\n ],\n })\n }\n\n protected setup() {\n super.setup()\n\n let handleParentMessage: NodeJS.MessageListener\n\n this.on('request', async ({ request, requestId, controller }) => {\n // Send the stringified intercepted request to\n // the parent process where the remote resolver is established.\n const serializedRequest = JSON.stringify({\n id: requestId,\n method: request.method,\n url: request.url,\n headers: Array.from(request.headers.entries()),\n credentials: request.credentials,\n body: ['GET', 'HEAD'].includes(request.method)\n ? null\n : await request.text(),\n } as SerializedRequest)\n\n this.logger.info(\n 'sent serialized request to the child:',\n serializedRequest\n )\n\n process.send?.(`request:${serializedRequest}`)\n\n const responsePromise = new Promise((resolve) => {\n handleParentMessage = (message) => {\n if (typeof message !== 'string') {\n return resolve()\n }\n\n if (message.startsWith(`response:${requestId}`)) {\n const [, serializedResponse] =\n message.match(/^response:.+?:(.+)$/) || []\n\n if (!serializedResponse) {\n return resolve()\n }\n\n const responseInit = JSON.parse(\n serializedResponse\n ) as SerializedResponse\n\n const mockedResponse = new FetchResponse(responseInit.body, {\n url: request.url,\n status: responseInit.status,\n statusText: responseInit.statusText,\n headers: responseInit.headers,\n })\n\n /**\n * @todo Support \"errorWith\" as well.\n * This response handling from the child is incomplete.\n */\n\n controller.respondWith(mockedResponse)\n return resolve()\n }\n }\n })\n\n // Listen for the mocked response message from the parent.\n this.logger.info(\n 'add \"message\" listener to the parent process',\n handleParentMessage\n )\n process.addListener('message', handleParentMessage)\n\n return responsePromise\n })\n\n this.subscriptions.push(() => {\n process.removeListener('message', handleParentMessage)\n })\n }\n}\n\nexport function requestReviver(key: string, value: any) {\n switch (key) {\n case 'url':\n return new URL(value)\n\n case 'headers':\n return new Headers(value)\n\n default:\n return value\n }\n}\n\nexport interface RemoveResolverOptions {\n process: ChildProcess\n}\n\nexport class RemoteHttpResolver extends Interceptor {\n static symbol = Symbol('remote-resolver')\n private process: ChildProcess\n\n constructor(options: RemoveResolverOptions) {\n super(RemoteHttpResolver.symbol)\n this.process = options.process\n }\n\n protected setup() {\n const logger = this.logger.extend('setup')\n\n const handleChildMessage: NodeJS.MessageListener = async (message) => {\n logger.info('received message from child!', message)\n\n if (typeof message !== 'string' || !message.startsWith('request:')) {\n logger.info('unknown message, ignoring...')\n return\n }\n\n const [, serializedRequest] = message.match(/^request:(.+)$/) || []\n if (!serializedRequest) {\n return\n }\n\n const requestJson = JSON.parse(\n serializedRequest,\n requestReviver\n ) as RevivedRequest\n\n logger.info('parsed intercepted request', requestJson)\n\n const request = new Request(requestJson.url, {\n method: requestJson.method,\n headers: new Headers(requestJson.headers),\n credentials: requestJson.credentials,\n body: requestJson.body,\n })\n\n const controller = new RequestController(request)\n await handleRequest({\n request,\n requestId: requestJson.id,\n controller,\n emitter: this.emitter,\n onResponse: async (response) => {\n this.logger.info('received mocked response!', { response })\n\n const responseClone = response.clone()\n const responseText = await responseClone.text()\n\n // // Send the mocked response to the child process.\n const serializedResponse = JSON.stringify({\n status: response.status,\n statusText: response.statusText,\n headers: Array.from(response.headers.entries()),\n body: responseText,\n } as SerializedResponse)\n\n this.process.send(\n `response:${requestJson.id}:${serializedResponse}`,\n (error) => {\n if (error) {\n return\n }\n\n // Emit an optimistic \"response\" event at this point,\n // not to rely on the back-and-forth signaling for the sake of the event.\n this.emitter.emit('response', {\n request,\n requestId: requestJson.id,\n response: responseClone,\n isMockedResponse: true,\n })\n }\n )\n\n logger.info(\n 'sent serialized mocked response to the parent:',\n serializedResponse\n )\n },\n onRequestError: (response) => {\n this.logger.info('received a network error!', { response })\n throw new Error('Not implemented')\n },\n onError: (error) => {\n this.logger.info('request has errored!', { error })\n throw new Error('Not implemented')\n },\n })\n }\n\n this.subscriptions.push(() => {\n this.process.removeListener('message', handleChildMessage)\n logger.info('removed the \"message\" listener from the child process!')\n })\n\n logger.info('adding a \"message\" listener to the child process')\n this.process.addListener('message', handleChildMessage)\n\n this.process.once('error', () => this.dispose())\n this.process.once('exit', () => this.dispose())\n }\n}\n"],"mappings":"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","names":[]} \ No newline at end of file diff --git a/node_modules/@mswjs/interceptors/lib/node/chunk-3HCE66HZ.js b/node_modules/@mswjs/interceptors/lib/node/chunk-3HCE66HZ.js new file mode 100644 index 0000000000000000000000000000000000000000..24f1a9d4ed4a1a979f7eb19a99e1af27e017b7d7 --- /dev/null +++ b/node_modules/@mswjs/interceptors/lib/node/chunk-3HCE66HZ.js @@ -0,0 +1,1064 @@ +"use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + + + + + +var _chunk6L3PFBGTjs = require('./chunk-6L3PFBGT.js'); + + + + + +var _chunkWZTE4PCOjs = require('./chunk-WZTE4PCO.js'); + +// src/interceptors/ClientRequest/index.ts +var _http = require('http'); var _http2 = _interopRequireDefault(_http); +var _https = require('https'); var _https2 = _interopRequireDefault(_https); + +// src/interceptors/ClientRequest/MockHttpSocket.ts +var _net = require('net'); var _net2 = _interopRequireDefault(_net); + + +var __http_common = require('_http_common'); + +var _stream = require('stream'); +var _outvariant = require('outvariant'); + +// src/interceptors/Socket/MockSocket.ts + + +// src/interceptors/Socket/utils/normalizeSocketWriteArgs.ts +function normalizeSocketWriteArgs(args) { + const normalized = [args[0], void 0, void 0]; + if (typeof args[1] === "string") { + normalized[1] = args[1]; + } else if (typeof args[1] === "function") { + normalized[2] = args[1]; + } + if (typeof args[2] === "function") { + normalized[2] = args[2]; + } + return normalized; +} + +// src/interceptors/Socket/MockSocket.ts +var MockSocket = class extends _net2.default.Socket { + constructor(options) { + super(); + this.options = options; + this.connecting = false; + this.connect(); + this._final = (callback) => { + callback(null); + }; + } + connect() { + this.connecting = true; + return this; + } + write(...args) { + const [chunk, encoding, callback] = normalizeSocketWriteArgs( + args + ); + this.options.write(chunk, encoding, callback); + return true; + } + end(...args) { + const [chunk, encoding, callback] = normalizeSocketWriteArgs( + args + ); + this.options.write(chunk, encoding, callback); + return super.end.apply(this, args); + } + push(chunk, encoding) { + this.options.read(chunk, encoding); + return super.push(chunk, encoding); + } +}; + +// src/interceptors/Socket/utils/baseUrlFromConnectionOptions.ts +function baseUrlFromConnectionOptions(options) { + if ("href" in options) { + return new URL(options.href); + } + const protocol = options.port === 443 ? "https:" : "http:"; + const host = options.host; + const url = new URL(`${protocol}//${host}`); + if (options.port) { + url.port = options.port.toString(); + } + if (options.path) { + url.pathname = options.path; + } + if (options.auth) { + const [username, password] = options.auth.split(":"); + url.username = username; + url.password = password; + } + return url; +} + +// src/interceptors/ClientRequest/utils/recordRawHeaders.ts +var kRawHeaders = Symbol("kRawHeaders"); +var kRestorePatches = Symbol("kRestorePatches"); +function recordRawHeader(headers, args, behavior) { + ensureRawHeadersSymbol(headers, []); + const rawHeaders = Reflect.get(headers, kRawHeaders); + if (behavior === "set") { + for (let index = rawHeaders.length - 1; index >= 0; index--) { + if (rawHeaders[index][0].toLowerCase() === args[0].toLowerCase()) { + rawHeaders.splice(index, 1); + } + } + } + rawHeaders.push(args); +} +function ensureRawHeadersSymbol(headers, rawHeaders) { + if (Reflect.has(headers, kRawHeaders)) { + return; + } + defineRawHeadersSymbol(headers, rawHeaders); +} +function defineRawHeadersSymbol(headers, rawHeaders) { + Object.defineProperty(headers, kRawHeaders, { + value: rawHeaders, + enumerable: false, + // Mark the symbol as configurable so its value can be overridden. + // Overrides happen when merging raw headers from multiple sources. + // E.g. new Request(new Request(url, { headers }), { headers }) + configurable: true + }); +} +function recordRawFetchHeaders() { + if (Reflect.get(Headers, kRestorePatches)) { + return Reflect.get(Headers, kRestorePatches); + } + const { + Headers: OriginalHeaders, + Request: OriginalRequest, + Response: OriginalResponse + } = globalThis; + const { set, append, delete: headersDeleteMethod } = Headers.prototype; + Object.defineProperty(Headers, kRestorePatches, { + value: () => { + Headers.prototype.set = set; + Headers.prototype.append = append; + Headers.prototype.delete = headersDeleteMethod; + globalThis.Headers = OriginalHeaders; + globalThis.Request = OriginalRequest; + globalThis.Response = OriginalResponse; + Reflect.deleteProperty(Headers, kRestorePatches); + }, + enumerable: false, + /** + * @note Mark this property as configurable + * so we can delete it using `Reflect.delete` during cleanup. + */ + configurable: true + }); + Object.defineProperty(globalThis, "Headers", { + enumerable: true, + writable: true, + value: new Proxy(Headers, { + construct(target, args, newTarget) { + const headersInit = args[0] || []; + if (headersInit instanceof Headers && Reflect.has(headersInit, kRawHeaders)) { + const headers2 = Reflect.construct( + target, + [Reflect.get(headersInit, kRawHeaders)], + newTarget + ); + ensureRawHeadersSymbol(headers2, [ + /** + * @note Spread the retrieved headers to clone them. + * This prevents multiple Headers instances from pointing + * at the same internal "rawHeaders" array. + */ + ...Reflect.get(headersInit, kRawHeaders) + ]); + return headers2; + } + const headers = Reflect.construct(target, args, newTarget); + if (!Reflect.has(headers, kRawHeaders)) { + const rawHeadersInit = Array.isArray(headersInit) ? headersInit : Object.entries(headersInit); + ensureRawHeadersSymbol(headers, rawHeadersInit); + } + return headers; + } + }) + }); + Headers.prototype.set = new Proxy(Headers.prototype.set, { + apply(target, thisArg, args) { + recordRawHeader(thisArg, args, "set"); + return Reflect.apply(target, thisArg, args); + } + }); + Headers.prototype.append = new Proxy(Headers.prototype.append, { + apply(target, thisArg, args) { + recordRawHeader(thisArg, args, "append"); + return Reflect.apply(target, thisArg, args); + } + }); + Headers.prototype.delete = new Proxy(Headers.prototype.delete, { + apply(target, thisArg, args) { + const rawHeaders = Reflect.get(thisArg, kRawHeaders); + if (rawHeaders) { + for (let index = rawHeaders.length - 1; index >= 0; index--) { + if (rawHeaders[index][0].toLowerCase() === args[0].toLowerCase()) { + rawHeaders.splice(index, 1); + } + } + } + return Reflect.apply(target, thisArg, args); + } + }); + Object.defineProperty(globalThis, "Request", { + enumerable: true, + writable: true, + value: new Proxy(Request, { + construct(target, args, newTarget) { + const request = Reflect.construct(target, args, newTarget); + const inferredRawHeaders = []; + if (typeof args[0] === "object" && args[0].headers != null) { + inferredRawHeaders.push(...inferRawHeaders(args[0].headers)); + } + if (typeof args[1] === "object" && args[1].headers != null) { + inferredRawHeaders.push(...inferRawHeaders(args[1].headers)); + } + if (inferredRawHeaders.length > 0) { + ensureRawHeadersSymbol(request.headers, inferredRawHeaders); + } + return request; + } + }) + }); + Object.defineProperty(globalThis, "Response", { + enumerable: true, + writable: true, + value: new Proxy(Response, { + construct(target, args, newTarget) { + const response = Reflect.construct(target, args, newTarget); + if (typeof args[1] === "object" && args[1].headers != null) { + ensureRawHeadersSymbol( + response.headers, + inferRawHeaders(args[1].headers) + ); + } + return response; + } + }) + }); +} +function restoreHeadersPrototype() { + if (!Reflect.get(Headers, kRestorePatches)) { + return; + } + Reflect.get(Headers, kRestorePatches)(); +} +function getRawFetchHeaders(headers) { + if (!Reflect.has(headers, kRawHeaders)) { + return Array.from(headers.entries()); + } + const rawHeaders = Reflect.get(headers, kRawHeaders); + return rawHeaders.length > 0 ? rawHeaders : Array.from(headers.entries()); +} +function inferRawHeaders(headers) { + if (headers instanceof Headers) { + return Reflect.get(headers, kRawHeaders) || []; + } + return Reflect.get(new Headers(headers), kRawHeaders); +} + +// src/interceptors/ClientRequest/MockHttpSocket.ts +var kRequestId = Symbol("kRequestId"); +var MockHttpSocket = class extends MockSocket { + constructor(options) { + super({ + write: (chunk, encoding, callback) => { + var _a; + if (this.socketState !== "passthrough") { + this.writeBuffer.push([chunk, encoding, callback]); + } + if (chunk) { + if (this.socketState === "passthrough") { + (_a = this.originalSocket) == null ? void 0 : _a.write(chunk, encoding, callback); + } + this.requestParser.execute( + Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk, encoding) + ); + } + }, + read: (chunk) => { + if (chunk !== null) { + this.responseParser.execute( + Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk) + ); + } + } + }); + this.writeBuffer = []; + this.socketState = "unknown"; + this.onRequestStart = (versionMajor, versionMinor, rawHeaders, _, path, __, ___, ____, shouldKeepAlive) => { + var _a; + this.shouldKeepAlive = shouldKeepAlive; + const url = new URL(path, this.baseUrl); + const method = ((_a = this.connectionOptions.method) == null ? void 0 : _a.toUpperCase()) || "GET"; + const headers = _chunkWZTE4PCOjs.FetchResponse.parseRawHeaders(rawHeaders); + const canHaveBody = method !== "GET" && method !== "HEAD"; + if (url.username || url.password) { + if (!headers.has("authorization")) { + headers.set("authorization", `Basic ${url.username}:${url.password}`); + } + url.username = ""; + url.password = ""; + } + if (canHaveBody) { + this.requestStream = new (0, _stream.Readable)({ + /** + * @note Provide the `read()` method so a `Readable` could be + * used as the actual request body (the stream calls "read()"). + * We control the queue in the onRequestBody/End functions. + */ + read: () => { + this.flushWriteBuffer(); + } + }); + } + const requestId = _chunkWZTE4PCOjs.createRequestId.call(void 0, ); + this.request = new Request(url, { + method, + headers, + credentials: "same-origin", + // @ts-expect-error Undocumented Fetch property. + duplex: canHaveBody ? "half" : void 0, + body: canHaveBody ? _stream.Readable.toWeb(this.requestStream) : null + }); + Reflect.set(this.request, kRequestId, requestId); + if (this.request.headers.has(_chunkWZTE4PCOjs.INTERNAL_REQUEST_ID_HEADER_NAME)) { + this.passthrough(); + return; + } + this.onRequest({ + requestId, + request: this.request, + socket: this + }); + }; + this.onResponseStart = (versionMajor, versionMinor, rawHeaders, method, url, status, statusText) => { + const headers = _chunkWZTE4PCOjs.FetchResponse.parseRawHeaders(rawHeaders); + const response = new (0, _chunkWZTE4PCOjs.FetchResponse)( + /** + * @note The Fetch API response instance exposed to the consumer + * is created over the response stream of the HTTP parser. It is NOT + * related to the Socket instance. This way, you can read response body + * in response listener while the Socket instance delays the emission + * of "end" and other events until those response listeners are finished. + */ + _chunkWZTE4PCOjs.FetchResponse.isResponseWithBody(status) ? _stream.Readable.toWeb( + this.responseStream = new (0, _stream.Readable)({ read() { + } }) + ) : null, + { + url, + status, + statusText, + headers + } + ); + _outvariant.invariant.call(void 0, + this.request, + "Failed to handle a response: request does not exist" + ); + if (this.request.headers.has(_chunkWZTE4PCOjs.INTERNAL_REQUEST_ID_HEADER_NAME)) { + return; + } + this.responseListenersPromise = this.onResponse({ + response, + isMockedResponse: this.socketState === "mock", + requestId: Reflect.get(this.request, kRequestId), + request: this.request, + socket: this + }); + }; + this.connectionOptions = options.connectionOptions; + this.createConnection = options.createConnection; + this.onRequest = options.onRequest; + this.onResponse = options.onResponse; + this.baseUrl = baseUrlFromConnectionOptions(this.connectionOptions); + this.requestParser = new (0, __http_common.HTTPParser)(); + this.requestParser.initialize(__http_common.HTTPParser.REQUEST, {}); + this.requestParser[__http_common.HTTPParser.kOnHeadersComplete] = this.onRequestStart.bind(this); + this.requestParser[__http_common.HTTPParser.kOnBody] = this.onRequestBody.bind(this); + this.requestParser[__http_common.HTTPParser.kOnMessageComplete] = this.onRequestEnd.bind(this); + this.responseParser = new (0, __http_common.HTTPParser)(); + this.responseParser.initialize(__http_common.HTTPParser.RESPONSE, {}); + this.responseParser[__http_common.HTTPParser.kOnHeadersComplete] = this.onResponseStart.bind(this); + this.responseParser[__http_common.HTTPParser.kOnBody] = this.onResponseBody.bind(this); + this.responseParser[__http_common.HTTPParser.kOnMessageComplete] = this.onResponseEnd.bind(this); + this.once("finish", () => this.requestParser.free()); + if (this.baseUrl.protocol === "https:") { + Reflect.set(this, "encrypted", true); + Reflect.set(this, "authorized", false); + Reflect.set(this, "getProtocol", () => "TLSv1.3"); + Reflect.set(this, "getSession", () => void 0); + Reflect.set(this, "isSessionReused", () => false); + } + } + emit(event, ...args) { + const emitEvent = super.emit.bind(this, event, ...args); + if (this.responseListenersPromise) { + this.responseListenersPromise.finally(emitEvent); + return this.listenerCount(event) > 0; + } + return emitEvent(); + } + destroy(error) { + this.responseParser.free(); + if (error) { + this.emit("error", error); + } + return super.destroy(error); + } + /** + * Establish this Socket connection as-is and pipe + * its data/events through this Socket. + */ + passthrough() { + this.socketState = "passthrough"; + if (this.destroyed) { + return; + } + const socket = this.createConnection(); + this.originalSocket = socket; + this.once("error", (error) => { + socket.destroy(error); + }); + this.address = socket.address.bind(socket); + let writeArgs; + let headersWritten = false; + while (writeArgs = this.writeBuffer.shift()) { + if (writeArgs !== void 0) { + if (!headersWritten) { + const [chunk, encoding, callback] = writeArgs; + const chunkString = chunk.toString(); + const chunkBeforeRequestHeaders = chunkString.slice( + 0, + chunkString.indexOf("\r\n") + 2 + ); + const chunkAfterRequestHeaders = chunkString.slice( + chunk.indexOf("\r\n\r\n") + ); + const rawRequestHeaders = getRawFetchHeaders(this.request.headers); + const requestHeadersString = rawRequestHeaders.filter(([name]) => { + return name.toLowerCase() !== _chunkWZTE4PCOjs.INTERNAL_REQUEST_ID_HEADER_NAME; + }).map(([name, value]) => `${name}: ${value}`).join("\r\n"); + const headersChunk = `${chunkBeforeRequestHeaders}${requestHeadersString}${chunkAfterRequestHeaders}`; + socket.write(headersChunk, encoding, callback); + headersWritten = true; + continue; + } + socket.write(...writeArgs); + } + } + if (Reflect.get(socket, "encrypted")) { + const tlsProperties = [ + "encrypted", + "authorized", + "getProtocol", + "getSession", + "isSessionReused" + ]; + tlsProperties.forEach((propertyName) => { + Object.defineProperty(this, propertyName, { + enumerable: true, + get: () => { + const value = Reflect.get(socket, propertyName); + return typeof value === "function" ? value.bind(socket) : value; + } + }); + }); + } + socket.on("lookup", (...args) => this.emit("lookup", ...args)).on("connect", () => { + this.connecting = socket.connecting; + this.emit("connect"); + }).on("secureConnect", () => this.emit("secureConnect")).on("secure", () => this.emit("secure")).on("session", (session) => this.emit("session", session)).on("ready", () => this.emit("ready")).on("drain", () => this.emit("drain")).on("data", (chunk) => { + this.push(chunk); + }).on("error", (error) => { + Reflect.set(this, "_hadError", Reflect.get(socket, "_hadError")); + this.emit("error", error); + }).on("resume", () => this.emit("resume")).on("timeout", () => this.emit("timeout")).on("prefinish", () => this.emit("prefinish")).on("finish", () => this.emit("finish")).on("close", (hadError) => this.emit("close", hadError)).on("end", () => this.emit("end")); + } + /** + * Convert the given Fetch API `Response` instance to an + * HTTP message and push it to the socket. + */ + async respondWith(response) { + var _a; + if (this.destroyed) { + return; + } + if (_chunk6L3PFBGTjs.isPropertyAccessible.call(void 0, response, "type") && response.type === "error") { + this.errorWith(new TypeError("Network error")); + return; + } + this.mockConnect(); + this.socketState = "mock"; + this.flushWriteBuffer(); + const serverResponse = new (0, _http.ServerResponse)(new (0, _http.IncomingMessage)(this)); + serverResponse.assignSocket( + new MockSocket({ + write: (chunk, encoding, callback) => { + this.push(chunk, encoding); + callback == null ? void 0 : callback(); + }, + read() { + } + }) + ); + serverResponse.removeHeader("connection"); + serverResponse.removeHeader("date"); + const rawResponseHeaders = getRawFetchHeaders(response.headers); + serverResponse.writeHead( + response.status, + response.statusText || _http.STATUS_CODES[response.status], + rawResponseHeaders + ); + this.once("error", () => { + serverResponse.destroy(); + }); + if (response.body) { + try { + const reader = response.body.getReader(); + while (true) { + const { done, value } = await reader.read(); + if (done) { + serverResponse.end(); + break; + } + serverResponse.write(value); + } + } catch (error) { + this.respondWith(_chunk6L3PFBGTjs.createServerErrorResponse.call(void 0, error)); + return; + } + } else { + serverResponse.end(); + } + if (!this.shouldKeepAlive) { + this.emit("readable"); + (_a = this.responseStream) == null ? void 0 : _a.push(null); + this.push(null); + } + } + /** + * Close this socket connection with the given error. + */ + errorWith(error) { + this.destroy(error); + } + mockConnect() { + this.connecting = false; + const isIPv6 = _net2.default.isIPv6(this.connectionOptions.hostname) || this.connectionOptions.family === 6; + const addressInfo = { + address: isIPv6 ? "::1" : "127.0.0.1", + family: isIPv6 ? "IPv6" : "IPv4", + port: this.connectionOptions.port + }; + this.address = () => addressInfo; + this.emit( + "lookup", + null, + addressInfo.address, + addressInfo.family === "IPv6" ? 6 : 4, + this.connectionOptions.host + ); + this.emit("connect"); + this.emit("ready"); + if (this.baseUrl.protocol === "https:") { + this.emit("secure"); + this.emit("secureConnect"); + this.emit( + "session", + this.connectionOptions.session || Buffer.from("mock-session-renegotiate") + ); + this.emit("session", Buffer.from("mock-session-resume")); + } + } + flushWriteBuffer() { + for (const writeCall of this.writeBuffer) { + if (typeof writeCall[2] === "function") { + writeCall[2](); + writeCall[2] = void 0; + } + } + } + onRequestBody(chunk) { + _outvariant.invariant.call(void 0, + this.requestStream, + "Failed to write to a request stream: stream does not exist" + ); + this.requestStream.push(chunk); + } + onRequestEnd() { + if (this.requestStream) { + this.requestStream.push(null); + } + } + onResponseBody(chunk) { + _outvariant.invariant.call(void 0, + this.responseStream, + "Failed to write to a response stream: stream does not exist" + ); + this.responseStream.push(chunk); + } + onResponseEnd() { + if (this.responseStream) { + this.responseStream.push(null); + } + } +}; + +// src/interceptors/ClientRequest/agents.ts + + +var MockAgent = class extends _http2.default.Agent { + constructor(options) { + super(); + this.customAgent = options.customAgent; + this.onRequest = options.onRequest; + this.onResponse = options.onResponse; + } + createConnection(options, callback) { + const createConnection = this.customAgent instanceof _http2.default.Agent ? this.customAgent.createConnection : super.createConnection; + const createConnectionOptions = this.customAgent instanceof _http2.default.Agent ? { + ...options, + ...this.customAgent.options + } : options; + const socket = new MockHttpSocket({ + connectionOptions: options, + createConnection: createConnection.bind( + this.customAgent || this, + createConnectionOptions, + callback + ), + onRequest: this.onRequest.bind(this), + onResponse: this.onResponse.bind(this) + }); + return socket; + } +}; +var MockHttpsAgent = class extends _https2.default.Agent { + constructor(options) { + super(); + this.customAgent = options.customAgent; + this.onRequest = options.onRequest; + this.onResponse = options.onResponse; + } + createConnection(options, callback) { + const createConnection = this.customAgent instanceof _https2.default.Agent ? this.customAgent.createConnection : super.createConnection; + const createConnectionOptions = this.customAgent instanceof _https2.default.Agent ? { + ...options, + ...this.customAgent.options + } : options; + const socket = new MockHttpSocket({ + connectionOptions: options, + createConnection: createConnection.bind( + this.customAgent || this, + createConnectionOptions, + callback + ), + onRequest: this.onRequest.bind(this), + onResponse: this.onResponse.bind(this) + }); + return socket; + } +}; + +// src/interceptors/ClientRequest/utils/normalizeClientRequestArgs.ts +var _url = require('url'); + + + + + + + + + + + + +var _logger = require('@open-draft/logger'); + +// src/utils/getUrlByRequestOptions.ts + + +var logger = new (0, _logger.Logger)("utils getUrlByRequestOptions"); +var DEFAULT_PATH = "/"; +var DEFAULT_PROTOCOL = "http:"; +var DEFAULT_HOSTNAME = "localhost"; +var SSL_PORT = 443; +function getAgent(options) { + return options.agent instanceof _http.Agent ? options.agent : void 0; +} +function getProtocolByRequestOptions(options) { + var _a; + if (options.protocol) { + return options.protocol; + } + const agent = getAgent(options); + const agentProtocol = agent == null ? void 0 : agent.protocol; + if (agentProtocol) { + return agentProtocol; + } + const port = getPortByRequestOptions(options); + const isSecureRequest = options.cert || port === SSL_PORT; + return isSecureRequest ? "https:" : ((_a = options.uri) == null ? void 0 : _a.protocol) || DEFAULT_PROTOCOL; +} +function getPortByRequestOptions(options) { + if (options.port) { + return Number(options.port); + } + const agent = getAgent(options); + if (agent == null ? void 0 : agent.options.port) { + return Number(agent.options.port); + } + if (agent == null ? void 0 : agent.defaultPort) { + return Number(agent.defaultPort); + } + return void 0; +} +function getAuthByRequestOptions(options) { + if (options.auth) { + const [username, password] = options.auth.split(":"); + return { username, password }; + } +} +function isRawIPv6Address(host) { + return host.includes(":") && !host.startsWith("[") && !host.endsWith("]"); +} +function getHostname(options) { + let host = options.hostname || options.host; + if (host) { + if (isRawIPv6Address(host)) { + host = `[${host}]`; + } + return new URL(`http://${host}`).hostname; + } + return DEFAULT_HOSTNAME; +} +function getUrlByRequestOptions(options) { + logger.info("request options", options); + if (options.uri) { + logger.info( + 'constructing url from explicitly provided "options.uri": %s', + options.uri + ); + return new URL(options.uri.href); + } + logger.info("figuring out url from request options..."); + const protocol = getProtocolByRequestOptions(options); + logger.info("protocol", protocol); + const port = getPortByRequestOptions(options); + logger.info("port", port); + const hostname = getHostname(options); + logger.info("hostname", hostname); + const path = options.path || DEFAULT_PATH; + logger.info("path", path); + const credentials = getAuthByRequestOptions(options); + logger.info("credentials", credentials); + const authString = credentials ? `${credentials.username}:${credentials.password}@` : ""; + logger.info("auth string:", authString); + const portString = typeof port !== "undefined" ? `:${port}` : ""; + const url = new URL(`${protocol}//${hostname}${portString}${path}`); + url.username = (credentials == null ? void 0 : credentials.username) || ""; + url.password = (credentials == null ? void 0 : credentials.password) || ""; + logger.info("created url:", url); + return url; +} + +// src/utils/cloneObject.ts + +var logger2 = new (0, _logger.Logger)("cloneObject"); +function isPlainObject(obj) { + var _a; + logger2.info("is plain object?", obj); + if (obj == null || !((_a = obj.constructor) == null ? void 0 : _a.name)) { + logger2.info("given object is undefined, not a plain object..."); + return false; + } + logger2.info("checking the object constructor:", obj.constructor.name); + return obj.constructor.name === "Object"; +} +function cloneObject(obj) { + logger2.info("cloning object:", obj); + const enumerableProperties = Object.entries(obj).reduce( + (acc, [key, value]) => { + logger2.info("analyzing key-value pair:", key, value); + acc[key] = isPlainObject(value) ? cloneObject(value) : value; + return acc; + }, + {} + ); + return isPlainObject(obj) ? enumerableProperties : Object.assign(Object.getPrototypeOf(obj), enumerableProperties); +} + +// src/utils/isObject.ts +function isObject(value, loose = false) { + return loose ? Object.prototype.toString.call(value).startsWith("[object ") : Object.prototype.toString.call(value) === "[object Object]"; +} + +// src/interceptors/ClientRequest/utils/normalizeClientRequestArgs.ts +var logger3 = new (0, _logger.Logger)("http normalizeClientRequestArgs"); +function resolveRequestOptions(args, url) { + if (typeof args[1] === "undefined" || typeof args[1] === "function") { + logger3.info("request options not provided, deriving from the url", url); + return _url.urlToHttpOptions.call(void 0, url); + } + if (args[1]) { + logger3.info("has custom RequestOptions!", args[1]); + const requestOptionsFromUrl = _url.urlToHttpOptions.call(void 0, url); + logger3.info("derived RequestOptions from the URL:", requestOptionsFromUrl); + logger3.info("cloning RequestOptions..."); + const clonedRequestOptions = cloneObject(args[1]); + logger3.info("successfully cloned RequestOptions!", clonedRequestOptions); + return { + ...requestOptionsFromUrl, + ...clonedRequestOptions + }; + } + logger3.info("using an empty object as request options"); + return {}; +} +function overrideUrlByRequestOptions(url, options) { + url.host = options.host || url.host; + url.hostname = options.hostname || url.hostname; + url.port = options.port ? options.port.toString() : url.port; + if (options.path) { + const parsedOptionsPath = _url.parse.call(void 0, options.path, false); + url.pathname = parsedOptionsPath.pathname || ""; + url.search = parsedOptionsPath.search || ""; + } + return url; +} +function resolveCallback(args) { + return typeof args[1] === "function" ? args[1] : args[2]; +} +function normalizeClientRequestArgs(defaultProtocol, args) { + let url; + let options; + let callback; + logger3.info("arguments", args); + logger3.info("using default protocol:", defaultProtocol); + if (args.length === 0) { + const url2 = new (0, _url.URL)("http://localhost"); + const options2 = resolveRequestOptions(args, url2); + return [url2, options2]; + } + if (typeof args[0] === "string") { + logger3.info("first argument is a location string:", args[0]); + url = new (0, _url.URL)(args[0]); + logger3.info("created a url:", url); + const requestOptionsFromUrl = _url.urlToHttpOptions.call(void 0, url); + logger3.info("request options from url:", requestOptionsFromUrl); + options = resolveRequestOptions(args, url); + logger3.info("resolved request options:", options); + callback = resolveCallback(args); + } else if (args[0] instanceof _url.URL) { + url = args[0]; + logger3.info("first argument is a URL:", url); + if (typeof args[1] !== "undefined" && isObject(args[1])) { + url = overrideUrlByRequestOptions(url, args[1]); + } + options = resolveRequestOptions(args, url); + logger3.info("derived request options:", options); + callback = resolveCallback(args); + } else if ("hash" in args[0] && !("method" in args[0])) { + const [legacyUrl] = args; + logger3.info("first argument is a legacy URL:", legacyUrl); + if (legacyUrl.hostname === null) { + logger3.info("given legacy URL is relative (no hostname)"); + return isObject(args[1]) ? normalizeClientRequestArgs(defaultProtocol, [ + { path: legacyUrl.path, ...args[1] }, + args[2] + ]) : normalizeClientRequestArgs(defaultProtocol, [ + { path: legacyUrl.path }, + args[1] + ]); + } + logger3.info("given legacy url is absolute"); + const resolvedUrl = new (0, _url.URL)(legacyUrl.href); + return args[1] === void 0 ? normalizeClientRequestArgs(defaultProtocol, [resolvedUrl]) : typeof args[1] === "function" ? normalizeClientRequestArgs(defaultProtocol, [resolvedUrl, args[1]]) : normalizeClientRequestArgs(defaultProtocol, [ + resolvedUrl, + args[1], + args[2] + ]); + } else if (isObject(args[0])) { + options = { ...args[0] }; + logger3.info("first argument is RequestOptions:", options); + options.protocol = options.protocol || defaultProtocol; + logger3.info("normalized request options:", options); + url = getUrlByRequestOptions(options); + logger3.info("created a URL from RequestOptions:", url.href); + callback = resolveCallback(args); + } else { + throw new Error( + `Failed to construct ClientRequest with these parameters: ${args}` + ); + } + options.protocol = options.protocol || url.protocol; + options.method = options.method || "GET"; + if (typeof options.agent === "undefined") { + const agent = options.protocol === "https:" ? new (0, _https.Agent)({ + // Any other value other than false is considered as true, so we don't add this property if undefined. + ..."rejectUnauthorized" in options && { + rejectUnauthorized: options.rejectUnauthorized + } + }) : new (0, _http.Agent)(); + options.agent = agent; + logger3.info("resolved fallback agent:", agent); + } + if (!options._defaultAgent) { + logger3.info( + 'has no default agent, setting the default agent for "%s"', + options.protocol + ); + options._defaultAgent = options.protocol === "https:" ? _https.globalAgent : _http.globalAgent; + } + logger3.info("successfully resolved url:", url.href); + logger3.info("successfully resolved options:", options); + logger3.info("successfully resolved callback:", callback); + if (!(url instanceof _url.URL)) { + url = url.toString(); + } + return [url, options, callback]; +} + +// src/interceptors/ClientRequest/index.ts +var _ClientRequestInterceptor = class extends _chunkWZTE4PCOjs.Interceptor { + constructor() { + super(_ClientRequestInterceptor.symbol); + this.onRequest = async ({ + request, + socket + }) => { + const requestId = Reflect.get(request, kRequestId); + const controller = new (0, _chunk6L3PFBGTjs.RequestController)(request); + const isRequestHandled = await _chunk6L3PFBGTjs.handleRequest.call(void 0, { + request, + requestId, + controller, + emitter: this.emitter, + onResponse: (response) => { + socket.respondWith(response); + }, + onRequestError: (response) => { + socket.respondWith(response); + }, + onError: (error) => { + if (error instanceof Error) { + socket.errorWith(error); + } + } + }); + if (!isRequestHandled) { + return socket.passthrough(); + } + }; + this.onResponse = async ({ + requestId, + request, + response, + isMockedResponse + }) => { + return _chunk6L3PFBGTjs.emitAsync.call(void 0, this.emitter, "response", { + requestId, + request, + response, + isMockedResponse + }); + }; + } + setup() { + const { get: originalGet, request: originalRequest } = _http2.default; + const { get: originalHttpsGet, request: originalHttpsRequest } = _https2.default; + const onRequest = this.onRequest.bind(this); + const onResponse = this.onResponse.bind(this); + _http2.default.request = new Proxy(_http2.default.request, { + apply: (target, thisArg, args) => { + const [url, options, callback] = normalizeClientRequestArgs( + "http:", + args + ); + const mockAgent = new MockAgent({ + customAgent: options.agent, + onRequest, + onResponse + }); + options.agent = mockAgent; + return Reflect.apply(target, thisArg, [url, options, callback]); + } + }); + _http2.default.get = new Proxy(_http2.default.get, { + apply: (target, thisArg, args) => { + const [url, options, callback] = normalizeClientRequestArgs( + "http:", + args + ); + const mockAgent = new MockAgent({ + customAgent: options.agent, + onRequest, + onResponse + }); + options.agent = mockAgent; + return Reflect.apply(target, thisArg, [url, options, callback]); + } + }); + _https2.default.request = new Proxy(_https2.default.request, { + apply: (target, thisArg, args) => { + const [url, options, callback] = normalizeClientRequestArgs( + "https:", + args + ); + const mockAgent = new MockHttpsAgent({ + customAgent: options.agent, + onRequest, + onResponse + }); + options.agent = mockAgent; + return Reflect.apply(target, thisArg, [url, options, callback]); + } + }); + _https2.default.get = new Proxy(_https2.default.get, { + apply: (target, thisArg, args) => { + const [url, options, callback] = normalizeClientRequestArgs( + "https:", + args + ); + const mockAgent = new MockHttpsAgent({ + customAgent: options.agent, + onRequest, + onResponse + }); + options.agent = mockAgent; + return Reflect.apply(target, thisArg, [url, options, callback]); + } + }); + recordRawFetchHeaders(); + this.subscriptions.push(() => { + _http2.default.get = originalGet; + _http2.default.request = originalRequest; + _https2.default.get = originalHttpsGet; + _https2.default.request = originalHttpsRequest; + restoreHeadersPrototype(); + }); + } +}; +var ClientRequestInterceptor = _ClientRequestInterceptor; +ClientRequestInterceptor.symbol = Symbol("client-request-interceptor"); + + + +exports.ClientRequestInterceptor = ClientRequestInterceptor; +//# sourceMappingURL=chunk-3HCE66HZ.js.map \ No newline at end of file diff --git a/node_modules/@mswjs/interceptors/lib/node/chunk-3HCE66HZ.js.map b/node_modules/@mswjs/interceptors/lib/node/chunk-3HCE66HZ.js.map new file mode 100644 index 0000000000000000000000000000000000000000..270a59677ff81ccee0a5786120944babc71fd5c1 --- /dev/null +++ b/node_modules/@mswjs/interceptors/lib/node/chunk-3HCE66HZ.js.map @@ -0,0 +1 @@ +{"version":3,"sources":["../../src/interceptors/ClientRequest/index.ts","../../src/interceptors/ClientRequest/MockHttpSocket.ts","../../src/interceptors/Socket/MockSocket.ts","../../src/interceptors/Socket/utils/normalizeSocketWriteArgs.ts","../../src/interceptors/Socket/utils/baseUrlFromConnectionOptions.ts","../../src/interceptors/ClientRequest/utils/recordRawHeaders.ts","../../src/interceptors/ClientRequest/agents.ts","../../src/interceptors/ClientRequest/utils/normalizeClientRequestArgs.ts","../../src/utils/getUrlByRequestOptions.ts","../../src/utils/cloneObject.ts","../../src/utils/isObject.ts"],"names":["http","https","net","headers","URL","Logger","logger","url","options"],"mappings":"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","sourcesContent":["import http from 'node:http'\nimport https from 'node:https'\nimport { Interceptor } from '../../Interceptor'\nimport type { HttpRequestEventMap } from '../../glossary'\nimport {\n kRequestId,\n MockHttpSocketRequestCallback,\n MockHttpSocketResponseCallback,\n} from './MockHttpSocket'\nimport { MockAgent, MockHttpsAgent } from './agents'\nimport { RequestController } from '../../RequestController'\nimport { emitAsync } from '../../utils/emitAsync'\nimport { normalizeClientRequestArgs } from './utils/normalizeClientRequestArgs'\nimport { handleRequest } from '../../utils/handleRequest'\nimport {\n recordRawFetchHeaders,\n restoreHeadersPrototype,\n} from './utils/recordRawHeaders'\n\nexport class ClientRequestInterceptor extends Interceptor {\n static symbol = Symbol('client-request-interceptor')\n\n constructor() {\n super(ClientRequestInterceptor.symbol)\n }\n\n protected setup(): void {\n const { get: originalGet, request: originalRequest } = http\n const { get: originalHttpsGet, request: originalHttpsRequest } = https\n\n const onRequest = this.onRequest.bind(this)\n const onResponse = this.onResponse.bind(this)\n\n http.request = new Proxy(http.request, {\n apply: (target, thisArg, args: Parameters) => {\n const [url, options, callback] = normalizeClientRequestArgs(\n 'http:',\n args\n )\n const mockAgent = new MockAgent({\n customAgent: options.agent,\n onRequest,\n onResponse,\n })\n options.agent = mockAgent\n\n return Reflect.apply(target, thisArg, [url, options, callback])\n },\n })\n\n http.get = new Proxy(http.get, {\n apply: (target, thisArg, args: Parameters) => {\n const [url, options, callback] = normalizeClientRequestArgs(\n 'http:',\n args\n )\n\n const mockAgent = new MockAgent({\n customAgent: options.agent,\n onRequest,\n onResponse,\n })\n options.agent = mockAgent\n\n return Reflect.apply(target, thisArg, [url, options, callback])\n },\n })\n\n //\n // HTTPS.\n //\n\n https.request = new Proxy(https.request, {\n apply: (target, thisArg, args: Parameters) => {\n const [url, options, callback] = normalizeClientRequestArgs(\n 'https:',\n args\n )\n\n const mockAgent = new MockHttpsAgent({\n customAgent: options.agent,\n onRequest,\n onResponse,\n })\n options.agent = mockAgent\n\n return Reflect.apply(target, thisArg, [url, options, callback])\n },\n })\n\n https.get = new Proxy(https.get, {\n apply: (target, thisArg, args: Parameters) => {\n const [url, options, callback] = normalizeClientRequestArgs(\n 'https:',\n args\n )\n\n const mockAgent = new MockHttpsAgent({\n customAgent: options.agent,\n onRequest,\n onResponse,\n })\n options.agent = mockAgent\n\n return Reflect.apply(target, thisArg, [url, options, callback])\n },\n })\n\n // Spy on `Header.prototype.set` and `Header.prototype.append` calls\n // and record the raw header names provided. This is to support\n // `IncomingMessage.prototype.rawHeaders`.\n recordRawFetchHeaders()\n\n this.subscriptions.push(() => {\n http.get = originalGet\n http.request = originalRequest\n\n https.get = originalHttpsGet\n https.request = originalHttpsRequest\n\n restoreHeadersPrototype()\n })\n }\n\n private onRequest: MockHttpSocketRequestCallback = async ({\n request,\n socket,\n }) => {\n const requestId = Reflect.get(request, kRequestId)\n const controller = new RequestController(request)\n\n const isRequestHandled = await handleRequest({\n request,\n requestId,\n controller,\n emitter: this.emitter,\n onResponse: (response) => {\n socket.respondWith(response)\n },\n onRequestError: (response) => {\n socket.respondWith(response)\n },\n onError: (error) => {\n if (error instanceof Error) {\n socket.errorWith(error)\n }\n },\n })\n\n if (!isRequestHandled) {\n return socket.passthrough()\n }\n }\n\n public onResponse: MockHttpSocketResponseCallback = async ({\n requestId,\n request,\n response,\n isMockedResponse,\n }) => {\n // Return the promise to when all the response event listeners\n // are finished.\n return emitAsync(this.emitter, 'response', {\n requestId,\n request,\n response,\n isMockedResponse,\n })\n }\n}\n","import net from 'node:net'\nimport {\n HTTPParser,\n type RequestHeadersCompleteCallback,\n type ResponseHeadersCompleteCallback,\n} from '_http_common'\nimport { STATUS_CODES, IncomingMessage, ServerResponse } from 'node:http'\nimport { Readable } from 'node:stream'\nimport { invariant } from 'outvariant'\nimport { INTERNAL_REQUEST_ID_HEADER_NAME } from '../../Interceptor'\nimport { MockSocket } from '../Socket/MockSocket'\nimport type { NormalizedSocketWriteArgs } from '../Socket/utils/normalizeSocketWriteArgs'\nimport { isPropertyAccessible } from '../../utils/isPropertyAccessible'\nimport { baseUrlFromConnectionOptions } from '../Socket/utils/baseUrlFromConnectionOptions'\nimport { createServerErrorResponse } from '../../utils/responseUtils'\nimport { createRequestId } from '../../createRequestId'\nimport { getRawFetchHeaders } from './utils/recordRawHeaders'\nimport { FetchResponse } from '../../utils/fetchUtils'\n\ntype HttpConnectionOptions = any\n\nexport type MockHttpSocketRequestCallback = (args: {\n requestId: string\n request: Request\n socket: MockHttpSocket\n}) => void\n\nexport type MockHttpSocketResponseCallback = (args: {\n requestId: string\n request: Request\n response: Response\n isMockedResponse: boolean\n socket: MockHttpSocket\n}) => Promise\n\ninterface MockHttpSocketOptions {\n connectionOptions: HttpConnectionOptions\n createConnection: () => net.Socket\n onRequest: MockHttpSocketRequestCallback\n onResponse: MockHttpSocketResponseCallback\n}\n\nexport const kRequestId = Symbol('kRequestId')\n\nexport class MockHttpSocket extends MockSocket {\n private connectionOptions: HttpConnectionOptions\n private createConnection: () => net.Socket\n private baseUrl: URL\n\n private onRequest: MockHttpSocketRequestCallback\n private onResponse: MockHttpSocketResponseCallback\n private responseListenersPromise?: Promise\n\n private writeBuffer: Array = []\n private request?: Request\n private requestParser: HTTPParser<0>\n private requestStream?: Readable\n private shouldKeepAlive?: boolean\n\n private socketState: 'unknown' | 'mock' | 'passthrough' = 'unknown'\n private responseParser: HTTPParser<1>\n private responseStream?: Readable\n private originalSocket?: net.Socket\n\n constructor(options: MockHttpSocketOptions) {\n super({\n write: (chunk, encoding, callback) => {\n // Buffer the writes so they can be flushed in case of the original connection\n // and when reading the request body in the interceptor. If the connection has\n // been established, no need to buffer the chunks anymore, they will be forwarded.\n if (this.socketState !== 'passthrough') {\n this.writeBuffer.push([chunk, encoding, callback])\n }\n\n if (chunk) {\n /**\n * Forward any writes to the mock socket to the underlying original socket.\n * This ensures functional duplex connections, like WebSocket.\n * @see https://github.com/mswjs/interceptors/issues/682\n */\n if (this.socketState === 'passthrough') {\n this.originalSocket?.write(chunk, encoding, callback)\n }\n\n this.requestParser.execute(\n Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk, encoding)\n )\n }\n },\n read: (chunk) => {\n if (chunk !== null) {\n /**\n * @todo We need to free the parser if the connection has been\n * upgraded to a non-HTTP protocol. It won't be able to parse data\n * from that point onward anyway. No need to keep it in memory.\n */\n this.responseParser.execute(\n Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk)\n )\n }\n },\n })\n\n this.connectionOptions = options.connectionOptions\n this.createConnection = options.createConnection\n this.onRequest = options.onRequest\n this.onResponse = options.onResponse\n\n this.baseUrl = baseUrlFromConnectionOptions(this.connectionOptions)\n\n // Request parser.\n this.requestParser = new HTTPParser()\n this.requestParser.initialize(HTTPParser.REQUEST, {})\n this.requestParser[HTTPParser.kOnHeadersComplete] =\n this.onRequestStart.bind(this)\n this.requestParser[HTTPParser.kOnBody] = this.onRequestBody.bind(this)\n this.requestParser[HTTPParser.kOnMessageComplete] =\n this.onRequestEnd.bind(this)\n\n // Response parser.\n this.responseParser = new HTTPParser()\n this.responseParser.initialize(HTTPParser.RESPONSE, {})\n this.responseParser[HTTPParser.kOnHeadersComplete] =\n this.onResponseStart.bind(this)\n this.responseParser[HTTPParser.kOnBody] = this.onResponseBody.bind(this)\n this.responseParser[HTTPParser.kOnMessageComplete] =\n this.onResponseEnd.bind(this)\n\n // Once the socket is finished, nothing can write to it\n // anymore. It has also flushed any buffered chunks.\n this.once('finish', () => this.requestParser.free())\n\n if (this.baseUrl.protocol === 'https:') {\n Reflect.set(this, 'encrypted', true)\n // The server certificate is not the same as a CA\n // passed to the TLS socket connection options.\n Reflect.set(this, 'authorized', false)\n Reflect.set(this, 'getProtocol', () => 'TLSv1.3')\n Reflect.set(this, 'getSession', () => undefined)\n Reflect.set(this, 'isSessionReused', () => false)\n }\n }\n\n public emit(event: string | symbol, ...args: any[]): boolean {\n const emitEvent = super.emit.bind(this, event as any, ...args)\n\n if (this.responseListenersPromise) {\n this.responseListenersPromise.finally(emitEvent)\n return this.listenerCount(event) > 0\n }\n\n return emitEvent()\n }\n\n public destroy(error?: Error | undefined): this {\n // Destroy the response parser when the socket gets destroyed.\n // Normally, we shoud listen to the \"close\" event but it\n // can be suppressed by using the \"emitClose: false\" option.\n this.responseParser.free()\n\n if (error) {\n this.emit('error', error)\n }\n\n return super.destroy(error)\n }\n\n /**\n * Establish this Socket connection as-is and pipe\n * its data/events through this Socket.\n */\n public passthrough(): void {\n this.socketState = 'passthrough'\n\n if (this.destroyed) {\n return\n }\n\n const socket = this.createConnection()\n this.originalSocket = socket\n\n // If the developer destroys the socket, destroy the original connection.\n this.once('error', (error) => {\n socket.destroy(error)\n })\n\n this.address = socket.address.bind(socket)\n\n // Flush the buffered \"socket.write()\" calls onto\n // the original socket instance (i.e. write request body).\n // Exhaust the \"requestBuffer\" in case this Socket\n // gets reused for different requests.\n let writeArgs: NormalizedSocketWriteArgs | undefined\n let headersWritten = false\n\n while ((writeArgs = this.writeBuffer.shift())) {\n if (writeArgs !== undefined) {\n if (!headersWritten) {\n const [chunk, encoding, callback] = writeArgs\n const chunkString = chunk.toString()\n const chunkBeforeRequestHeaders = chunkString.slice(\n 0,\n chunkString.indexOf('\\r\\n') + 2\n )\n const chunkAfterRequestHeaders = chunkString.slice(\n chunk.indexOf('\\r\\n\\r\\n')\n )\n const rawRequestHeaders = getRawFetchHeaders(this.request!.headers)\n const requestHeadersString = rawRequestHeaders\n // Skip the internal request ID deduplication header.\n .filter(([name]) => {\n return name.toLowerCase() !== INTERNAL_REQUEST_ID_HEADER_NAME\n })\n .map(([name, value]) => `${name}: ${value}`)\n .join('\\r\\n')\n\n // Modify the HTTP request message headers\n // to reflect any changes to the request headers\n // from the \"request\" event listener.\n const headersChunk = `${chunkBeforeRequestHeaders}${requestHeadersString}${chunkAfterRequestHeaders}`\n socket.write(headersChunk, encoding, callback)\n headersWritten = true\n continue\n }\n\n socket.write(...writeArgs)\n }\n }\n\n // Forward TLS Socket properties onto this Socket instance\n // in the case of a TLS/SSL connection.\n if (Reflect.get(socket, 'encrypted')) {\n const tlsProperties = [\n 'encrypted',\n 'authorized',\n 'getProtocol',\n 'getSession',\n 'isSessionReused',\n ]\n\n tlsProperties.forEach((propertyName) => {\n Object.defineProperty(this, propertyName, {\n enumerable: true,\n get: () => {\n const value = Reflect.get(socket, propertyName)\n return typeof value === 'function' ? value.bind(socket) : value\n },\n })\n })\n }\n\n socket\n .on('lookup', (...args) => this.emit('lookup', ...args))\n .on('connect', () => {\n this.connecting = socket.connecting\n this.emit('connect')\n })\n .on('secureConnect', () => this.emit('secureConnect'))\n .on('secure', () => this.emit('secure'))\n .on('session', (session) => this.emit('session', session))\n .on('ready', () => this.emit('ready'))\n .on('drain', () => this.emit('drain'))\n .on('data', (chunk) => {\n // Push the original response to this socket\n // so it triggers the HTTP response parser. This unifies\n // the handling pipeline for original and mocked response.\n this.push(chunk)\n })\n .on('error', (error) => {\n Reflect.set(this, '_hadError', Reflect.get(socket, '_hadError'))\n this.emit('error', error)\n })\n .on('resume', () => this.emit('resume'))\n .on('timeout', () => this.emit('timeout'))\n .on('prefinish', () => this.emit('prefinish'))\n .on('finish', () => this.emit('finish'))\n .on('close', (hadError) => this.emit('close', hadError))\n .on('end', () => this.emit('end'))\n }\n\n /**\n * Convert the given Fetch API `Response` instance to an\n * HTTP message and push it to the socket.\n */\n public async respondWith(response: Response): Promise {\n // Ignore the mocked response if the socket has been destroyed\n // (e.g. aborted or timed out),\n if (this.destroyed) {\n return\n }\n\n // Handle \"type: error\" responses.\n if (isPropertyAccessible(response, 'type') && response.type === 'error') {\n this.errorWith(new TypeError('Network error'))\n return\n }\n\n // First, emit all the connection events\n // to emulate a successful connection.\n this.mockConnect()\n this.socketState = 'mock'\n\n // Flush the write buffer to trigger write callbacks\n // if it hasn't been flushed already (e.g. someone started reading request stream).\n this.flushWriteBuffer()\n\n // Create a `ServerResponse` instance to delegate HTTP message parsing,\n // Transfer-Encoding, and other things to Node.js internals.\n const serverResponse = new ServerResponse(new IncomingMessage(this))\n\n /**\n * Assign a mock socket instance to the server response to\n * spy on the response chunk writes. Push the transformed response chunks\n * to this `MockHttpSocket` instance to trigger the \"data\" event.\n * @note Providing the same `MockSocket` instance when creating `ServerResponse`\n * does not have the same effect.\n * @see https://github.com/nodejs/node/blob/10099bb3f7fd97bb9dd9667188426866b3098e07/test/parallel/test-http-server-response-standalone.js#L32\n */\n serverResponse.assignSocket(\n new MockSocket({\n write: (chunk, encoding, callback) => {\n this.push(chunk, encoding)\n callback?.()\n },\n read() {},\n })\n )\n\n /**\n * @note Remove the `Connection` and `Date` response headers\n * injected by `ServerResponse` by default. Those are required\n * from the server but the interceptor is NOT technically a server.\n * It's confusing to add response headers that the developer didn't\n * specify themselves. They can always add these if they wish.\n * @see https://www.rfc-editor.org/rfc/rfc9110#field.date\n * @see https://www.rfc-editor.org/rfc/rfc9110#field.connection\n */\n serverResponse.removeHeader('connection')\n serverResponse.removeHeader('date')\n\n const rawResponseHeaders = getRawFetchHeaders(response.headers)\n\n /**\n * @note Call `.writeHead` in order to set the raw response headers\n * in the same case as they were provided by the developer. Using\n * `.setHeader()`/`.appendHeader()` normalizes header names.\n */\n serverResponse.writeHead(\n response.status,\n response.statusText || STATUS_CODES[response.status],\n rawResponseHeaders\n )\n\n // If the developer destroy the socket, gracefully destroy the response.\n this.once('error', () => {\n serverResponse.destroy()\n })\n\n if (response.body) {\n try {\n const reader = response.body.getReader()\n\n while (true) {\n const { done, value } = await reader.read()\n\n if (done) {\n serverResponse.end()\n break\n }\n\n serverResponse.write(value)\n }\n } catch (error) {\n // Coerce response stream errors to 500 responses.\n this.respondWith(createServerErrorResponse(error))\n return\n }\n } else {\n serverResponse.end()\n }\n\n // Close the socket if the connection wasn't marked as keep-alive.\n if (!this.shouldKeepAlive) {\n this.emit('readable')\n\n /**\n * @todo @fixme This is likely a hack.\n * Since we push null to the socket, it never propagates to the\n * parser, and the parser never calls \"onResponseEnd\" to close\n * the response stream. We are closing the stream here manually\n * but that shouldn't be the case.\n */\n this.responseStream?.push(null)\n this.push(null)\n }\n }\n\n /**\n * Close this socket connection with the given error.\n */\n public errorWith(error?: Error): void {\n this.destroy(error)\n }\n\n private mockConnect(): void {\n // Calling this method immediately puts the socket\n // into the connected state.\n this.connecting = false\n\n const isIPv6 =\n net.isIPv6(this.connectionOptions.hostname) ||\n this.connectionOptions.family === 6\n const addressInfo = {\n address: isIPv6 ? '::1' : '127.0.0.1',\n family: isIPv6 ? 'IPv6' : 'IPv4',\n port: this.connectionOptions.port,\n }\n // Return fake address information for the socket.\n this.address = () => addressInfo\n this.emit(\n 'lookup',\n null,\n addressInfo.address,\n addressInfo.family === 'IPv6' ? 6 : 4,\n this.connectionOptions.host\n )\n this.emit('connect')\n this.emit('ready')\n\n if (this.baseUrl.protocol === 'https:') {\n this.emit('secure')\n this.emit('secureConnect')\n\n // A single TLS connection is represented by two \"session\" events.\n this.emit(\n 'session',\n this.connectionOptions.session ||\n Buffer.from('mock-session-renegotiate')\n )\n this.emit('session', Buffer.from('mock-session-resume'))\n }\n }\n\n private flushWriteBuffer(): void {\n for (const writeCall of this.writeBuffer) {\n if (typeof writeCall[2] === 'function') {\n writeCall[2]()\n /**\n * @note Remove the callback from the write call\n * so it doesn't get called twice on passthrough\n * if `request.end()` was called within `request.write()`.\n * @see https://github.com/mswjs/interceptors/issues/684\n */\n writeCall[2] = undefined\n }\n }\n }\n\n private onRequestStart: RequestHeadersCompleteCallback = (\n versionMajor,\n versionMinor,\n rawHeaders,\n _,\n path,\n __,\n ___,\n ____,\n shouldKeepAlive\n ) => {\n this.shouldKeepAlive = shouldKeepAlive\n\n const url = new URL(path, this.baseUrl)\n const method = this.connectionOptions.method?.toUpperCase() || 'GET'\n const headers = FetchResponse.parseRawHeaders(rawHeaders)\n const canHaveBody = method !== 'GET' && method !== 'HEAD'\n\n // Translate the basic authorization in the URL to the request header.\n // Constructing a Request instance with a URL containing auth is no-op.\n if (url.username || url.password) {\n if (!headers.has('authorization')) {\n headers.set('authorization', `Basic ${url.username}:${url.password}`)\n }\n url.username = ''\n url.password = ''\n }\n\n // Create a new stream for each request.\n // If this Socket is reused for multiple requests,\n // this ensures that each request gets its own stream.\n // One Socket instance can only handle one request at a time.\n if (canHaveBody) {\n this.requestStream = new Readable({\n /**\n * @note Provide the `read()` method so a `Readable` could be\n * used as the actual request body (the stream calls \"read()\").\n * We control the queue in the onRequestBody/End functions.\n */\n read: () => {\n // If the user attempts to read the request body,\n // flush the write buffer to trigger the callbacks.\n // This way, if the request stream ends in the write callback,\n // it will indeed end correctly.\n this.flushWriteBuffer()\n },\n })\n }\n\n const requestId = createRequestId()\n this.request = new Request(url, {\n method,\n headers,\n credentials: 'same-origin',\n // @ts-expect-error Undocumented Fetch property.\n duplex: canHaveBody ? 'half' : undefined,\n body: canHaveBody ? (Readable.toWeb(this.requestStream!) as any) : null,\n })\n\n Reflect.set(this.request, kRequestId, requestId)\n\n // Skip handling the request that's already being handled\n // by another (parent) interceptor. For example, XMLHttpRequest\n // is often implemented via ClientRequest in Node.js (e.g. JSDOM).\n // In that case, XHR interceptor will bubble down to the ClientRequest\n // interceptor. No need to try to handle that request again.\n /**\n * @fixme Stop relying on the \"X-Request-Id\" request header\n * to figure out if one interceptor has been invoked within another.\n * @see https://github.com/mswjs/interceptors/issues/378\n */\n if (this.request.headers.has(INTERNAL_REQUEST_ID_HEADER_NAME)) {\n this.passthrough()\n return\n }\n\n this.onRequest({\n requestId,\n request: this.request,\n socket: this,\n })\n }\n\n private onRequestBody(chunk: Buffer): void {\n invariant(\n this.requestStream,\n 'Failed to write to a request stream: stream does not exist'\n )\n\n this.requestStream.push(chunk)\n }\n\n private onRequestEnd(): void {\n // Request end can be called for requests without body.\n if (this.requestStream) {\n this.requestStream.push(null)\n }\n }\n\n private onResponseStart: ResponseHeadersCompleteCallback = (\n versionMajor,\n versionMinor,\n rawHeaders,\n method,\n url,\n status,\n statusText\n ) => {\n const headers = FetchResponse.parseRawHeaders(rawHeaders)\n\n const response = new FetchResponse(\n /**\n * @note The Fetch API response instance exposed to the consumer\n * is created over the response stream of the HTTP parser. It is NOT\n * related to the Socket instance. This way, you can read response body\n * in response listener while the Socket instance delays the emission\n * of \"end\" and other events until those response listeners are finished.\n */\n FetchResponse.isResponseWithBody(status)\n ? (Readable.toWeb(\n (this.responseStream = new Readable({ read() {} }))\n ) as any)\n : null,\n {\n url,\n status,\n statusText,\n headers,\n }\n )\n\n invariant(\n this.request,\n 'Failed to handle a response: request does not exist'\n )\n\n /**\n * @fixme Stop relying on the \"X-Request-Id\" request header\n * to figure out if one interceptor has been invoked within another.\n * @see https://github.com/mswjs/interceptors/issues/378\n */\n if (this.request.headers.has(INTERNAL_REQUEST_ID_HEADER_NAME)) {\n return\n }\n\n this.responseListenersPromise = this.onResponse({\n response,\n isMockedResponse: this.socketState === 'mock',\n requestId: Reflect.get(this.request, kRequestId),\n request: this.request,\n socket: this,\n })\n }\n\n private onResponseBody(chunk: Buffer) {\n invariant(\n this.responseStream,\n 'Failed to write to a response stream: stream does not exist'\n )\n\n this.responseStream.push(chunk)\n }\n\n private onResponseEnd(): void {\n // Response end can be called for responses without body.\n if (this.responseStream) {\n this.responseStream.push(null)\n }\n }\n}\n","import net from 'node:net'\nimport {\n normalizeSocketWriteArgs,\n type WriteArgs,\n type WriteCallback,\n} from './utils/normalizeSocketWriteArgs'\n\nexport interface MockSocketOptions {\n write: (\n chunk: Buffer | string,\n encoding: BufferEncoding | undefined,\n callback?: WriteCallback\n ) => void\n\n read: (chunk: Buffer, encoding: BufferEncoding | undefined) => void\n}\n\nexport class MockSocket extends net.Socket {\n public connecting: boolean\n\n constructor(protected readonly options: MockSocketOptions) {\n super()\n this.connecting = false\n this.connect()\n\n this._final = (callback) => {\n callback(null)\n }\n }\n\n public connect() {\n // The connection will remain pending until\n // the consumer decides to handle it.\n this.connecting = true\n return this\n }\n\n public write(...args: Array): boolean {\n const [chunk, encoding, callback] = normalizeSocketWriteArgs(\n args as WriteArgs\n )\n this.options.write(chunk, encoding, callback)\n return true\n }\n\n public end(...args: Array) {\n const [chunk, encoding, callback] = normalizeSocketWriteArgs(\n args as WriteArgs\n )\n this.options.write(chunk, encoding, callback)\n return super.end.apply(this, args as any)\n }\n\n public push(chunk: any, encoding?: BufferEncoding): boolean {\n this.options.read(chunk, encoding)\n return super.push(chunk, encoding)\n }\n}\n","export type WriteCallback = (error?: Error | null) => void\n\nexport type WriteArgs =\n | [chunk: unknown, callback?: WriteCallback]\n | [chunk: unknown, encoding: BufferEncoding, callback?: WriteCallback]\n\nexport type NormalizedSocketWriteArgs = [\n chunk: any,\n encoding?: BufferEncoding,\n callback?: WriteCallback,\n]\n\n/**\n * Normalizes the arguments provided to the `Writable.prototype.write()`\n * and `Writable.prototype.end()`.\n */\nexport function normalizeSocketWriteArgs(\n args: WriteArgs\n): NormalizedSocketWriteArgs {\n const normalized: NormalizedSocketWriteArgs = [args[0], undefined, undefined]\n\n if (typeof args[1] === 'string') {\n normalized[1] = args[1]\n } else if (typeof args[1] === 'function') {\n normalized[2] = args[1]\n }\n\n if (typeof args[2] === 'function') {\n normalized[2] = args[2]\n }\n\n return normalized\n}\n","export function baseUrlFromConnectionOptions(options: any): URL {\n if ('href' in options) {\n return new URL(options.href)\n }\n\n const protocol = options.port === 443 ? 'https:' : 'http:'\n const host = options.host\n\n const url = new URL(`${protocol}//${host}`)\n\n if (options.port) {\n url.port = options.port.toString()\n }\n\n if (options.path) {\n url.pathname = options.path\n }\n\n if (options.auth) {\n const [username, password] = options.auth.split(':')\n url.username = username\n url.password = password\n }\n\n return url\n}\n","type HeaderTuple = [string, string]\ntype RawHeaders = Array\ntype SetHeaderBehavior = 'set' | 'append'\n\nconst kRawHeaders = Symbol('kRawHeaders')\nconst kRestorePatches = Symbol('kRestorePatches')\n\nfunction recordRawHeader(\n headers: Headers,\n args: HeaderTuple,\n behavior: SetHeaderBehavior\n) {\n ensureRawHeadersSymbol(headers, [])\n const rawHeaders = Reflect.get(headers, kRawHeaders) as RawHeaders\n\n if (behavior === 'set') {\n // When recording a set header, ensure we remove any matching existing headers.\n for (let index = rawHeaders.length - 1; index >= 0; index--) {\n if (rawHeaders[index][0].toLowerCase() === args[0].toLowerCase()) {\n rawHeaders.splice(index, 1)\n }\n }\n }\n\n rawHeaders.push(args)\n}\n\n/**\n * Define the raw headers symbol on the given `Headers` instance.\n * If the symbol already exists, this function does nothing.\n */\nfunction ensureRawHeadersSymbol(\n headers: Headers,\n rawHeaders: RawHeaders\n): void {\n if (Reflect.has(headers, kRawHeaders)) {\n return\n }\n\n defineRawHeadersSymbol(headers, rawHeaders)\n}\n\n/**\n * Define the raw headers symbol on the given `Headers` instance.\n * If the symbol already exists, it gets overridden.\n */\nfunction defineRawHeadersSymbol(headers: Headers, rawHeaders: RawHeaders) {\n Object.defineProperty(headers, kRawHeaders, {\n value: rawHeaders,\n enumerable: false,\n // Mark the symbol as configurable so its value can be overridden.\n // Overrides happen when merging raw headers from multiple sources.\n // E.g. new Request(new Request(url, { headers }), { headers })\n configurable: true,\n })\n}\n\n/**\n * Patch the global `Headers` class to store raw headers.\n * This is for compatibility with `IncomingMessage.prototype.rawHeaders`.\n *\n * @note Node.js has their own raw headers symbol but it\n * only records the first header name in case of multi-value headers.\n * Any other headers are normalized before comparing. This makes it\n * incompatible with the `rawHeaders` format.\n *\n * let h = new Headers()\n * h.append('X-Custom', 'one')\n * h.append('x-custom', 'two')\n * h[Symbol('headers map')] // Map { 'X-Custom' => 'one, two' }\n */\nexport function recordRawFetchHeaders() {\n // Prevent patching the Headers prototype multiple times.\n if (Reflect.get(Headers, kRestorePatches)) {\n return Reflect.get(Headers, kRestorePatches)\n }\n\n const {\n Headers: OriginalHeaders,\n Request: OriginalRequest,\n Response: OriginalResponse,\n } = globalThis\n const { set, append, delete: headersDeleteMethod } = Headers.prototype\n\n Object.defineProperty(Headers, kRestorePatches, {\n value: () => {\n Headers.prototype.set = set\n Headers.prototype.append = append\n Headers.prototype.delete = headersDeleteMethod\n globalThis.Headers = OriginalHeaders\n\n globalThis.Request = OriginalRequest\n globalThis.Response = OriginalResponse\n\n Reflect.deleteProperty(Headers, kRestorePatches)\n },\n enumerable: false,\n /**\n * @note Mark this property as configurable\n * so we can delete it using `Reflect.delete` during cleanup.\n */\n configurable: true,\n })\n\n Object.defineProperty(globalThis, 'Headers', {\n enumerable: true,\n writable: true,\n value: new Proxy(Headers, {\n construct(target, args, newTarget) {\n const headersInit = args[0] || []\n\n if (\n headersInit instanceof Headers &&\n Reflect.has(headersInit, kRawHeaders)\n ) {\n const headers = Reflect.construct(\n target,\n [Reflect.get(headersInit, kRawHeaders)],\n newTarget\n )\n ensureRawHeadersSymbol(headers, [\n /**\n * @note Spread the retrieved headers to clone them.\n * This prevents multiple Headers instances from pointing\n * at the same internal \"rawHeaders\" array.\n */\n ...Reflect.get(headersInit, kRawHeaders),\n ])\n return headers\n }\n\n const headers = Reflect.construct(target, args, newTarget)\n\n // Request/Response constructors will set the symbol\n // upon creating a new instance, using the raw developer\n // input as the raw headers. Skip the symbol altogether\n // in those cases because the input to Headers will be normalized.\n if (!Reflect.has(headers, kRawHeaders)) {\n const rawHeadersInit = Array.isArray(headersInit)\n ? headersInit\n : Object.entries(headersInit)\n ensureRawHeadersSymbol(headers, rawHeadersInit)\n }\n\n return headers\n },\n }),\n })\n\n Headers.prototype.set = new Proxy(Headers.prototype.set, {\n apply(target, thisArg, args: HeaderTuple) {\n recordRawHeader(thisArg, args, 'set')\n return Reflect.apply(target, thisArg, args)\n },\n })\n\n Headers.prototype.append = new Proxy(Headers.prototype.append, {\n apply(target, thisArg, args: HeaderTuple) {\n recordRawHeader(thisArg, args, 'append')\n return Reflect.apply(target, thisArg, args)\n },\n })\n\n Headers.prototype.delete = new Proxy(Headers.prototype.delete, {\n apply(target, thisArg, args: [string]) {\n const rawHeaders = Reflect.get(thisArg, kRawHeaders) as RawHeaders\n\n if (rawHeaders) {\n for (let index = rawHeaders.length - 1; index >= 0; index--) {\n if (rawHeaders[index][0].toLowerCase() === args[0].toLowerCase()) {\n rawHeaders.splice(index, 1)\n }\n }\n }\n\n return Reflect.apply(target, thisArg, args)\n },\n })\n\n Object.defineProperty(globalThis, 'Request', {\n enumerable: true,\n writable: true,\n value: new Proxy(Request, {\n construct(target, args, newTarget) {\n const request = Reflect.construct(target, args, newTarget)\n const inferredRawHeaders: RawHeaders = []\n\n // Infer raw headers from a `Request` instance used as init.\n if (typeof args[0] === 'object' && args[0].headers != null) {\n inferredRawHeaders.push(...inferRawHeaders(args[0].headers))\n }\n\n // Infer raw headers from the \"headers\" init argument.\n if (typeof args[1] === 'object' && args[1].headers != null) {\n inferredRawHeaders.push(...inferRawHeaders(args[1].headers))\n }\n\n if (inferredRawHeaders.length > 0) {\n ensureRawHeadersSymbol(request.headers, inferredRawHeaders)\n }\n\n return request\n },\n }),\n })\n\n Object.defineProperty(globalThis, 'Response', {\n enumerable: true,\n writable: true,\n value: new Proxy(Response, {\n construct(target, args, newTarget) {\n const response = Reflect.construct(target, args, newTarget)\n\n if (typeof args[1] === 'object' && args[1].headers != null) {\n ensureRawHeadersSymbol(\n response.headers,\n inferRawHeaders(args[1].headers)\n )\n }\n\n return response\n },\n }),\n })\n}\n\nexport function restoreHeadersPrototype() {\n if (!Reflect.get(Headers, kRestorePatches)) {\n return\n }\n\n Reflect.get(Headers, kRestorePatches)()\n}\n\nexport function getRawFetchHeaders(headers: Headers): RawHeaders {\n // If the raw headers recording failed for some reason,\n // use the normalized header entries instead.\n if (!Reflect.has(headers, kRawHeaders)) {\n return Array.from(headers.entries())\n }\n\n const rawHeaders = Reflect.get(headers, kRawHeaders) as RawHeaders\n return rawHeaders.length > 0 ? rawHeaders : Array.from(headers.entries())\n}\n\n/**\n * Infers the raw headers from the given `HeadersInit` provided\n * to the Request/Response constructor.\n *\n * If the `init.headers` is a Headers instance, use it directly.\n * That means the headers were created standalone and already have\n * the raw headers stored.\n * If the `init.headers` is a HeadersInit, create a new Headers\n * instace out of it.\n */\nfunction inferRawHeaders(headers: HeadersInit): RawHeaders {\n if (headers instanceof Headers) {\n return Reflect.get(headers, kRawHeaders) || []\n }\n\n return Reflect.get(new Headers(headers), kRawHeaders)\n}\n","import net from 'node:net'\nimport http from 'node:http'\nimport https from 'node:https'\nimport {\n MockHttpSocket,\n type MockHttpSocketRequestCallback,\n type MockHttpSocketResponseCallback,\n} from './MockHttpSocket'\n\ndeclare module 'node:http' {\n interface Agent {\n options?: http.AgentOptions\n createConnection(options: any, callback: any): net.Socket\n }\n}\n\ninterface MockAgentOptions {\n customAgent?: http.RequestOptions['agent']\n onRequest: MockHttpSocketRequestCallback\n onResponse: MockHttpSocketResponseCallback\n}\n\nexport class MockAgent extends http.Agent {\n private customAgent?: http.RequestOptions['agent']\n private onRequest: MockHttpSocketRequestCallback\n private onResponse: MockHttpSocketResponseCallback\n\n constructor(options: MockAgentOptions) {\n super()\n this.customAgent = options.customAgent\n this.onRequest = options.onRequest\n this.onResponse = options.onResponse\n }\n\n public createConnection(options: any, callback: any): net.Socket {\n const createConnection =\n this.customAgent instanceof http.Agent\n ? this.customAgent.createConnection\n : super.createConnection\n\n const createConnectionOptions =\n this.customAgent instanceof http.Agent\n ? {\n ...options,\n ...this.customAgent.options,\n }\n : options\n\n const socket = new MockHttpSocket({\n connectionOptions: options,\n createConnection: createConnection.bind(\n this.customAgent || this,\n createConnectionOptions,\n callback\n ),\n onRequest: this.onRequest.bind(this),\n onResponse: this.onResponse.bind(this),\n })\n\n return socket\n }\n}\n\nexport class MockHttpsAgent extends https.Agent {\n private customAgent?: https.RequestOptions['agent']\n private onRequest: MockHttpSocketRequestCallback\n private onResponse: MockHttpSocketResponseCallback\n\n constructor(options: MockAgentOptions) {\n super()\n this.customAgent = options.customAgent\n this.onRequest = options.onRequest\n this.onResponse = options.onResponse\n }\n\n public createConnection(options: any, callback: any): net.Socket {\n const createConnection =\n this.customAgent instanceof https.Agent\n ? this.customAgent.createConnection\n : super.createConnection\n\n const createConnectionOptions =\n this.customAgent instanceof https.Agent\n ? {\n ...options,\n ...this.customAgent.options,\n }\n : options\n\n const socket = new MockHttpSocket({\n connectionOptions: options,\n createConnection: createConnection.bind(\n this.customAgent || this,\n createConnectionOptions,\n callback\n ),\n onRequest: this.onRequest.bind(this),\n onResponse: this.onResponse.bind(this),\n })\n\n return socket\n }\n}\n","import { urlToHttpOptions } from 'node:url'\nimport {\n Agent as HttpAgent,\n globalAgent as httpGlobalAgent,\n IncomingMessage,\n} from 'node:http'\nimport {\n RequestOptions,\n Agent as HttpsAgent,\n globalAgent as httpsGlobalAgent,\n} from 'node:https'\nimport {\n /**\n * @note Use the Node.js URL instead of the global URL\n * because environments like JSDOM may override the global,\n * breaking the compatibility with Node.js.\n * @see https://github.com/node-fetch/node-fetch/issues/1376#issuecomment-966435555\n */\n URL,\n Url as LegacyURL,\n parse as parseUrl,\n} from 'node:url'\nimport { Logger } from '@open-draft/logger'\nimport {\n ResolvedRequestOptions,\n getUrlByRequestOptions,\n} from '../../../utils/getUrlByRequestOptions'\nimport { cloneObject } from '../../../utils/cloneObject'\nimport { isObject } from '../../../utils/isObject'\n\nconst logger = new Logger('http normalizeClientRequestArgs')\n\nexport type HttpRequestCallback = (response: IncomingMessage) => void\n\nexport type ClientRequestArgs =\n // Request without any arguments is also possible.\n | []\n | [string | URL | LegacyURL, HttpRequestCallback?]\n | [string | URL | LegacyURL, RequestOptions, HttpRequestCallback?]\n | [RequestOptions, HttpRequestCallback?]\n\nfunction resolveRequestOptions(\n args: ClientRequestArgs,\n url: URL\n): RequestOptions {\n // Calling `fetch` provides only URL to `ClientRequest`\n // without any `RequestOptions` or callback.\n if (typeof args[1] === 'undefined' || typeof args[1] === 'function') {\n logger.info('request options not provided, deriving from the url', url)\n return urlToHttpOptions(url)\n }\n\n if (args[1]) {\n logger.info('has custom RequestOptions!', args[1])\n const requestOptionsFromUrl = urlToHttpOptions(url)\n\n logger.info('derived RequestOptions from the URL:', requestOptionsFromUrl)\n\n /**\n * Clone the request options to lock their state\n * at the moment they are provided to `ClientRequest`.\n * @see https://github.com/mswjs/interceptors/issues/86\n */\n logger.info('cloning RequestOptions...')\n const clonedRequestOptions = cloneObject(args[1])\n logger.info('successfully cloned RequestOptions!', clonedRequestOptions)\n\n return {\n ...requestOptionsFromUrl,\n ...clonedRequestOptions,\n }\n }\n\n logger.info('using an empty object as request options')\n return {} as RequestOptions\n}\n\n/**\n * Overrides the given `URL` instance with the explicit properties provided\n * on the `RequestOptions` object. The options object takes precedence,\n * and will replace URL properties like \"host\", \"path\", and \"port\", if specified.\n */\nfunction overrideUrlByRequestOptions(url: URL, options: RequestOptions): URL {\n url.host = options.host || url.host\n url.hostname = options.hostname || url.hostname\n url.port = options.port ? options.port.toString() : url.port\n\n if (options.path) {\n const parsedOptionsPath = parseUrl(options.path, false)\n url.pathname = parsedOptionsPath.pathname || ''\n url.search = parsedOptionsPath.search || ''\n }\n\n return url\n}\n\nfunction resolveCallback(\n args: ClientRequestArgs\n): HttpRequestCallback | undefined {\n return typeof args[1] === 'function' ? args[1] : args[2]\n}\n\nexport type NormalizedClientRequestArgs = [\n url: URL,\n options: ResolvedRequestOptions,\n callback?: HttpRequestCallback\n]\n\n/**\n * Normalizes parameters given to a `http.request` call\n * so it always has a `URL` and `RequestOptions`.\n */\nexport function normalizeClientRequestArgs(\n defaultProtocol: string,\n args: ClientRequestArgs\n): NormalizedClientRequestArgs {\n let url: URL\n let options: ResolvedRequestOptions\n let callback: HttpRequestCallback | undefined\n\n logger.info('arguments', args)\n logger.info('using default protocol:', defaultProtocol)\n\n // Support \"http.request()\" calls without any arguments.\n // That call results in a \"GET http://localhost\" request.\n if (args.length === 0) {\n const url = new URL('http://localhost')\n const options = resolveRequestOptions(args, url)\n return [url, options]\n }\n\n // Convert a url string into a URL instance\n // and derive request options from it.\n if (typeof args[0] === 'string') {\n logger.info('first argument is a location string:', args[0])\n\n url = new URL(args[0])\n logger.info('created a url:', url)\n\n const requestOptionsFromUrl = urlToHttpOptions(url)\n logger.info('request options from url:', requestOptionsFromUrl)\n\n options = resolveRequestOptions(args, url)\n logger.info('resolved request options:', options)\n\n callback = resolveCallback(args)\n }\n // Handle a given URL instance as-is\n // and derive request options from it.\n else if (args[0] instanceof URL) {\n url = args[0]\n logger.info('first argument is a URL:', url)\n\n // Check if the second provided argument is RequestOptions.\n // If it is, check if \"options.path\" was set and rewrite it\n // on the input URL.\n // Do this before resolving options from the URL below\n // to prevent query string from being duplicated in the path.\n if (typeof args[1] !== 'undefined' && isObject(args[1])) {\n url = overrideUrlByRequestOptions(url, args[1])\n }\n\n options = resolveRequestOptions(args, url)\n logger.info('derived request options:', options)\n\n callback = resolveCallback(args)\n }\n // Handle a legacy URL instance and re-normalize from either a RequestOptions object\n // or a WHATWG URL.\n else if ('hash' in args[0] && !('method' in args[0])) {\n const [legacyUrl] = args\n logger.info('first argument is a legacy URL:', legacyUrl)\n\n if (legacyUrl.hostname === null) {\n /**\n * We are dealing with a relative url, so use the path as an \"option\" and\n * merge in any existing options, giving priority to exising options -- i.e. a path in any\n * existing options will take precedence over the one contained in the url. This is consistent\n * with the behaviour in ClientRequest.\n * @see https://github.com/nodejs/node/blob/d84f1312915fe45fe0febe888db692c74894c382/lib/_http_client.js#L122\n */\n logger.info('given legacy URL is relative (no hostname)')\n\n return isObject(args[1])\n ? normalizeClientRequestArgs(defaultProtocol, [\n { path: legacyUrl.path, ...args[1] },\n args[2],\n ])\n : normalizeClientRequestArgs(defaultProtocol, [\n { path: legacyUrl.path },\n args[1] as HttpRequestCallback,\n ])\n }\n\n logger.info('given legacy url is absolute')\n\n // We are dealing with an absolute URL, so convert to WHATWG and try again.\n const resolvedUrl = new URL(legacyUrl.href)\n\n return args[1] === undefined\n ? normalizeClientRequestArgs(defaultProtocol, [resolvedUrl])\n : typeof args[1] === 'function'\n ? normalizeClientRequestArgs(defaultProtocol, [resolvedUrl, args[1]])\n : normalizeClientRequestArgs(defaultProtocol, [\n resolvedUrl,\n args[1],\n args[2],\n ])\n }\n // Handle a given \"RequestOptions\" object as-is\n // and derive the URL instance from it.\n else if (isObject(args[0])) {\n options = { ...(args[0] as any) }\n logger.info('first argument is RequestOptions:', options)\n\n // When handling a \"RequestOptions\" object without an explicit \"protocol\",\n // infer the protocol from the request issuing module (http/https).\n options.protocol = options.protocol || defaultProtocol\n logger.info('normalized request options:', options)\n\n url = getUrlByRequestOptions(options)\n logger.info('created a URL from RequestOptions:', url.href)\n\n callback = resolveCallback(args)\n } else {\n throw new Error(\n `Failed to construct ClientRequest with these parameters: ${args}`\n )\n }\n\n options.protocol = options.protocol || url.protocol\n options.method = options.method || 'GET'\n\n /**\n * Infer a fallback agent from the URL protocol.\n * The interception is done on the \"ClientRequest\" level (\"NodeClientRequest\")\n * and it may miss the correct agent. Always align the agent\n * with the URL protocol, if not provided.\n *\n * @note Respect the \"agent: false\" value.\n */\n if (typeof options.agent === 'undefined') {\n const agent =\n options.protocol === 'https:'\n ? new HttpsAgent({\n // Any other value other than false is considered as true, so we don't add this property if undefined.\n ...('rejectUnauthorized' in options && {\n rejectUnauthorized: options.rejectUnauthorized,\n }),\n })\n : new HttpAgent()\n\n options.agent = agent\n logger.info('resolved fallback agent:', agent)\n }\n\n /**\n * Ensure that the default Agent is always set.\n * This prevents the protocol mismatch for requests with { agent: false },\n * where the global Agent is inferred.\n * @see https://github.com/mswjs/msw/issues/1150\n * @see https://github.com/nodejs/node/blob/418ff70b810f0e7112d48baaa72932a56cfa213b/lib/_http_client.js#L130\n * @see https://github.com/nodejs/node/blob/418ff70b810f0e7112d48baaa72932a56cfa213b/lib/_http_client.js#L157-L159\n */\n if (!options._defaultAgent) {\n logger.info(\n 'has no default agent, setting the default agent for \"%s\"',\n options.protocol\n )\n\n options._defaultAgent =\n options.protocol === 'https:' ? httpsGlobalAgent : httpGlobalAgent\n }\n\n logger.info('successfully resolved url:', url.href)\n logger.info('successfully resolved options:', options)\n logger.info('successfully resolved callback:', callback)\n\n /**\n * @note If the user-provided URL is not a valid URL in Node.js,\n * (e.g. the one provided by the JSDOM polyfills), case it to\n * string. Otherwise, this throws on Node.js incompatibility\n * (`ERR_INVALID_ARG_TYPE` on the connection listener)\n * @see https://github.com/node-fetch/node-fetch/issues/1376#issuecomment-966435555\n */\n if (!(url instanceof URL)) {\n url = (url as any).toString()\n }\n\n return [url, options, callback]\n}\n","import { Agent } from 'http'\nimport { RequestOptions, Agent as HttpsAgent } from 'https'\nimport { Logger } from '@open-draft/logger'\n\nconst logger = new Logger('utils getUrlByRequestOptions')\n\n// Request instance constructed by the \"request\" library\n// has a \"self\" property that has a \"uri\" field. This is\n// reproducible by performing a \"XMLHttpRequest\" request in JSDOM.\nexport interface RequestSelf {\n uri?: URL\n}\n\nexport type ResolvedRequestOptions = RequestOptions & RequestSelf\n\nexport const DEFAULT_PATH = '/'\nconst DEFAULT_PROTOCOL = 'http:'\nconst DEFAULT_HOSTNAME = 'localhost'\nconst SSL_PORT = 443\n\nfunction getAgent(\n options: ResolvedRequestOptions\n): Agent | HttpsAgent | undefined {\n return options.agent instanceof Agent ? options.agent : undefined\n}\n\nfunction getProtocolByRequestOptions(options: ResolvedRequestOptions): string {\n if (options.protocol) {\n return options.protocol\n }\n\n const agent = getAgent(options)\n const agentProtocol = (agent as RequestOptions)?.protocol\n\n if (agentProtocol) {\n return agentProtocol\n }\n\n const port = getPortByRequestOptions(options)\n const isSecureRequest = options.cert || port === SSL_PORT\n\n return isSecureRequest ? 'https:' : options.uri?.protocol || DEFAULT_PROTOCOL\n}\n\nfunction getPortByRequestOptions(\n options: ResolvedRequestOptions\n): number | undefined {\n // Use the explicitly provided port.\n if (options.port) {\n return Number(options.port)\n }\n\n // Otherwise, try to resolve port from the agent.\n const agent = getAgent(options)\n\n if ((agent as HttpsAgent)?.options.port) {\n return Number((agent as HttpsAgent).options.port)\n }\n\n if ((agent as RequestOptions)?.defaultPort) {\n return Number((agent as RequestOptions).defaultPort)\n }\n\n // Lastly, return undefined indicating that the port\n // must inferred from the protocol. Do not infer it here.\n return undefined\n}\n\ninterface RequestAuth {\n username: string\n password: string\n}\n\nfunction getAuthByRequestOptions(\n options: ResolvedRequestOptions\n): RequestAuth | undefined {\n if (options.auth) {\n const [username, password] = options.auth.split(':')\n return { username, password }\n }\n}\n\n/**\n * Returns true if host looks like an IPv6 address without surrounding brackets\n * It assumes any host containing `:` is definitely not IPv4 and probably IPv6,\n * but note that this could include invalid IPv6 addresses as well.\n */\nfunction isRawIPv6Address(host: string): boolean {\n return host.includes(':') && !host.startsWith('[') && !host.endsWith(']')\n}\n\nfunction getHostname(options: ResolvedRequestOptions): string | undefined {\n let host = options.hostname || options.host\n\n if (host) {\n if (isRawIPv6Address(host)) {\n host = `[${host}]`\n }\n\n // Check the presence of the port, and if it's present,\n // remove it from the host, returning a hostname.\n return new URL(`http://${host}`).hostname\n }\n\n return DEFAULT_HOSTNAME\n}\n\n/**\n * Creates a `URL` instance from a given `RequestOptions` object.\n */\nexport function getUrlByRequestOptions(options: ResolvedRequestOptions): URL {\n logger.info('request options', options)\n\n if (options.uri) {\n logger.info(\n 'constructing url from explicitly provided \"options.uri\": %s',\n options.uri\n )\n return new URL(options.uri.href)\n }\n\n logger.info('figuring out url from request options...')\n\n const protocol = getProtocolByRequestOptions(options)\n logger.info('protocol', protocol)\n\n const port = getPortByRequestOptions(options)\n logger.info('port', port)\n\n const hostname = getHostname(options)\n logger.info('hostname', hostname)\n\n const path = options.path || DEFAULT_PATH\n logger.info('path', path)\n\n const credentials = getAuthByRequestOptions(options)\n logger.info('credentials', credentials)\n\n const authString = credentials\n ? `${credentials.username}:${credentials.password}@`\n : ''\n logger.info('auth string:', authString)\n\n const portString = typeof port !== 'undefined' ? `:${port}` : ''\n const url = new URL(`${protocol}//${hostname}${portString}${path}`)\n url.username = credentials?.username || ''\n url.password = credentials?.password || ''\n\n logger.info('created url:', url)\n\n return url\n}\n","import { Logger } from '@open-draft/logger'\n\nconst logger = new Logger('cloneObject')\n\nfunction isPlainObject(obj?: Record): boolean {\n logger.info('is plain object?', obj)\n\n if (obj == null || !obj.constructor?.name) {\n logger.info('given object is undefined, not a plain object...')\n return false\n }\n\n logger.info('checking the object constructor:', obj.constructor.name)\n return obj.constructor.name === 'Object'\n}\n\nexport function cloneObject>(\n obj: ObjectType\n): ObjectType {\n logger.info('cloning object:', obj)\n\n const enumerableProperties = Object.entries(obj).reduce>(\n (acc, [key, value]) => {\n logger.info('analyzing key-value pair:', key, value)\n\n // Recursively clone only plain objects, omitting class instances.\n acc[key] = isPlainObject(value) ? cloneObject(value) : value\n return acc\n },\n {}\n )\n\n return isPlainObject(obj)\n ? enumerableProperties\n : Object.assign(Object.getPrototypeOf(obj), enumerableProperties)\n}\n","/**\n * Determines if a given value is an instance of object.\n */\nexport function isObject(value: any, loose = false): value is T {\n return loose\n ? Object.prototype.toString.call(value).startsWith('[object ')\n : Object.prototype.toString.call(value) === '[object Object]'\n}\n"]} \ No newline at end of file diff --git a/node_modules/@mswjs/interceptors/lib/node/chunk-5KMS5CTP.mjs b/node_modules/@mswjs/interceptors/lib/node/chunk-5KMS5CTP.mjs new file mode 100644 index 0000000000000000000000000000000000000000..12e6e12bde0e7aa369d1d839c2a9ca800955e2fa --- /dev/null +++ b/node_modules/@mswjs/interceptors/lib/node/chunk-5KMS5CTP.mjs @@ -0,0 +1,230 @@ +// src/RequestController.ts +import { invariant } from "outvariant"; +import { DeferredPromise } from "@open-draft/deferred-promise"; + +// src/InterceptorError.ts +var InterceptorError = class extends Error { + constructor(message) { + super(message); + this.name = "InterceptorError"; + Object.setPrototypeOf(this, InterceptorError.prototype); + } +}; + +// src/RequestController.ts +var kRequestHandled = Symbol("kRequestHandled"); +var kResponsePromise = Symbol("kResponsePromise"); +var RequestController = class { + constructor(request) { + this.request = request; + this[kRequestHandled] = false; + this[kResponsePromise] = new DeferredPromise(); + } + /** + * Respond to this request with the given `Response` instance. + * @example + * controller.respondWith(new Response()) + * controller.respondWith(Response.json({ id })) + * controller.respondWith(Response.error()) + */ + respondWith(response) { + invariant.as( + InterceptorError, + !this[kRequestHandled], + 'Failed to respond to the "%s %s" request: the "request" event has already been handled.', + this.request.method, + this.request.url + ); + this[kRequestHandled] = true; + this[kResponsePromise].resolve(response); + } + /** + * Error this request with the given error. + * @example + * controller.errorWith() + * controller.errorWith(new Error('Oops!')) + */ + errorWith(error) { + invariant.as( + InterceptorError, + !this[kRequestHandled], + 'Failed to error the "%s %s" request: the "request" event has already been handled.', + this.request.method, + this.request.url + ); + this[kRequestHandled] = true; + this[kResponsePromise].resolve(error); + } +}; +kResponsePromise, kRequestHandled; + +// src/utils/emitAsync.ts +async function emitAsync(emitter, eventName, ...data) { + const listners = emitter.listeners(eventName); + if (listners.length === 0) { + return; + } + for (const listener of listners) { + await listener.apply(emitter, data); + } +} + +// src/utils/handleRequest.ts +import { DeferredPromise as DeferredPromise2 } from "@open-draft/deferred-promise"; +import { until } from "@open-draft/until"; + +// src/utils/isPropertyAccessible.ts +function isPropertyAccessible(obj, key) { + try { + obj[key]; + return true; + } catch (e) { + return false; + } +} + +// src/utils/responseUtils.ts +function createServerErrorResponse(body) { + return new Response( + JSON.stringify( + body instanceof Error ? { + name: body.name, + message: body.message, + stack: body.stack + } : body + ), + { + status: 500, + statusText: "Unhandled Exception", + headers: { + "Content-Type": "application/json" + } + } + ); +} +function isResponseError(response) { + return isPropertyAccessible(response, "type") && response.type === "error"; +} + +// src/utils/isNodeLikeError.ts +function isNodeLikeError(error) { + if (error == null) { + return false; + } + if (!(error instanceof Error)) { + return false; + } + return "code" in error && "errno" in error; +} + +// src/utils/handleRequest.ts +async function handleRequest(options) { + const handleResponse = async (response) => { + if (response instanceof Error) { + options.onError(response); + } else if (isResponseError(response)) { + options.onRequestError(response); + } else { + await options.onResponse(response); + } + return true; + }; + const handleResponseError = async (error) => { + if (error instanceof InterceptorError) { + throw result.error; + } + if (isNodeLikeError(error)) { + options.onError(error); + return true; + } + if (error instanceof Response) { + return await handleResponse(error); + } + return false; + }; + options.emitter.once("request", ({ requestId: pendingRequestId }) => { + if (pendingRequestId !== options.requestId) { + return; + } + if (options.controller[kResponsePromise].state === "pending") { + options.controller[kResponsePromise].resolve(void 0); + } + }); + const requestAbortPromise = new DeferredPromise2(); + if (options.request.signal) { + if (options.request.signal.aborted) { + requestAbortPromise.reject(options.request.signal.reason); + } else { + options.request.signal.addEventListener( + "abort", + () => { + requestAbortPromise.reject(options.request.signal.reason); + }, + { once: true } + ); + } + } + const result = await until(async () => { + const requestListtenersPromise = emitAsync(options.emitter, "request", { + requestId: options.requestId, + request: options.request, + controller: options.controller + }); + await Promise.race([ + // Short-circuit the request handling promise if the request gets aborted. + requestAbortPromise, + requestListtenersPromise, + options.controller[kResponsePromise] + ]); + const mockedResponse = await options.controller[kResponsePromise]; + return mockedResponse; + }); + if (requestAbortPromise.state === "rejected") { + options.onError(requestAbortPromise.rejectionReason); + return true; + } + if (result.error) { + if (await handleResponseError(result.error)) { + return true; + } + if (options.emitter.listenerCount("unhandledException") > 0) { + const unhandledExceptionController = new RequestController( + options.request + ); + await emitAsync(options.emitter, "unhandledException", { + error: result.error, + request: options.request, + requestId: options.requestId, + controller: unhandledExceptionController + }).then(() => { + if (unhandledExceptionController[kResponsePromise].state === "pending") { + unhandledExceptionController[kResponsePromise].resolve(void 0); + } + }); + const nextResult = await until( + () => unhandledExceptionController[kResponsePromise] + ); + if (nextResult.error) { + return handleResponseError(nextResult.error); + } + if (nextResult.data) { + return handleResponse(nextResult.data); + } + } + options.onResponse(createServerErrorResponse(result.error)); + return true; + } + if (result.data) { + return handleResponse(result.data); + } + return false; +} + +export { + isPropertyAccessible, + createServerErrorResponse, + RequestController, + emitAsync, + handleRequest +}; +//# sourceMappingURL=chunk-5KMS5CTP.mjs.map \ No newline at end of file diff --git a/node_modules/@mswjs/interceptors/lib/node/chunk-5KMS5CTP.mjs.map b/node_modules/@mswjs/interceptors/lib/node/chunk-5KMS5CTP.mjs.map new file mode 100644 index 0000000000000000000000000000000000000000..41215da76064f753f0fe9ade069a3f63da6bc0aa --- /dev/null +++ b/node_modules/@mswjs/interceptors/lib/node/chunk-5KMS5CTP.mjs.map @@ -0,0 +1 @@ +{"version":3,"sources":["../../src/RequestController.ts","../../src/InterceptorError.ts","../../src/utils/emitAsync.ts","../../src/utils/handleRequest.ts","../../src/utils/isPropertyAccessible.ts","../../src/utils/responseUtils.ts","../../src/utils/isNodeLikeError.ts"],"sourcesContent":["import { invariant } from 'outvariant'\nimport { DeferredPromise } from '@open-draft/deferred-promise'\nimport { InterceptorError } from './InterceptorError'\n\nconst kRequestHandled = Symbol('kRequestHandled')\nexport const kResponsePromise = Symbol('kResponsePromise')\n\nexport class RequestController {\n /**\n * Internal response promise.\n * Available only for the library internals to grab the\n * response instance provided by the developer.\n * @note This promise cannot be rejected. It's either infinitely\n * pending or resolved with whichever Response was passed to `respondWith()`.\n */\n [kResponsePromise]: DeferredPromise;\n\n /**\n * Internal flag indicating if this request has been handled.\n * @note The response promise becomes \"fulfilled\" on the next tick.\n */\n [kRequestHandled]: boolean\n\n constructor(private request: Request) {\n this[kRequestHandled] = false\n this[kResponsePromise] = new DeferredPromise()\n }\n\n /**\n * Respond to this request with the given `Response` instance.\n * @example\n * controller.respondWith(new Response())\n * controller.respondWith(Response.json({ id }))\n * controller.respondWith(Response.error())\n */\n public respondWith(response: Response): void {\n invariant.as(\n InterceptorError,\n !this[kRequestHandled],\n 'Failed to respond to the \"%s %s\" request: the \"request\" event has already been handled.',\n this.request.method,\n this.request.url\n )\n\n this[kRequestHandled] = true\n this[kResponsePromise].resolve(response)\n\n /**\n * @note The request conrtoller doesn't do anything\n * apart from letting the interceptor await the response\n * provided by the developer through the response promise.\n * Each interceptor implements the actual respondWith/errorWith\n * logic based on that interceptor's needs.\n */\n }\n\n /**\n * Error this request with the given error.\n * @example\n * controller.errorWith()\n * controller.errorWith(new Error('Oops!'))\n */\n public errorWith(error?: Error): void {\n invariant.as(\n InterceptorError,\n !this[kRequestHandled],\n 'Failed to error the \"%s %s\" request: the \"request\" event has already been handled.',\n this.request.method,\n this.request.url\n )\n\n this[kRequestHandled] = true\n\n /**\n * @note Resolve the response promise, not reject.\n * This helps us differentiate between unhandled exceptions\n * and intended errors (\"errorWith\") while waiting for the response.\n */\n this[kResponsePromise].resolve(error)\n }\n}\n","export class InterceptorError extends Error {\n constructor(message?: string) {\n super(message)\n this.name = 'InterceptorError'\n Object.setPrototypeOf(this, InterceptorError.prototype)\n }\n}\n","import { Emitter, EventMap } from 'strict-event-emitter'\n\n/**\n * Emits an event on the given emitter but executes\n * the listeners sequentially. This accounts for asynchronous\n * listeners (e.g. those having \"sleep\" and handling the request).\n */\nexport async function emitAsync<\n Events extends EventMap,\n EventName extends keyof Events\n>(\n emitter: Emitter,\n eventName: EventName,\n ...data: Events[EventName]\n): Promise {\n const listners = emitter.listeners(eventName)\n\n if (listners.length === 0) {\n return\n }\n\n for (const listener of listners) {\n await listener.apply(emitter, data)\n }\n}\n","import type { Emitter } from 'strict-event-emitter'\nimport { DeferredPromise } from '@open-draft/deferred-promise'\nimport { until } from '@open-draft/until'\nimport type { HttpRequestEventMap } from '../glossary'\nimport { emitAsync } from './emitAsync'\nimport { kResponsePromise, RequestController } from '../RequestController'\nimport {\n createServerErrorResponse,\n isResponseError,\n ResponseError,\n} from './responseUtils'\nimport { InterceptorError } from '../InterceptorError'\nimport { isNodeLikeError } from './isNodeLikeError'\n\ninterface HandleRequestOptions {\n requestId: string\n request: Request\n emitter: Emitter\n controller: RequestController\n\n /**\n * Called when the request has been handled\n * with the given `Response` instance.\n */\n onResponse: (response: Response) => void | Promise\n\n /**\n * Called when the request has been handled\n * with the given `Response.error()` instance.\n */\n onRequestError: (response: ResponseError) => void\n\n /**\n * Called when an unhandled error happens during the\n * request handling. This is never a thrown error/response.\n */\n onError: (error: unknown) => void\n}\n\n/**\n * @returns {Promise} Indicates whether the request has been handled.\n */\nexport async function handleRequest(\n options: HandleRequestOptions\n): Promise {\n const handleResponse = async (response: Response | Error) => {\n if (response instanceof Error) {\n options.onError(response)\n }\n\n // Handle \"Response.error()\" instances.\n else if (isResponseError(response)) {\n options.onRequestError(response)\n } else {\n await options.onResponse(response)\n }\n\n return true\n }\n\n const handleResponseError = async (error: unknown): Promise => {\n // Forward the special interceptor error instances\n // to the developer. These must not be handled in any way.\n if (error instanceof InterceptorError) {\n throw result.error\n }\n\n // Support mocking Node.js-like errors.\n if (isNodeLikeError(error)) {\n options.onError(error)\n return true\n }\n\n // Handle thrown responses.\n if (error instanceof Response) {\n return await handleResponse(error)\n }\n\n return false\n }\n\n // Add the last \"request\" listener to check if the request\n // has been handled in any way. If it hasn't, resolve the\n // response promise with undefined.\n options.emitter.once('request', ({ requestId: pendingRequestId }) => {\n if (pendingRequestId !== options.requestId) {\n return\n }\n\n if (options.controller[kResponsePromise].state === 'pending') {\n options.controller[kResponsePromise].resolve(undefined)\n }\n })\n\n const requestAbortPromise = new DeferredPromise()\n\n /**\n * @note `signal` is not always defined in React Native.\n */\n if (options.request.signal) {\n if (options.request.signal.aborted) {\n requestAbortPromise.reject(options.request.signal.reason)\n } else {\n options.request.signal.addEventListener(\n 'abort',\n () => {\n requestAbortPromise.reject(options.request.signal.reason)\n },\n { once: true }\n )\n }\n }\n\n const result = await until(async () => {\n // Emit the \"request\" event and wait until all the listeners\n // for that event are finished (e.g. async listeners awaited).\n // By the end of this promise, the developer cannot affect the\n // request anymore.\n const requestListtenersPromise = emitAsync(options.emitter, 'request', {\n requestId: options.requestId,\n request: options.request,\n controller: options.controller,\n })\n\n await Promise.race([\n // Short-circuit the request handling promise if the request gets aborted.\n requestAbortPromise,\n requestListtenersPromise,\n options.controller[kResponsePromise],\n ])\n\n // The response promise will settle immediately once\n // the developer calls either \"respondWith\" or \"errorWith\".\n const mockedResponse = await options.controller[kResponsePromise]\n return mockedResponse\n })\n\n // Handle the request being aborted while waiting for the request listeners.\n if (requestAbortPromise.state === 'rejected') {\n options.onError(requestAbortPromise.rejectionReason)\n return true\n }\n\n if (result.error) {\n // Handle the error during the request listener execution.\n // These can be thrown responses or request errors.\n if (await handleResponseError(result.error)) {\n return true\n }\n\n // If the developer has added \"unhandledException\" listeners,\n // allow them to handle the error. They can translate it to a\n // mocked response, network error, or forward it as-is.\n if (options.emitter.listenerCount('unhandledException') > 0) {\n // Create a new request controller just for the unhandled exception case.\n // This is needed because the original controller might have been already\n // interacted with (e.g. \"respondWith\" or \"errorWith\" called on it).\n const unhandledExceptionController = new RequestController(\n options.request\n )\n\n await emitAsync(options.emitter, 'unhandledException', {\n error: result.error,\n request: options.request,\n requestId: options.requestId,\n controller: unhandledExceptionController,\n }).then(() => {\n // If all the \"unhandledException\" listeners have finished\n // but have not handled the response in any way, preemptively\n // resolve the pending response promise from the new controller.\n // This prevents it from hanging forever.\n if (\n unhandledExceptionController[kResponsePromise].state === 'pending'\n ) {\n unhandledExceptionController[kResponsePromise].resolve(undefined)\n }\n })\n\n const nextResult = await until(\n () => unhandledExceptionController[kResponsePromise]\n )\n\n /**\n * @note Handle the result of the unhandled controller\n * in the same way as the original request controller.\n * The exception here is that thrown errors within the\n * \"unhandledException\" event do NOT result in another\n * emit of the same event. They are forwarded as-is.\n */\n if (nextResult.error) {\n return handleResponseError(nextResult.error)\n }\n\n if (nextResult.data) {\n return handleResponse(nextResult.data)\n }\n }\n\n // Otherwise, coerce unhandled exceptions to a 500 Internal Server Error response.\n options.onResponse(createServerErrorResponse(result.error))\n return true\n }\n\n /**\n * Handle a mocked Response instance.\n * @note That this can also be an Error in case\n * the developer called \"errorWith\". This differentiates\n * unhandled exceptions from intended errors.\n */\n if (result.data) {\n return handleResponse(result.data)\n }\n\n // In all other cases, consider the request unhandled.\n // The interceptor must perform it as-is.\n return false\n}\n","/**\n * A function that validates if property access is possible on an object\n * without throwing. It returns `true` if the property access is possible\n * and `false` otherwise.\n *\n * Environments like miniflare will throw on property access on certain objects\n * like Request and Response, for unimplemented properties.\n */\nexport function isPropertyAccessible>(\n obj: Obj,\n key: keyof Obj\n) {\n try {\n obj[key]\n return true\n } catch {\n return false\n }\n}\n","import { isPropertyAccessible } from './isPropertyAccessible'\n\n/**\n * Creates a generic 500 Unhandled Exception response.\n */\nexport function createServerErrorResponse(body: unknown): Response {\n return new Response(\n JSON.stringify(\n body instanceof Error\n ? {\n name: body.name,\n message: body.message,\n stack: body.stack,\n }\n : body\n ),\n {\n status: 500,\n statusText: 'Unhandled Exception',\n headers: {\n 'Content-Type': 'application/json',\n },\n }\n )\n}\n\nexport type ResponseError = Response & { type: 'error' }\n\n/**\n * Check if the given response is a `Response.error()`.\n *\n * @note Some environments, like Miniflare (Cloudflare) do not\n * implement the \"Response.type\" property and throw on its access.\n * Safely check if we can access \"type\" on \"Response\" before continuing.\n * @see https://github.com/mswjs/msw/issues/1834\n */\nexport function isResponseError(response: Response): response is ResponseError {\n return isPropertyAccessible(response, 'type') && response.type === 'error'\n}\n","export function isNodeLikeError(\n error: unknown\n): error is NodeJS.ErrnoException {\n if (error == null) {\n return false\n }\n\n if (!(error instanceof Error)) {\n return false\n }\n\n return 'code' in error && 'errno' in error\n}\n"],"mappings":";AAAA,SAAS,iBAAiB;AAC1B,SAAS,uBAAuB;;;ACDzB,IAAM,mBAAN,cAA+B,MAAM;AAAA,EAC1C,YAAY,SAAkB;AAC5B,UAAM,OAAO;AACb,SAAK,OAAO;AACZ,WAAO,eAAe,MAAM,iBAAiB,SAAS;AAAA,EACxD;AACF;;;ADFA,IAAM,kBAAkB,OAAO,iBAAiB;AACzC,IAAM,mBAAmB,OAAO,kBAAkB;AAElD,IAAM,oBAAN,MAAwB;AAAA,EAgB7B,YAAoB,SAAkB;AAAlB;AAClB,SAAK,eAAe,IAAI;AACxB,SAAK,gBAAgB,IAAI,IAAI,gBAAgB;AAAA,EAC/C;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASO,YAAY,UAA0B;AAC3C,cAAU;AAAA,MACR;AAAA,MACA,CAAC,KAAK,eAAe;AAAA,MACrB;AAAA,MACA,KAAK,QAAQ;AAAA,MACb,KAAK,QAAQ;AAAA,IACf;AAEA,SAAK,eAAe,IAAI;AACxB,SAAK,gBAAgB,EAAE,QAAQ,QAAQ;AAAA,EASzC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQO,UAAU,OAAqB;AACpC,cAAU;AAAA,MACR;AAAA,MACA,CAAC,KAAK,eAAe;AAAA,MACrB;AAAA,MACA,KAAK,QAAQ;AAAA,MACb,KAAK,QAAQ;AAAA,IACf;AAEA,SAAK,eAAe,IAAI;AAOxB,SAAK,gBAAgB,EAAE,QAAQ,KAAK;AAAA,EACtC;AACF;AAjEG,kBAMA;;;AEdH,eAAsB,UAIpB,SACA,cACG,MACY;AACf,QAAM,WAAW,QAAQ,UAAU,SAAS;AAE5C,MAAI,SAAS,WAAW,GAAG;AACzB;AAAA,EACF;AAEA,aAAW,YAAY,UAAU;AAC/B,UAAM,SAAS,MAAM,SAAS,IAAI;AAAA,EACpC;AACF;;;ACvBA,SAAS,mBAAAA,wBAAuB;AAChC,SAAS,aAAa;;;ACMf,SAAS,qBACd,KACA,KACA;AACA,MAAI;AACF,QAAI,GAAG;AACP,WAAO;AAAA,EACT,SAAQ,GAAN;AACA,WAAO;AAAA,EACT;AACF;;;ACbO,SAAS,0BAA0B,MAAyB;AACjE,SAAO,IAAI;AAAA,IACT,KAAK;AAAA,MACH,gBAAgB,QACZ;AAAA,QACE,MAAM,KAAK;AAAA,QACX,SAAS,KAAK;AAAA,QACd,OAAO,KAAK;AAAA,MACd,IACA;AAAA,IACN;AAAA,IACA;AAAA,MACE,QAAQ;AAAA,MACR,YAAY;AAAA,MACZ,SAAS;AAAA,QACP,gBAAgB;AAAA,MAClB;AAAA,IACF;AAAA,EACF;AACF;AAYO,SAAS,gBAAgB,UAA+C;AAC7E,SAAO,qBAAqB,UAAU,MAAM,KAAK,SAAS,SAAS;AACrE;;;ACtCO,SAAS,gBACd,OACgC;AAChC,MAAI,SAAS,MAAM;AACjB,WAAO;AAAA,EACT;AAEA,MAAI,EAAE,iBAAiB,QAAQ;AAC7B,WAAO;AAAA,EACT;AAEA,SAAO,UAAU,SAAS,WAAW;AACvC;;;AH8BA,eAAsB,cACpB,SACkB;AAClB,QAAM,iBAAiB,OAAO,aAA+B;AAC3D,QAAI,oBAAoB,OAAO;AAC7B,cAAQ,QAAQ,QAAQ;AAAA,IAC1B,WAGS,gBAAgB,QAAQ,GAAG;AAClC,cAAQ,eAAe,QAAQ;AAAA,IACjC,OAAO;AACL,YAAM,QAAQ,WAAW,QAAQ;AAAA,IACnC;AAEA,WAAO;AAAA,EACT;AAEA,QAAM,sBAAsB,OAAO,UAAqC;AAGtE,QAAI,iBAAiB,kBAAkB;AACrC,YAAM,OAAO;AAAA,IACf;AAGA,QAAI,gBAAgB,KAAK,GAAG;AAC1B,cAAQ,QAAQ,KAAK;AACrB,aAAO;AAAA,IACT;AAGA,QAAI,iBAAiB,UAAU;AAC7B,aAAO,MAAM,eAAe,KAAK;AAAA,IACnC;AAEA,WAAO;AAAA,EACT;AAKA,UAAQ,QAAQ,KAAK,WAAW,CAAC,EAAE,WAAW,iBAAiB,MAAM;AACnE,QAAI,qBAAqB,QAAQ,WAAW;AAC1C;AAAA,IACF;AAEA,QAAI,QAAQ,WAAW,gBAAgB,EAAE,UAAU,WAAW;AAC5D,cAAQ,WAAW,gBAAgB,EAAE,QAAQ,MAAS;AAAA,IACxD;AAAA,EACF,CAAC;AAED,QAAM,sBAAsB,IAAIC,iBAA+B;AAK/D,MAAI,QAAQ,QAAQ,QAAQ;AAC1B,QAAI,QAAQ,QAAQ,OAAO,SAAS;AAClC,0BAAoB,OAAO,QAAQ,QAAQ,OAAO,MAAM;AAAA,IAC1D,OAAO;AACL,cAAQ,QAAQ,OAAO;AAAA,QACrB;AAAA,QACA,MAAM;AACJ,8BAAoB,OAAO,QAAQ,QAAQ,OAAO,MAAM;AAAA,QAC1D;AAAA,QACA,EAAE,MAAM,KAAK;AAAA,MACf;AAAA,IACF;AAAA,EACF;AAEA,QAAM,SAAS,MAAM,MAAM,YAAY;AAKrC,UAAM,2BAA2B,UAAU,QAAQ,SAAS,WAAW;AAAA,MACrE,WAAW,QAAQ;AAAA,MACnB,SAAS,QAAQ;AAAA,MACjB,YAAY,QAAQ;AAAA,IACtB,CAAC;AAED,UAAM,QAAQ,KAAK;AAAA;AAAA,MAEjB;AAAA,MACA;AAAA,MACA,QAAQ,WAAW,gBAAgB;AAAA,IACrC,CAAC;AAID,UAAM,iBAAiB,MAAM,QAAQ,WAAW,gBAAgB;AAChE,WAAO;AAAA,EACT,CAAC;AAGD,MAAI,oBAAoB,UAAU,YAAY;AAC5C,YAAQ,QAAQ,oBAAoB,eAAe;AACnD,WAAO;AAAA,EACT;AAEA,MAAI,OAAO,OAAO;AAGhB,QAAI,MAAM,oBAAoB,OAAO,KAAK,GAAG;AAC3C,aAAO;AAAA,IACT;AAKA,QAAI,QAAQ,QAAQ,cAAc,oBAAoB,IAAI,GAAG;AAI3D,YAAM,+BAA+B,IAAI;AAAA,QACvC,QAAQ;AAAA,MACV;AAEA,YAAM,UAAU,QAAQ,SAAS,sBAAsB;AAAA,QACrD,OAAO,OAAO;AAAA,QACd,SAAS,QAAQ;AAAA,QACjB,WAAW,QAAQ;AAAA,QACnB,YAAY;AAAA,MACd,CAAC,EAAE,KAAK,MAAM;AAKZ,YACE,6BAA6B,gBAAgB,EAAE,UAAU,WACzD;AACA,uCAA6B,gBAAgB,EAAE,QAAQ,MAAS;AAAA,QAClE;AAAA,MACF,CAAC;AAED,YAAM,aAAa,MAAM;AAAA,QACvB,MAAM,6BAA6B,gBAAgB;AAAA,MACrD;AASA,UAAI,WAAW,OAAO;AACpB,eAAO,oBAAoB,WAAW,KAAK;AAAA,MAC7C;AAEA,UAAI,WAAW,MAAM;AACnB,eAAO,eAAe,WAAW,IAAI;AAAA,MACvC;AAAA,IACF;AAGA,YAAQ,WAAW,0BAA0B,OAAO,KAAK,CAAC;AAC1D,WAAO;AAAA,EACT;AAQA,MAAI,OAAO,MAAM;AACf,WAAO,eAAe,OAAO,IAAI;AAAA,EACnC;AAIA,SAAO;AACT;","names":["DeferredPromise","DeferredPromise"]} \ No newline at end of file diff --git a/node_modules/@mswjs/interceptors/lib/node/chunk-6HYIRFX2.mjs b/node_modules/@mswjs/interceptors/lib/node/chunk-6HYIRFX2.mjs new file mode 100644 index 0000000000000000000000000000000000000000..05b6c33cb2dec03c23115c9c1de440c0a0a10277 --- /dev/null +++ b/node_modules/@mswjs/interceptors/lib/node/chunk-6HYIRFX2.mjs @@ -0,0 +1,22 @@ +// src/utils/bufferUtils.ts +var encoder = new TextEncoder(); +function encodeBuffer(text) { + return encoder.encode(text); +} +function decodeBuffer(buffer, encoding) { + const decoder = new TextDecoder(encoding); + return decoder.decode(buffer); +} +function toArrayBuffer(array) { + return array.buffer.slice( + array.byteOffset, + array.byteOffset + array.byteLength + ); +} + +export { + encodeBuffer, + decodeBuffer, + toArrayBuffer +}; +//# sourceMappingURL=chunk-6HYIRFX2.mjs.map \ No newline at end of file diff --git a/node_modules/@mswjs/interceptors/lib/node/chunk-6HYIRFX2.mjs.map b/node_modules/@mswjs/interceptors/lib/node/chunk-6HYIRFX2.mjs.map new file mode 100644 index 0000000000000000000000000000000000000000..6f27915c41e396fe4b28381b580d8fc7fdffbb3b --- /dev/null +++ b/node_modules/@mswjs/interceptors/lib/node/chunk-6HYIRFX2.mjs.map @@ -0,0 +1 @@ +{"version":3,"sources":["../../src/utils/bufferUtils.ts"],"sourcesContent":["const encoder = new TextEncoder()\n\nexport function encodeBuffer(text: string): Uint8Array {\n return encoder.encode(text)\n}\n\nexport function decodeBuffer(buffer: ArrayBuffer, encoding?: string): string {\n const decoder = new TextDecoder(encoding)\n return decoder.decode(buffer)\n}\n\n/**\n * Create an `ArrayBuffer` from the given `Uint8Array`.\n * Takes the byte offset into account to produce the right buffer\n * in the case when the buffer is bigger than the data view.\n */\nexport function toArrayBuffer(array: Uint8Array): ArrayBuffer {\n return array.buffer.slice(\n array.byteOffset,\n array.byteOffset + array.byteLength\n )\n}\n"],"mappings":";AAAA,IAAM,UAAU,IAAI,YAAY;AAEzB,SAAS,aAAa,MAA0B;AACrD,SAAO,QAAQ,OAAO,IAAI;AAC5B;AAEO,SAAS,aAAa,QAAqB,UAA2B;AAC3E,QAAM,UAAU,IAAI,YAAY,QAAQ;AACxC,SAAO,QAAQ,OAAO,MAAM;AAC9B;AAOO,SAAS,cAAc,OAAgC;AAC5D,SAAO,MAAM,OAAO;AAAA,IAClB,MAAM;AAAA,IACN,MAAM,aAAa,MAAM;AAAA,EAC3B;AACF;","names":[]} \ No newline at end of file diff --git a/node_modules/@mswjs/interceptors/lib/node/chunk-6L3PFBGT.js b/node_modules/@mswjs/interceptors/lib/node/chunk-6L3PFBGT.js new file mode 100644 index 0000000000000000000000000000000000000000..4dc5e0cb77de31c20c757adfb53b5d71f99e608a --- /dev/null +++ b/node_modules/@mswjs/interceptors/lib/node/chunk-6L3PFBGT.js @@ -0,0 +1,230 @@ +"use strict";Object.defineProperty(exports, "__esModule", {value: true});// src/RequestController.ts +var _outvariant = require('outvariant'); +var _deferredpromise = require('@open-draft/deferred-promise'); + +// src/InterceptorError.ts +var InterceptorError = class extends Error { + constructor(message) { + super(message); + this.name = "InterceptorError"; + Object.setPrototypeOf(this, InterceptorError.prototype); + } +}; + +// src/RequestController.ts +var kRequestHandled = Symbol("kRequestHandled"); +var kResponsePromise = Symbol("kResponsePromise"); +var RequestController = class { + constructor(request) { + this.request = request; + this[kRequestHandled] = false; + this[kResponsePromise] = new (0, _deferredpromise.DeferredPromise)(); + } + /** + * Respond to this request with the given `Response` instance. + * @example + * controller.respondWith(new Response()) + * controller.respondWith(Response.json({ id })) + * controller.respondWith(Response.error()) + */ + respondWith(response) { + _outvariant.invariant.as( + InterceptorError, + !this[kRequestHandled], + 'Failed to respond to the "%s %s" request: the "request" event has already been handled.', + this.request.method, + this.request.url + ); + this[kRequestHandled] = true; + this[kResponsePromise].resolve(response); + } + /** + * Error this request with the given error. + * @example + * controller.errorWith() + * controller.errorWith(new Error('Oops!')) + */ + errorWith(error) { + _outvariant.invariant.as( + InterceptorError, + !this[kRequestHandled], + 'Failed to error the "%s %s" request: the "request" event has already been handled.', + this.request.method, + this.request.url + ); + this[kRequestHandled] = true; + this[kResponsePromise].resolve(error); + } +}; +kResponsePromise, kRequestHandled; + +// src/utils/emitAsync.ts +async function emitAsync(emitter, eventName, ...data) { + const listners = emitter.listeners(eventName); + if (listners.length === 0) { + return; + } + for (const listener of listners) { + await listener.apply(emitter, data); + } +} + +// src/utils/handleRequest.ts + +var _until = require('@open-draft/until'); + +// src/utils/isPropertyAccessible.ts +function isPropertyAccessible(obj, key) { + try { + obj[key]; + return true; + } catch (e) { + return false; + } +} + +// src/utils/responseUtils.ts +function createServerErrorResponse(body) { + return new Response( + JSON.stringify( + body instanceof Error ? { + name: body.name, + message: body.message, + stack: body.stack + } : body + ), + { + status: 500, + statusText: "Unhandled Exception", + headers: { + "Content-Type": "application/json" + } + } + ); +} +function isResponseError(response) { + return isPropertyAccessible(response, "type") && response.type === "error"; +} + +// src/utils/isNodeLikeError.ts +function isNodeLikeError(error) { + if (error == null) { + return false; + } + if (!(error instanceof Error)) { + return false; + } + return "code" in error && "errno" in error; +} + +// src/utils/handleRequest.ts +async function handleRequest(options) { + const handleResponse = async (response) => { + if (response instanceof Error) { + options.onError(response); + } else if (isResponseError(response)) { + options.onRequestError(response); + } else { + await options.onResponse(response); + } + return true; + }; + const handleResponseError = async (error) => { + if (error instanceof InterceptorError) { + throw result.error; + } + if (isNodeLikeError(error)) { + options.onError(error); + return true; + } + if (error instanceof Response) { + return await handleResponse(error); + } + return false; + }; + options.emitter.once("request", ({ requestId: pendingRequestId }) => { + if (pendingRequestId !== options.requestId) { + return; + } + if (options.controller[kResponsePromise].state === "pending") { + options.controller[kResponsePromise].resolve(void 0); + } + }); + const requestAbortPromise = new (0, _deferredpromise.DeferredPromise)(); + if (options.request.signal) { + if (options.request.signal.aborted) { + requestAbortPromise.reject(options.request.signal.reason); + } else { + options.request.signal.addEventListener( + "abort", + () => { + requestAbortPromise.reject(options.request.signal.reason); + }, + { once: true } + ); + } + } + const result = await _until.until.call(void 0, async () => { + const requestListtenersPromise = emitAsync(options.emitter, "request", { + requestId: options.requestId, + request: options.request, + controller: options.controller + }); + await Promise.race([ + // Short-circuit the request handling promise if the request gets aborted. + requestAbortPromise, + requestListtenersPromise, + options.controller[kResponsePromise] + ]); + const mockedResponse = await options.controller[kResponsePromise]; + return mockedResponse; + }); + if (requestAbortPromise.state === "rejected") { + options.onError(requestAbortPromise.rejectionReason); + return true; + } + if (result.error) { + if (await handleResponseError(result.error)) { + return true; + } + if (options.emitter.listenerCount("unhandledException") > 0) { + const unhandledExceptionController = new RequestController( + options.request + ); + await emitAsync(options.emitter, "unhandledException", { + error: result.error, + request: options.request, + requestId: options.requestId, + controller: unhandledExceptionController + }).then(() => { + if (unhandledExceptionController[kResponsePromise].state === "pending") { + unhandledExceptionController[kResponsePromise].resolve(void 0); + } + }); + const nextResult = await _until.until.call(void 0, + () => unhandledExceptionController[kResponsePromise] + ); + if (nextResult.error) { + return handleResponseError(nextResult.error); + } + if (nextResult.data) { + return handleResponse(nextResult.data); + } + } + options.onResponse(createServerErrorResponse(result.error)); + return true; + } + if (result.data) { + return handleResponse(result.data); + } + return false; +} + + + + + + + +exports.isPropertyAccessible = isPropertyAccessible; exports.createServerErrorResponse = createServerErrorResponse; exports.RequestController = RequestController; exports.emitAsync = emitAsync; exports.handleRequest = handleRequest; +//# sourceMappingURL=chunk-6L3PFBGT.js.map \ No newline at end of file diff --git a/node_modules/@mswjs/interceptors/lib/node/chunk-6L3PFBGT.js.map b/node_modules/@mswjs/interceptors/lib/node/chunk-6L3PFBGT.js.map new file mode 100644 index 0000000000000000000000000000000000000000..9c5a436574e934d12c4688b420d1d0056a473f9d --- /dev/null +++ b/node_modules/@mswjs/interceptors/lib/node/chunk-6L3PFBGT.js.map @@ -0,0 +1 @@ +{"version":3,"sources":["../../src/RequestController.ts","../../src/InterceptorError.ts","../../src/utils/emitAsync.ts","../../src/utils/handleRequest.ts","../../src/utils/isPropertyAccessible.ts","../../src/utils/responseUtils.ts","../../src/utils/isNodeLikeError.ts"],"names":["DeferredPromise"],"mappings":"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","sourcesContent":["import { invariant } from 'outvariant'\nimport { DeferredPromise } from '@open-draft/deferred-promise'\nimport { InterceptorError } from './InterceptorError'\n\nconst kRequestHandled = Symbol('kRequestHandled')\nexport const kResponsePromise = Symbol('kResponsePromise')\n\nexport class RequestController {\n /**\n * Internal response promise.\n * Available only for the library internals to grab the\n * response instance provided by the developer.\n * @note This promise cannot be rejected. It's either infinitely\n * pending or resolved with whichever Response was passed to `respondWith()`.\n */\n [kResponsePromise]: DeferredPromise;\n\n /**\n * Internal flag indicating if this request has been handled.\n * @note The response promise becomes \"fulfilled\" on the next tick.\n */\n [kRequestHandled]: boolean\n\n constructor(private request: Request) {\n this[kRequestHandled] = false\n this[kResponsePromise] = new DeferredPromise()\n }\n\n /**\n * Respond to this request with the given `Response` instance.\n * @example\n * controller.respondWith(new Response())\n * controller.respondWith(Response.json({ id }))\n * controller.respondWith(Response.error())\n */\n public respondWith(response: Response): void {\n invariant.as(\n InterceptorError,\n !this[kRequestHandled],\n 'Failed to respond to the \"%s %s\" request: the \"request\" event has already been handled.',\n this.request.method,\n this.request.url\n )\n\n this[kRequestHandled] = true\n this[kResponsePromise].resolve(response)\n\n /**\n * @note The request conrtoller doesn't do anything\n * apart from letting the interceptor await the response\n * provided by the developer through the response promise.\n * Each interceptor implements the actual respondWith/errorWith\n * logic based on that interceptor's needs.\n */\n }\n\n /**\n * Error this request with the given error.\n * @example\n * controller.errorWith()\n * controller.errorWith(new Error('Oops!'))\n */\n public errorWith(error?: Error): void {\n invariant.as(\n InterceptorError,\n !this[kRequestHandled],\n 'Failed to error the \"%s %s\" request: the \"request\" event has already been handled.',\n this.request.method,\n this.request.url\n )\n\n this[kRequestHandled] = true\n\n /**\n * @note Resolve the response promise, not reject.\n * This helps us differentiate between unhandled exceptions\n * and intended errors (\"errorWith\") while waiting for the response.\n */\n this[kResponsePromise].resolve(error)\n }\n}\n","export class InterceptorError extends Error {\n constructor(message?: string) {\n super(message)\n this.name = 'InterceptorError'\n Object.setPrototypeOf(this, InterceptorError.prototype)\n }\n}\n","import { Emitter, EventMap } from 'strict-event-emitter'\n\n/**\n * Emits an event on the given emitter but executes\n * the listeners sequentially. This accounts for asynchronous\n * listeners (e.g. those having \"sleep\" and handling the request).\n */\nexport async function emitAsync<\n Events extends EventMap,\n EventName extends keyof Events\n>(\n emitter: Emitter,\n eventName: EventName,\n ...data: Events[EventName]\n): Promise {\n const listners = emitter.listeners(eventName)\n\n if (listners.length === 0) {\n return\n }\n\n for (const listener of listners) {\n await listener.apply(emitter, data)\n }\n}\n","import type { Emitter } from 'strict-event-emitter'\nimport { DeferredPromise } from '@open-draft/deferred-promise'\nimport { until } from '@open-draft/until'\nimport type { HttpRequestEventMap } from '../glossary'\nimport { emitAsync } from './emitAsync'\nimport { kResponsePromise, RequestController } from '../RequestController'\nimport {\n createServerErrorResponse,\n isResponseError,\n ResponseError,\n} from './responseUtils'\nimport { InterceptorError } from '../InterceptorError'\nimport { isNodeLikeError } from './isNodeLikeError'\n\ninterface HandleRequestOptions {\n requestId: string\n request: Request\n emitter: Emitter\n controller: RequestController\n\n /**\n * Called when the request has been handled\n * with the given `Response` instance.\n */\n onResponse: (response: Response) => void | Promise\n\n /**\n * Called when the request has been handled\n * with the given `Response.error()` instance.\n */\n onRequestError: (response: ResponseError) => void\n\n /**\n * Called when an unhandled error happens during the\n * request handling. This is never a thrown error/response.\n */\n onError: (error: unknown) => void\n}\n\n/**\n * @returns {Promise} Indicates whether the request has been handled.\n */\nexport async function handleRequest(\n options: HandleRequestOptions\n): Promise {\n const handleResponse = async (response: Response | Error) => {\n if (response instanceof Error) {\n options.onError(response)\n }\n\n // Handle \"Response.error()\" instances.\n else if (isResponseError(response)) {\n options.onRequestError(response)\n } else {\n await options.onResponse(response)\n }\n\n return true\n }\n\n const handleResponseError = async (error: unknown): Promise => {\n // Forward the special interceptor error instances\n // to the developer. These must not be handled in any way.\n if (error instanceof InterceptorError) {\n throw result.error\n }\n\n // Support mocking Node.js-like errors.\n if (isNodeLikeError(error)) {\n options.onError(error)\n return true\n }\n\n // Handle thrown responses.\n if (error instanceof Response) {\n return await handleResponse(error)\n }\n\n return false\n }\n\n // Add the last \"request\" listener to check if the request\n // has been handled in any way. If it hasn't, resolve the\n // response promise with undefined.\n options.emitter.once('request', ({ requestId: pendingRequestId }) => {\n if (pendingRequestId !== options.requestId) {\n return\n }\n\n if (options.controller[kResponsePromise].state === 'pending') {\n options.controller[kResponsePromise].resolve(undefined)\n }\n })\n\n const requestAbortPromise = new DeferredPromise()\n\n /**\n * @note `signal` is not always defined in React Native.\n */\n if (options.request.signal) {\n if (options.request.signal.aborted) {\n requestAbortPromise.reject(options.request.signal.reason)\n } else {\n options.request.signal.addEventListener(\n 'abort',\n () => {\n requestAbortPromise.reject(options.request.signal.reason)\n },\n { once: true }\n )\n }\n }\n\n const result = await until(async () => {\n // Emit the \"request\" event and wait until all the listeners\n // for that event are finished (e.g. async listeners awaited).\n // By the end of this promise, the developer cannot affect the\n // request anymore.\n const requestListtenersPromise = emitAsync(options.emitter, 'request', {\n requestId: options.requestId,\n request: options.request,\n controller: options.controller,\n })\n\n await Promise.race([\n // Short-circuit the request handling promise if the request gets aborted.\n requestAbortPromise,\n requestListtenersPromise,\n options.controller[kResponsePromise],\n ])\n\n // The response promise will settle immediately once\n // the developer calls either \"respondWith\" or \"errorWith\".\n const mockedResponse = await options.controller[kResponsePromise]\n return mockedResponse\n })\n\n // Handle the request being aborted while waiting for the request listeners.\n if (requestAbortPromise.state === 'rejected') {\n options.onError(requestAbortPromise.rejectionReason)\n return true\n }\n\n if (result.error) {\n // Handle the error during the request listener execution.\n // These can be thrown responses or request errors.\n if (await handleResponseError(result.error)) {\n return true\n }\n\n // If the developer has added \"unhandledException\" listeners,\n // allow them to handle the error. They can translate it to a\n // mocked response, network error, or forward it as-is.\n if (options.emitter.listenerCount('unhandledException') > 0) {\n // Create a new request controller just for the unhandled exception case.\n // This is needed because the original controller might have been already\n // interacted with (e.g. \"respondWith\" or \"errorWith\" called on it).\n const unhandledExceptionController = new RequestController(\n options.request\n )\n\n await emitAsync(options.emitter, 'unhandledException', {\n error: result.error,\n request: options.request,\n requestId: options.requestId,\n controller: unhandledExceptionController,\n }).then(() => {\n // If all the \"unhandledException\" listeners have finished\n // but have not handled the response in any way, preemptively\n // resolve the pending response promise from the new controller.\n // This prevents it from hanging forever.\n if (\n unhandledExceptionController[kResponsePromise].state === 'pending'\n ) {\n unhandledExceptionController[kResponsePromise].resolve(undefined)\n }\n })\n\n const nextResult = await until(\n () => unhandledExceptionController[kResponsePromise]\n )\n\n /**\n * @note Handle the result of the unhandled controller\n * in the same way as the original request controller.\n * The exception here is that thrown errors within the\n * \"unhandledException\" event do NOT result in another\n * emit of the same event. They are forwarded as-is.\n */\n if (nextResult.error) {\n return handleResponseError(nextResult.error)\n }\n\n if (nextResult.data) {\n return handleResponse(nextResult.data)\n }\n }\n\n // Otherwise, coerce unhandled exceptions to a 500 Internal Server Error response.\n options.onResponse(createServerErrorResponse(result.error))\n return true\n }\n\n /**\n * Handle a mocked Response instance.\n * @note That this can also be an Error in case\n * the developer called \"errorWith\". This differentiates\n * unhandled exceptions from intended errors.\n */\n if (result.data) {\n return handleResponse(result.data)\n }\n\n // In all other cases, consider the request unhandled.\n // The interceptor must perform it as-is.\n return false\n}\n","/**\n * A function that validates if property access is possible on an object\n * without throwing. It returns `true` if the property access is possible\n * and `false` otherwise.\n *\n * Environments like miniflare will throw on property access on certain objects\n * like Request and Response, for unimplemented properties.\n */\nexport function isPropertyAccessible>(\n obj: Obj,\n key: keyof Obj\n) {\n try {\n obj[key]\n return true\n } catch {\n return false\n }\n}\n","import { isPropertyAccessible } from './isPropertyAccessible'\n\n/**\n * Creates a generic 500 Unhandled Exception response.\n */\nexport function createServerErrorResponse(body: unknown): Response {\n return new Response(\n JSON.stringify(\n body instanceof Error\n ? {\n name: body.name,\n message: body.message,\n stack: body.stack,\n }\n : body\n ),\n {\n status: 500,\n statusText: 'Unhandled Exception',\n headers: {\n 'Content-Type': 'application/json',\n },\n }\n )\n}\n\nexport type ResponseError = Response & { type: 'error' }\n\n/**\n * Check if the given response is a `Response.error()`.\n *\n * @note Some environments, like Miniflare (Cloudflare) do not\n * implement the \"Response.type\" property and throw on its access.\n * Safely check if we can access \"type\" on \"Response\" before continuing.\n * @see https://github.com/mswjs/msw/issues/1834\n */\nexport function isResponseError(response: Response): response is ResponseError {\n return isPropertyAccessible(response, 'type') && response.type === 'error'\n}\n","export function isNodeLikeError(\n error: unknown\n): error is NodeJS.ErrnoException {\n if (error == null) {\n return false\n }\n\n if (!(error instanceof Error)) {\n return false\n }\n\n return 'code' in error && 'errno' in error\n}\n"]} \ No newline at end of file diff --git a/node_modules/@mswjs/interceptors/lib/node/chunk-6YM4PLBI.mjs b/node_modules/@mswjs/interceptors/lib/node/chunk-6YM4PLBI.mjs new file mode 100644 index 0000000000000000000000000000000000000000..0f6592117c9b14c7fdfb4dcfb6a62a8405c2bc74 --- /dev/null +++ b/node_modules/@mswjs/interceptors/lib/node/chunk-6YM4PLBI.mjs @@ -0,0 +1,7 @@ +// src/glossary.ts +var IS_PATCHED_MODULE = Symbol("isPatchedModule"); + +export { + IS_PATCHED_MODULE +}; +//# sourceMappingURL=chunk-6YM4PLBI.mjs.map \ No newline at end of file diff --git a/node_modules/@mswjs/interceptors/lib/node/chunk-6YM4PLBI.mjs.map b/node_modules/@mswjs/interceptors/lib/node/chunk-6YM4PLBI.mjs.map new file mode 100644 index 0000000000000000000000000000000000000000..cf918a1aae1637f92ba4dbd9e4470820513bc039 --- /dev/null +++ b/node_modules/@mswjs/interceptors/lib/node/chunk-6YM4PLBI.mjs.map @@ -0,0 +1 @@ +{"version":3,"sources":["../../src/glossary.ts"],"sourcesContent":["import type { RequestController } from './RequestController'\n\nexport const IS_PATCHED_MODULE: unique symbol = Symbol('isPatchedModule')\n\n/**\n * @note Export `RequestController` as a type only.\n * It's never meant to be created in the userland.\n */\nexport type { RequestController }\n\nexport type RequestCredentials = 'omit' | 'include' | 'same-origin'\n\nexport type HttpRequestEventMap = {\n request: [\n args: {\n request: Request\n requestId: string\n controller: RequestController\n }\n ]\n response: [\n args: {\n response: Response\n isMockedResponse: boolean\n request: Request\n requestId: string\n }\n ]\n unhandledException: [\n args: {\n error: unknown\n request: Request\n requestId: string\n controller: RequestController\n }\n ]\n}\n"],"mappings":";AAEO,IAAM,oBAAmC,OAAO,iBAAiB;","names":[]} \ No newline at end of file diff --git a/node_modules/@mswjs/interceptors/lib/node/chunk-73NOP3T5.js b/node_modules/@mswjs/interceptors/lib/node/chunk-73NOP3T5.js new file mode 100644 index 0000000000000000000000000000000000000000..3bcf384147c73113d20a7d84b3716557a49419c4 --- /dev/null +++ b/node_modules/@mswjs/interceptors/lib/node/chunk-73NOP3T5.js @@ -0,0 +1,7 @@ +"use strict";Object.defineProperty(exports, "__esModule", {value: true});// src/glossary.ts +var IS_PATCHED_MODULE = Symbol("isPatchedModule"); + + + +exports.IS_PATCHED_MODULE = IS_PATCHED_MODULE; +//# sourceMappingURL=chunk-73NOP3T5.js.map \ No newline at end of file diff --git a/node_modules/@mswjs/interceptors/lib/node/chunk-73NOP3T5.js.map b/node_modules/@mswjs/interceptors/lib/node/chunk-73NOP3T5.js.map new file mode 100644 index 0000000000000000000000000000000000000000..6615ceaf1c56c2b56cb261bc351f19a6ab791b42 --- /dev/null +++ b/node_modules/@mswjs/interceptors/lib/node/chunk-73NOP3T5.js.map @@ -0,0 +1 @@ +{"version":3,"sources":["../../src/glossary.ts"],"names":[],"mappings":";AAEO,IAAM,oBAAmC,OAAO,iBAAiB","sourcesContent":["import type { RequestController } from './RequestController'\n\nexport const IS_PATCHED_MODULE: unique symbol = Symbol('isPatchedModule')\n\n/**\n * @note Export `RequestController` as a type only.\n * It's never meant to be created in the userland.\n */\nexport type { RequestController }\n\nexport type RequestCredentials = 'omit' | 'include' | 'same-origin'\n\nexport type HttpRequestEventMap = {\n request: [\n args: {\n request: Request\n requestId: string\n controller: RequestController\n }\n ]\n response: [\n args: {\n response: Response\n isMockedResponse: boolean\n request: Request\n requestId: string\n }\n ]\n unhandledException: [\n args: {\n error: unknown\n request: Request\n requestId: string\n controller: RequestController\n }\n ]\n}\n"]} \ No newline at end of file diff --git a/node_modules/@mswjs/interceptors/lib/node/chunk-CTGTMEFD.mjs b/node_modules/@mswjs/interceptors/lib/node/chunk-CTGTMEFD.mjs new file mode 100644 index 0000000000000000000000000000000000000000..d9bb95584e2458f48df956eeb5215e1693b506e0 --- /dev/null +++ b/node_modules/@mswjs/interceptors/lib/node/chunk-CTGTMEFD.mjs @@ -0,0 +1,310 @@ +import { + hasConfigurableGlobal +} from "./chunk-TX5GBTFY.mjs"; +import { + IS_PATCHED_MODULE +} from "./chunk-6YM4PLBI.mjs"; +import { + RequestController, + emitAsync, + handleRequest +} from "./chunk-5KMS5CTP.mjs"; +import { + FetchResponse, + Interceptor, + createRequestId +} from "./chunk-I7HQIBT7.mjs"; + +// src/interceptors/fetch/index.ts +import { invariant } from "outvariant"; +import { DeferredPromise } from "@open-draft/deferred-promise"; + +// src/utils/canParseUrl.ts +function canParseUrl(url) { + try { + new URL(url); + return true; + } catch (_error) { + return false; + } +} + +// src/interceptors/fetch/utils/createNetworkError.ts +function createNetworkError(cause) { + return Object.assign(new TypeError("Failed to fetch"), { + cause + }); +} + +// src/interceptors/fetch/utils/followRedirect.ts +var REQUEST_BODY_HEADERS = [ + "content-encoding", + "content-language", + "content-location", + "content-type", + "content-length" +]; +var kRedirectCount = Symbol("kRedirectCount"); +async function followFetchRedirect(request, response) { + if (response.status !== 303 && request.body != null) { + return Promise.reject(createNetworkError()); + } + const requestUrl = new URL(request.url); + let locationUrl; + try { + locationUrl = new URL(response.headers.get("location"), request.url); + } catch (error) { + return Promise.reject(createNetworkError(error)); + } + if (!(locationUrl.protocol === "http:" || locationUrl.protocol === "https:")) { + return Promise.reject( + createNetworkError("URL scheme must be a HTTP(S) scheme") + ); + } + if (Reflect.get(request, kRedirectCount) > 20) { + return Promise.reject(createNetworkError("redirect count exceeded")); + } + Object.defineProperty(request, kRedirectCount, { + value: (Reflect.get(request, kRedirectCount) || 0) + 1 + }); + if (request.mode === "cors" && (locationUrl.username || locationUrl.password) && !sameOrigin(requestUrl, locationUrl)) { + return Promise.reject( + createNetworkError('cross origin not allowed for request mode "cors"') + ); + } + const requestInit = {}; + if ([301, 302].includes(response.status) && request.method === "POST" || response.status === 303 && !["HEAD", "GET"].includes(request.method)) { + requestInit.method = "GET"; + requestInit.body = null; + REQUEST_BODY_HEADERS.forEach((headerName) => { + request.headers.delete(headerName); + }); + } + if (!sameOrigin(requestUrl, locationUrl)) { + request.headers.delete("authorization"); + request.headers.delete("proxy-authorization"); + request.headers.delete("cookie"); + request.headers.delete("host"); + } + requestInit.headers = request.headers; + return fetch(new Request(locationUrl, requestInit)); +} +function sameOrigin(left, right) { + if (left.origin === right.origin && left.origin === "null") { + return true; + } + if (left.protocol === right.protocol && left.hostname === right.hostname && left.port === right.port) { + return true; + } + return false; +} + +// src/interceptors/fetch/utils/brotli-decompress.ts +import zlib from "zlib"; +var BrotliDecompressionStream = class extends TransformStream { + constructor() { + const decompress = zlib.createBrotliDecompress({ + flush: zlib.constants.BROTLI_OPERATION_FLUSH, + finishFlush: zlib.constants.BROTLI_OPERATION_FLUSH + }); + super({ + async transform(chunk, controller) { + const buffer = Buffer.from(chunk); + const decompressed = await new Promise((resolve, reject) => { + decompress.write(buffer, (error) => { + if (error) + reject(error); + }); + decompress.flush(); + decompress.once("data", (data) => resolve(data)); + decompress.once("error", (error) => reject(error)); + decompress.once("end", () => controller.terminate()); + }).catch((error) => { + controller.error(error); + }); + controller.enqueue(decompressed); + } + }); + } +}; + +// src/interceptors/fetch/utils/decompression.ts +var PipelineStream = class extends TransformStream { + constructor(transformStreams, ...strategies) { + super({}, ...strategies); + const readable = [super.readable, ...transformStreams].reduce( + (readable2, transform) => readable2.pipeThrough(transform) + ); + Object.defineProperty(this, "readable", { + get() { + return readable; + } + }); + } +}; +function parseContentEncoding(contentEncoding) { + return contentEncoding.toLowerCase().split(",").map((coding) => coding.trim()); +} +function createDecompressionStream(contentEncoding) { + if (contentEncoding === "") { + return null; + } + const codings = parseContentEncoding(contentEncoding); + if (codings.length === 0) { + return null; + } + const transformers = codings.reduceRight( + (transformers2, coding) => { + if (coding === "gzip" || coding === "x-gzip") { + return transformers2.concat(new DecompressionStream("gzip")); + } else if (coding === "deflate") { + return transformers2.concat(new DecompressionStream("deflate")); + } else if (coding === "br") { + return transformers2.concat(new BrotliDecompressionStream()); + } else { + transformers2.length = 0; + } + return transformers2; + }, + [] + ); + return new PipelineStream(transformers); +} +function decompressResponse(response) { + if (response.body === null) { + return null; + } + const decompressionStream = createDecompressionStream( + response.headers.get("content-encoding") || "" + ); + if (!decompressionStream) { + return null; + } + response.body.pipeTo(decompressionStream.writable); + return decompressionStream.readable; +} + +// src/interceptors/fetch/index.ts +var _FetchInterceptor = class extends Interceptor { + constructor() { + super(_FetchInterceptor.symbol); + } + checkEnvironment() { + return hasConfigurableGlobal("fetch"); + } + async setup() { + const pureFetch = globalThis.fetch; + invariant( + !pureFetch[IS_PATCHED_MODULE], + 'Failed to patch the "fetch" module: already patched.' + ); + globalThis.fetch = async (input, init) => { + const requestId = createRequestId(); + const resolvedInput = typeof input === "string" && typeof location !== "undefined" && !canParseUrl(input) ? new URL(input, location.origin) : input; + const request = new Request(resolvedInput, init); + const responsePromise = new DeferredPromise(); + const controller = new RequestController(request); + this.logger.info("[%s] %s", request.method, request.url); + this.logger.info("awaiting for the mocked response..."); + this.logger.info( + 'emitting the "request" event for %s listener(s)...', + this.emitter.listenerCount("request") + ); + const isRequestHandled = await handleRequest({ + request, + requestId, + emitter: this.emitter, + controller, + onResponse: async (rawResponse) => { + this.logger.info("received mocked response!", { + rawResponse + }); + const decompressedStream = decompressResponse(rawResponse); + const response = decompressedStream === null ? rawResponse : new FetchResponse(decompressedStream, rawResponse); + FetchResponse.setUrl(request.url, response); + if (FetchResponse.isRedirectResponse(response.status)) { + if (request.redirect === "error") { + responsePromise.reject(createNetworkError("unexpected redirect")); + return; + } + if (request.redirect === "follow") { + followFetchRedirect(request, response).then( + (response2) => { + responsePromise.resolve(response2); + }, + (reason) => { + responsePromise.reject(reason); + } + ); + return; + } + } + if (this.emitter.listenerCount("response") > 0) { + this.logger.info('emitting the "response" event...'); + await emitAsync(this.emitter, "response", { + // Clone the mocked response for the "response" event listener. + // This way, the listener can read the response and not lock its body + // for the actual fetch consumer. + response: response.clone(), + isMockedResponse: true, + request, + requestId + }); + } + responsePromise.resolve(response); + }, + onRequestError: (response) => { + this.logger.info("request has errored!", { response }); + responsePromise.reject(createNetworkError(response)); + }, + onError: (error) => { + this.logger.info("request has been aborted!", { error }); + responsePromise.reject(error); + } + }); + if (isRequestHandled) { + this.logger.info("request has been handled, returning mock promise..."); + return responsePromise; + } + this.logger.info( + "no mocked response received, performing request as-is..." + ); + return pureFetch(request).then(async (response) => { + this.logger.info("original fetch performed", response); + if (this.emitter.listenerCount("response") > 0) { + this.logger.info('emitting the "response" event...'); + const responseClone = response.clone(); + await emitAsync(this.emitter, "response", { + response: responseClone, + isMockedResponse: false, + request, + requestId + }); + } + return response; + }); + }; + Object.defineProperty(globalThis.fetch, IS_PATCHED_MODULE, { + enumerable: true, + configurable: true, + value: true + }); + this.subscriptions.push(() => { + Object.defineProperty(globalThis.fetch, IS_PATCHED_MODULE, { + value: void 0 + }); + globalThis.fetch = pureFetch; + this.logger.info( + 'restored native "globalThis.fetch"!', + globalThis.fetch.name + ); + }); + } +}; +var FetchInterceptor = _FetchInterceptor; +FetchInterceptor.symbol = Symbol("fetch"); + +export { + FetchInterceptor +}; +//# sourceMappingURL=chunk-CTGTMEFD.mjs.map \ No newline at end of file diff --git a/node_modules/@mswjs/interceptors/lib/node/chunk-CTGTMEFD.mjs.map b/node_modules/@mswjs/interceptors/lib/node/chunk-CTGTMEFD.mjs.map new file mode 100644 index 0000000000000000000000000000000000000000..0a272481e6c8b99774b51927609bf057d3bf54f8 --- /dev/null +++ b/node_modules/@mswjs/interceptors/lib/node/chunk-CTGTMEFD.mjs.map @@ -0,0 +1 @@ +{"version":3,"sources":["../../src/interceptors/fetch/index.ts","../../src/utils/canParseUrl.ts","../../src/interceptors/fetch/utils/createNetworkError.ts","../../src/interceptors/fetch/utils/followRedirect.ts","../../src/interceptors/fetch/utils/brotli-decompress.ts","../../src/interceptors/fetch/utils/decompression.ts"],"sourcesContent":["import { invariant } from 'outvariant'\nimport { DeferredPromise } from '@open-draft/deferred-promise'\nimport { HttpRequestEventMap, IS_PATCHED_MODULE } from '../../glossary'\nimport { Interceptor } from '../../Interceptor'\nimport { RequestController } from '../../RequestController'\nimport { emitAsync } from '../../utils/emitAsync'\nimport { handleRequest } from '../../utils/handleRequest'\nimport { canParseUrl } from '../../utils/canParseUrl'\nimport { createRequestId } from '../../createRequestId'\nimport { createNetworkError } from './utils/createNetworkError'\nimport { followFetchRedirect } from './utils/followRedirect'\nimport { decompressResponse } from './utils/decompression'\nimport { hasConfigurableGlobal } from '../../utils/hasConfigurableGlobal'\nimport { FetchResponse } from '../../utils/fetchUtils'\n\nexport class FetchInterceptor extends Interceptor {\n static symbol = Symbol('fetch')\n\n constructor() {\n super(FetchInterceptor.symbol)\n }\n\n protected checkEnvironment() {\n return hasConfigurableGlobal('fetch')\n }\n\n protected async setup() {\n const pureFetch = globalThis.fetch\n\n invariant(\n !(pureFetch as any)[IS_PATCHED_MODULE],\n 'Failed to patch the \"fetch\" module: already patched.'\n )\n\n globalThis.fetch = async (input, init) => {\n const requestId = createRequestId()\n\n /**\n * @note Resolve potentially relative request URL\n * against the present `location`. This is mainly\n * for native `fetch` in JSDOM.\n * @see https://github.com/mswjs/msw/issues/1625\n */\n const resolvedInput =\n typeof input === 'string' &&\n typeof location !== 'undefined' &&\n !canParseUrl(input)\n ? new URL(input, location.origin)\n : input\n\n const request = new Request(resolvedInput, init)\n const responsePromise = new DeferredPromise()\n const controller = new RequestController(request)\n\n this.logger.info('[%s] %s', request.method, request.url)\n this.logger.info('awaiting for the mocked response...')\n\n this.logger.info(\n 'emitting the \"request\" event for %s listener(s)...',\n this.emitter.listenerCount('request')\n )\n\n const isRequestHandled = await handleRequest({\n request,\n requestId,\n emitter: this.emitter,\n controller,\n onResponse: async (rawResponse) => {\n this.logger.info('received mocked response!', {\n rawResponse,\n })\n\n // Decompress the mocked response body, if applicable.\n const decompressedStream = decompressResponse(rawResponse)\n const response =\n decompressedStream === null\n ? rawResponse\n : new FetchResponse(decompressedStream, rawResponse)\n\n FetchResponse.setUrl(request.url, response)\n\n /**\n * Undici's handling of following redirect responses.\n * Treat the \"manual\" redirect mode as a regular mocked response.\n * This way, the client can manually follow the redirect it receives.\n * @see https://github.com/nodejs/undici/blob/a6dac3149c505b58d2e6d068b97f4dc993da55f0/lib/web/fetch/index.js#L1173\n */\n if (FetchResponse.isRedirectResponse(response.status)) {\n // Reject the request promise if its `redirect` is set to `error`\n // and it receives a mocked redirect response.\n if (request.redirect === 'error') {\n responsePromise.reject(createNetworkError('unexpected redirect'))\n return\n }\n\n if (request.redirect === 'follow') {\n followFetchRedirect(request, response).then(\n (response) => {\n responsePromise.resolve(response)\n },\n (reason) => {\n responsePromise.reject(reason)\n }\n )\n return\n }\n }\n\n if (this.emitter.listenerCount('response') > 0) {\n this.logger.info('emitting the \"response\" event...')\n\n // Await the response listeners to finish before resolving\n // the response promise. This ensures all your logic finishes\n // before the interceptor resolves the pending response.\n await emitAsync(this.emitter, 'response', {\n // Clone the mocked response for the \"response\" event listener.\n // This way, the listener can read the response and not lock its body\n // for the actual fetch consumer.\n response: response.clone(),\n isMockedResponse: true,\n request,\n requestId,\n })\n }\n\n responsePromise.resolve(response)\n },\n onRequestError: (response) => {\n this.logger.info('request has errored!', { response })\n responsePromise.reject(createNetworkError(response))\n },\n onError: (error) => {\n this.logger.info('request has been aborted!', { error })\n responsePromise.reject(error)\n },\n })\n\n if (isRequestHandled) {\n this.logger.info('request has been handled, returning mock promise...')\n return responsePromise\n }\n\n this.logger.info(\n 'no mocked response received, performing request as-is...'\n )\n\n return pureFetch(request).then(async (response) => {\n this.logger.info('original fetch performed', response)\n\n if (this.emitter.listenerCount('response') > 0) {\n this.logger.info('emitting the \"response\" event...')\n\n const responseClone = response.clone()\n\n await emitAsync(this.emitter, 'response', {\n response: responseClone,\n isMockedResponse: false,\n request,\n requestId,\n })\n }\n\n return response\n })\n }\n\n Object.defineProperty(globalThis.fetch, IS_PATCHED_MODULE, {\n enumerable: true,\n configurable: true,\n value: true,\n })\n\n this.subscriptions.push(() => {\n Object.defineProperty(globalThis.fetch, IS_PATCHED_MODULE, {\n value: undefined,\n })\n\n globalThis.fetch = pureFetch\n\n this.logger.info(\n 'restored native \"globalThis.fetch\"!',\n globalThis.fetch.name\n )\n })\n }\n}\n","/**\n * Returns a boolean indicating whether the given URL string\n * can be parsed into a `URL` instance.\n * A substitute for `URL.canParse()` for Node.js 18.\n */\nexport function canParseUrl(url: string): boolean {\n try {\n new URL(url)\n return true\n } catch (_error) {\n return false\n }\n}\n","export function createNetworkError(cause?: unknown) {\n return Object.assign(new TypeError('Failed to fetch'), {\n cause,\n })\n}\n","import { createNetworkError } from './createNetworkError'\n\nconst REQUEST_BODY_HEADERS = [\n 'content-encoding',\n 'content-language',\n 'content-location',\n 'content-type',\n 'content-length',\n]\n\nconst kRedirectCount = Symbol('kRedirectCount')\n\n/**\n * @see https://github.com/nodejs/undici/blob/a6dac3149c505b58d2e6d068b97f4dc993da55f0/lib/web/fetch/index.js#L1210\n */\nexport async function followFetchRedirect(\n request: Request,\n response: Response\n): Promise {\n if (response.status !== 303 && request.body != null) {\n return Promise.reject(createNetworkError())\n }\n\n const requestUrl = new URL(request.url)\n\n let locationUrl: URL\n try {\n // If the location is a relative URL, use the request URL as the base URL.\n locationUrl = new URL(response.headers.get('location')!, request.url) \n } catch (error) {\n return Promise.reject(createNetworkError(error))\n }\n\n if (\n !(locationUrl.protocol === 'http:' || locationUrl.protocol === 'https:')\n ) {\n return Promise.reject(\n createNetworkError('URL scheme must be a HTTP(S) scheme')\n )\n }\n\n if (Reflect.get(request, kRedirectCount) > 20) {\n return Promise.reject(createNetworkError('redirect count exceeded'))\n }\n\n Object.defineProperty(request, kRedirectCount, {\n value: (Reflect.get(request, kRedirectCount) || 0) + 1,\n })\n\n if (\n request.mode === 'cors' &&\n (locationUrl.username || locationUrl.password) &&\n !sameOrigin(requestUrl, locationUrl)\n ) {\n return Promise.reject(\n createNetworkError('cross origin not allowed for request mode \"cors\"')\n )\n }\n\n const requestInit: RequestInit = {}\n\n if (\n ([301, 302].includes(response.status) && request.method === 'POST') ||\n (response.status === 303 && !['HEAD', 'GET'].includes(request.method))\n ) {\n requestInit.method = 'GET'\n requestInit.body = null\n\n REQUEST_BODY_HEADERS.forEach((headerName) => {\n request.headers.delete(headerName)\n })\n }\n\n if (!sameOrigin(requestUrl, locationUrl)) {\n request.headers.delete('authorization')\n request.headers.delete('proxy-authorization')\n request.headers.delete('cookie')\n request.headers.delete('host')\n }\n\n /**\n * @note Undici \"safely\" extracts the request body.\n * I suspect we cannot dispatch this request again\n * since its body has been read and the stream is locked.\n */\n\n requestInit.headers = request.headers\n return fetch(new Request(locationUrl, requestInit))\n}\n\n/**\n * @see https://github.com/nodejs/undici/blob/a6dac3149c505b58d2e6d068b97f4dc993da55f0/lib/web/fetch/util.js#L761\n */\nfunction sameOrigin(left: URL, right: URL): boolean {\n if (left.origin === right.origin && left.origin === 'null') {\n return true\n }\n\n if (\n left.protocol === right.protocol &&\n left.hostname === right.hostname &&\n left.port === right.port\n ) {\n return true\n }\n\n return false\n}\n","import zlib from 'node:zlib'\n\nexport class BrotliDecompressionStream extends TransformStream {\n constructor() {\n const decompress = zlib.createBrotliDecompress({\n flush: zlib.constants.BROTLI_OPERATION_FLUSH,\n finishFlush: zlib.constants.BROTLI_OPERATION_FLUSH,\n })\n\n super({\n async transform(chunk, controller) {\n const buffer = Buffer.from(chunk)\n\n const decompressed = await new Promise((resolve, reject) => {\n decompress.write(buffer, (error) => {\n if (error) reject(error)\n })\n\n decompress.flush()\n decompress.once('data', (data) => resolve(data))\n decompress.once('error', (error) => reject(error))\n decompress.once('end', () => controller.terminate())\n }).catch((error) => {\n controller.error(error)\n })\n\n controller.enqueue(decompressed)\n },\n })\n }\n}\n","// Import from an internal alias that resolves to different modules\n// depending on the environment. This way, we can keep the fetch interceptor\n// intact while using different strategies for Brotli decompression.\nimport { BrotliDecompressionStream } from 'internal:brotli-decompress'\n\nclass PipelineStream extends TransformStream {\n constructor(\n transformStreams: Array,\n ...strategies: Array\n ) {\n super({}, ...strategies)\n\n const readable = [super.readable as any, ...transformStreams].reduce(\n (readable, transform) => readable.pipeThrough(transform)\n )\n\n Object.defineProperty(this, 'readable', {\n get() {\n return readable\n },\n })\n }\n}\n\nexport function parseContentEncoding(contentEncoding: string): Array {\n return contentEncoding\n .toLowerCase()\n .split(',')\n .map((coding) => coding.trim())\n}\n\nfunction createDecompressionStream(\n contentEncoding: string\n): TransformStream | null {\n if (contentEncoding === '') {\n return null\n }\n\n const codings = parseContentEncoding(contentEncoding)\n\n if (codings.length === 0) {\n return null\n }\n\n const transformers = codings.reduceRight>(\n (transformers, coding) => {\n if (coding === 'gzip' || coding === 'x-gzip') {\n return transformers.concat(new DecompressionStream('gzip'))\n } else if (coding === 'deflate') {\n return transformers.concat(new DecompressionStream('deflate'))\n } else if (coding === 'br') {\n return transformers.concat(new BrotliDecompressionStream())\n } else {\n transformers.length = 0\n }\n\n return transformers\n },\n []\n )\n\n return new PipelineStream(transformers)\n}\n\nexport function decompressResponse(\n response: Response\n): ReadableStream | null {\n if (response.body === null) {\n return null\n }\n\n const decompressionStream = createDecompressionStream(\n response.headers.get('content-encoding') || ''\n )\n\n if (!decompressionStream) {\n return null\n }\n\n // Use `pipeTo` and return the decompression stream's readable\n // instead of `pipeThrough` because that will lock the original\n // response stream, making it unusable as the input to Response.\n response.body.pipeTo(decompressionStream.writable)\n return decompressionStream.readable\n}\n"],"mappings":"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","names":["readable","transformers","response"]} \ No newline at end of file diff --git a/node_modules/@mswjs/interceptors/lib/node/chunk-FWJSC2QD.mjs b/node_modules/@mswjs/interceptors/lib/node/chunk-FWJSC2QD.mjs new file mode 100644 index 0000000000000000000000000000000000000000..b2558e1ee9c25b8811049c9b2a8bb67ede0b1652 --- /dev/null +++ b/node_modules/@mswjs/interceptors/lib/node/chunk-FWJSC2QD.mjs @@ -0,0 +1,1064 @@ +import { + RequestController, + createServerErrorResponse, + emitAsync, + handleRequest, + isPropertyAccessible +} from "./chunk-5KMS5CTP.mjs"; +import { + FetchResponse, + INTERNAL_REQUEST_ID_HEADER_NAME, + Interceptor, + createRequestId +} from "./chunk-I7HQIBT7.mjs"; + +// src/interceptors/ClientRequest/index.ts +import http2 from "http"; +import https2 from "https"; + +// src/interceptors/ClientRequest/MockHttpSocket.ts +import net2 from "net"; +import { + HTTPParser +} from "_http_common"; +import { STATUS_CODES, IncomingMessage, ServerResponse } from "http"; +import { Readable } from "stream"; +import { invariant } from "outvariant"; + +// src/interceptors/Socket/MockSocket.ts +import net from "net"; + +// src/interceptors/Socket/utils/normalizeSocketWriteArgs.ts +function normalizeSocketWriteArgs(args) { + const normalized = [args[0], void 0, void 0]; + if (typeof args[1] === "string") { + normalized[1] = args[1]; + } else if (typeof args[1] === "function") { + normalized[2] = args[1]; + } + if (typeof args[2] === "function") { + normalized[2] = args[2]; + } + return normalized; +} + +// src/interceptors/Socket/MockSocket.ts +var MockSocket = class extends net.Socket { + constructor(options) { + super(); + this.options = options; + this.connecting = false; + this.connect(); + this._final = (callback) => { + callback(null); + }; + } + connect() { + this.connecting = true; + return this; + } + write(...args) { + const [chunk, encoding, callback] = normalizeSocketWriteArgs( + args + ); + this.options.write(chunk, encoding, callback); + return true; + } + end(...args) { + const [chunk, encoding, callback] = normalizeSocketWriteArgs( + args + ); + this.options.write(chunk, encoding, callback); + return super.end.apply(this, args); + } + push(chunk, encoding) { + this.options.read(chunk, encoding); + return super.push(chunk, encoding); + } +}; + +// src/interceptors/Socket/utils/baseUrlFromConnectionOptions.ts +function baseUrlFromConnectionOptions(options) { + if ("href" in options) { + return new URL(options.href); + } + const protocol = options.port === 443 ? "https:" : "http:"; + const host = options.host; + const url = new URL(`${protocol}//${host}`); + if (options.port) { + url.port = options.port.toString(); + } + if (options.path) { + url.pathname = options.path; + } + if (options.auth) { + const [username, password] = options.auth.split(":"); + url.username = username; + url.password = password; + } + return url; +} + +// src/interceptors/ClientRequest/utils/recordRawHeaders.ts +var kRawHeaders = Symbol("kRawHeaders"); +var kRestorePatches = Symbol("kRestorePatches"); +function recordRawHeader(headers, args, behavior) { + ensureRawHeadersSymbol(headers, []); + const rawHeaders = Reflect.get(headers, kRawHeaders); + if (behavior === "set") { + for (let index = rawHeaders.length - 1; index >= 0; index--) { + if (rawHeaders[index][0].toLowerCase() === args[0].toLowerCase()) { + rawHeaders.splice(index, 1); + } + } + } + rawHeaders.push(args); +} +function ensureRawHeadersSymbol(headers, rawHeaders) { + if (Reflect.has(headers, kRawHeaders)) { + return; + } + defineRawHeadersSymbol(headers, rawHeaders); +} +function defineRawHeadersSymbol(headers, rawHeaders) { + Object.defineProperty(headers, kRawHeaders, { + value: rawHeaders, + enumerable: false, + // Mark the symbol as configurable so its value can be overridden. + // Overrides happen when merging raw headers from multiple sources. + // E.g. new Request(new Request(url, { headers }), { headers }) + configurable: true + }); +} +function recordRawFetchHeaders() { + if (Reflect.get(Headers, kRestorePatches)) { + return Reflect.get(Headers, kRestorePatches); + } + const { + Headers: OriginalHeaders, + Request: OriginalRequest, + Response: OriginalResponse + } = globalThis; + const { set, append, delete: headersDeleteMethod } = Headers.prototype; + Object.defineProperty(Headers, kRestorePatches, { + value: () => { + Headers.prototype.set = set; + Headers.prototype.append = append; + Headers.prototype.delete = headersDeleteMethod; + globalThis.Headers = OriginalHeaders; + globalThis.Request = OriginalRequest; + globalThis.Response = OriginalResponse; + Reflect.deleteProperty(Headers, kRestorePatches); + }, + enumerable: false, + /** + * @note Mark this property as configurable + * so we can delete it using `Reflect.delete` during cleanup. + */ + configurable: true + }); + Object.defineProperty(globalThis, "Headers", { + enumerable: true, + writable: true, + value: new Proxy(Headers, { + construct(target, args, newTarget) { + const headersInit = args[0] || []; + if (headersInit instanceof Headers && Reflect.has(headersInit, kRawHeaders)) { + const headers2 = Reflect.construct( + target, + [Reflect.get(headersInit, kRawHeaders)], + newTarget + ); + ensureRawHeadersSymbol(headers2, [ + /** + * @note Spread the retrieved headers to clone them. + * This prevents multiple Headers instances from pointing + * at the same internal "rawHeaders" array. + */ + ...Reflect.get(headersInit, kRawHeaders) + ]); + return headers2; + } + const headers = Reflect.construct(target, args, newTarget); + if (!Reflect.has(headers, kRawHeaders)) { + const rawHeadersInit = Array.isArray(headersInit) ? headersInit : Object.entries(headersInit); + ensureRawHeadersSymbol(headers, rawHeadersInit); + } + return headers; + } + }) + }); + Headers.prototype.set = new Proxy(Headers.prototype.set, { + apply(target, thisArg, args) { + recordRawHeader(thisArg, args, "set"); + return Reflect.apply(target, thisArg, args); + } + }); + Headers.prototype.append = new Proxy(Headers.prototype.append, { + apply(target, thisArg, args) { + recordRawHeader(thisArg, args, "append"); + return Reflect.apply(target, thisArg, args); + } + }); + Headers.prototype.delete = new Proxy(Headers.prototype.delete, { + apply(target, thisArg, args) { + const rawHeaders = Reflect.get(thisArg, kRawHeaders); + if (rawHeaders) { + for (let index = rawHeaders.length - 1; index >= 0; index--) { + if (rawHeaders[index][0].toLowerCase() === args[0].toLowerCase()) { + rawHeaders.splice(index, 1); + } + } + } + return Reflect.apply(target, thisArg, args); + } + }); + Object.defineProperty(globalThis, "Request", { + enumerable: true, + writable: true, + value: new Proxy(Request, { + construct(target, args, newTarget) { + const request = Reflect.construct(target, args, newTarget); + const inferredRawHeaders = []; + if (typeof args[0] === "object" && args[0].headers != null) { + inferredRawHeaders.push(...inferRawHeaders(args[0].headers)); + } + if (typeof args[1] === "object" && args[1].headers != null) { + inferredRawHeaders.push(...inferRawHeaders(args[1].headers)); + } + if (inferredRawHeaders.length > 0) { + ensureRawHeadersSymbol(request.headers, inferredRawHeaders); + } + return request; + } + }) + }); + Object.defineProperty(globalThis, "Response", { + enumerable: true, + writable: true, + value: new Proxy(Response, { + construct(target, args, newTarget) { + const response = Reflect.construct(target, args, newTarget); + if (typeof args[1] === "object" && args[1].headers != null) { + ensureRawHeadersSymbol( + response.headers, + inferRawHeaders(args[1].headers) + ); + } + return response; + } + }) + }); +} +function restoreHeadersPrototype() { + if (!Reflect.get(Headers, kRestorePatches)) { + return; + } + Reflect.get(Headers, kRestorePatches)(); +} +function getRawFetchHeaders(headers) { + if (!Reflect.has(headers, kRawHeaders)) { + return Array.from(headers.entries()); + } + const rawHeaders = Reflect.get(headers, kRawHeaders); + return rawHeaders.length > 0 ? rawHeaders : Array.from(headers.entries()); +} +function inferRawHeaders(headers) { + if (headers instanceof Headers) { + return Reflect.get(headers, kRawHeaders) || []; + } + return Reflect.get(new Headers(headers), kRawHeaders); +} + +// src/interceptors/ClientRequest/MockHttpSocket.ts +var kRequestId = Symbol("kRequestId"); +var MockHttpSocket = class extends MockSocket { + constructor(options) { + super({ + write: (chunk, encoding, callback) => { + var _a; + if (this.socketState !== "passthrough") { + this.writeBuffer.push([chunk, encoding, callback]); + } + if (chunk) { + if (this.socketState === "passthrough") { + (_a = this.originalSocket) == null ? void 0 : _a.write(chunk, encoding, callback); + } + this.requestParser.execute( + Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk, encoding) + ); + } + }, + read: (chunk) => { + if (chunk !== null) { + this.responseParser.execute( + Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk) + ); + } + } + }); + this.writeBuffer = []; + this.socketState = "unknown"; + this.onRequestStart = (versionMajor, versionMinor, rawHeaders, _, path, __, ___, ____, shouldKeepAlive) => { + var _a; + this.shouldKeepAlive = shouldKeepAlive; + const url = new URL(path, this.baseUrl); + const method = ((_a = this.connectionOptions.method) == null ? void 0 : _a.toUpperCase()) || "GET"; + const headers = FetchResponse.parseRawHeaders(rawHeaders); + const canHaveBody = method !== "GET" && method !== "HEAD"; + if (url.username || url.password) { + if (!headers.has("authorization")) { + headers.set("authorization", `Basic ${url.username}:${url.password}`); + } + url.username = ""; + url.password = ""; + } + if (canHaveBody) { + this.requestStream = new Readable({ + /** + * @note Provide the `read()` method so a `Readable` could be + * used as the actual request body (the stream calls "read()"). + * We control the queue in the onRequestBody/End functions. + */ + read: () => { + this.flushWriteBuffer(); + } + }); + } + const requestId = createRequestId(); + this.request = new Request(url, { + method, + headers, + credentials: "same-origin", + // @ts-expect-error Undocumented Fetch property. + duplex: canHaveBody ? "half" : void 0, + body: canHaveBody ? Readable.toWeb(this.requestStream) : null + }); + Reflect.set(this.request, kRequestId, requestId); + if (this.request.headers.has(INTERNAL_REQUEST_ID_HEADER_NAME)) { + this.passthrough(); + return; + } + this.onRequest({ + requestId, + request: this.request, + socket: this + }); + }; + this.onResponseStart = (versionMajor, versionMinor, rawHeaders, method, url, status, statusText) => { + const headers = FetchResponse.parseRawHeaders(rawHeaders); + const response = new FetchResponse( + /** + * @note The Fetch API response instance exposed to the consumer + * is created over the response stream of the HTTP parser. It is NOT + * related to the Socket instance. This way, you can read response body + * in response listener while the Socket instance delays the emission + * of "end" and other events until those response listeners are finished. + */ + FetchResponse.isResponseWithBody(status) ? Readable.toWeb( + this.responseStream = new Readable({ read() { + } }) + ) : null, + { + url, + status, + statusText, + headers + } + ); + invariant( + this.request, + "Failed to handle a response: request does not exist" + ); + if (this.request.headers.has(INTERNAL_REQUEST_ID_HEADER_NAME)) { + return; + } + this.responseListenersPromise = this.onResponse({ + response, + isMockedResponse: this.socketState === "mock", + requestId: Reflect.get(this.request, kRequestId), + request: this.request, + socket: this + }); + }; + this.connectionOptions = options.connectionOptions; + this.createConnection = options.createConnection; + this.onRequest = options.onRequest; + this.onResponse = options.onResponse; + this.baseUrl = baseUrlFromConnectionOptions(this.connectionOptions); + this.requestParser = new HTTPParser(); + this.requestParser.initialize(HTTPParser.REQUEST, {}); + this.requestParser[HTTPParser.kOnHeadersComplete] = this.onRequestStart.bind(this); + this.requestParser[HTTPParser.kOnBody] = this.onRequestBody.bind(this); + this.requestParser[HTTPParser.kOnMessageComplete] = this.onRequestEnd.bind(this); + this.responseParser = new HTTPParser(); + this.responseParser.initialize(HTTPParser.RESPONSE, {}); + this.responseParser[HTTPParser.kOnHeadersComplete] = this.onResponseStart.bind(this); + this.responseParser[HTTPParser.kOnBody] = this.onResponseBody.bind(this); + this.responseParser[HTTPParser.kOnMessageComplete] = this.onResponseEnd.bind(this); + this.once("finish", () => this.requestParser.free()); + if (this.baseUrl.protocol === "https:") { + Reflect.set(this, "encrypted", true); + Reflect.set(this, "authorized", false); + Reflect.set(this, "getProtocol", () => "TLSv1.3"); + Reflect.set(this, "getSession", () => void 0); + Reflect.set(this, "isSessionReused", () => false); + } + } + emit(event, ...args) { + const emitEvent = super.emit.bind(this, event, ...args); + if (this.responseListenersPromise) { + this.responseListenersPromise.finally(emitEvent); + return this.listenerCount(event) > 0; + } + return emitEvent(); + } + destroy(error) { + this.responseParser.free(); + if (error) { + this.emit("error", error); + } + return super.destroy(error); + } + /** + * Establish this Socket connection as-is and pipe + * its data/events through this Socket. + */ + passthrough() { + this.socketState = "passthrough"; + if (this.destroyed) { + return; + } + const socket = this.createConnection(); + this.originalSocket = socket; + this.once("error", (error) => { + socket.destroy(error); + }); + this.address = socket.address.bind(socket); + let writeArgs; + let headersWritten = false; + while (writeArgs = this.writeBuffer.shift()) { + if (writeArgs !== void 0) { + if (!headersWritten) { + const [chunk, encoding, callback] = writeArgs; + const chunkString = chunk.toString(); + const chunkBeforeRequestHeaders = chunkString.slice( + 0, + chunkString.indexOf("\r\n") + 2 + ); + const chunkAfterRequestHeaders = chunkString.slice( + chunk.indexOf("\r\n\r\n") + ); + const rawRequestHeaders = getRawFetchHeaders(this.request.headers); + const requestHeadersString = rawRequestHeaders.filter(([name]) => { + return name.toLowerCase() !== INTERNAL_REQUEST_ID_HEADER_NAME; + }).map(([name, value]) => `${name}: ${value}`).join("\r\n"); + const headersChunk = `${chunkBeforeRequestHeaders}${requestHeadersString}${chunkAfterRequestHeaders}`; + socket.write(headersChunk, encoding, callback); + headersWritten = true; + continue; + } + socket.write(...writeArgs); + } + } + if (Reflect.get(socket, "encrypted")) { + const tlsProperties = [ + "encrypted", + "authorized", + "getProtocol", + "getSession", + "isSessionReused" + ]; + tlsProperties.forEach((propertyName) => { + Object.defineProperty(this, propertyName, { + enumerable: true, + get: () => { + const value = Reflect.get(socket, propertyName); + return typeof value === "function" ? value.bind(socket) : value; + } + }); + }); + } + socket.on("lookup", (...args) => this.emit("lookup", ...args)).on("connect", () => { + this.connecting = socket.connecting; + this.emit("connect"); + }).on("secureConnect", () => this.emit("secureConnect")).on("secure", () => this.emit("secure")).on("session", (session) => this.emit("session", session)).on("ready", () => this.emit("ready")).on("drain", () => this.emit("drain")).on("data", (chunk) => { + this.push(chunk); + }).on("error", (error) => { + Reflect.set(this, "_hadError", Reflect.get(socket, "_hadError")); + this.emit("error", error); + }).on("resume", () => this.emit("resume")).on("timeout", () => this.emit("timeout")).on("prefinish", () => this.emit("prefinish")).on("finish", () => this.emit("finish")).on("close", (hadError) => this.emit("close", hadError)).on("end", () => this.emit("end")); + } + /** + * Convert the given Fetch API `Response` instance to an + * HTTP message and push it to the socket. + */ + async respondWith(response) { + var _a; + if (this.destroyed) { + return; + } + if (isPropertyAccessible(response, "type") && response.type === "error") { + this.errorWith(new TypeError("Network error")); + return; + } + this.mockConnect(); + this.socketState = "mock"; + this.flushWriteBuffer(); + const serverResponse = new ServerResponse(new IncomingMessage(this)); + serverResponse.assignSocket( + new MockSocket({ + write: (chunk, encoding, callback) => { + this.push(chunk, encoding); + callback == null ? void 0 : callback(); + }, + read() { + } + }) + ); + serverResponse.removeHeader("connection"); + serverResponse.removeHeader("date"); + const rawResponseHeaders = getRawFetchHeaders(response.headers); + serverResponse.writeHead( + response.status, + response.statusText || STATUS_CODES[response.status], + rawResponseHeaders + ); + this.once("error", () => { + serverResponse.destroy(); + }); + if (response.body) { + try { + const reader = response.body.getReader(); + while (true) { + const { done, value } = await reader.read(); + if (done) { + serverResponse.end(); + break; + } + serverResponse.write(value); + } + } catch (error) { + this.respondWith(createServerErrorResponse(error)); + return; + } + } else { + serverResponse.end(); + } + if (!this.shouldKeepAlive) { + this.emit("readable"); + (_a = this.responseStream) == null ? void 0 : _a.push(null); + this.push(null); + } + } + /** + * Close this socket connection with the given error. + */ + errorWith(error) { + this.destroy(error); + } + mockConnect() { + this.connecting = false; + const isIPv6 = net2.isIPv6(this.connectionOptions.hostname) || this.connectionOptions.family === 6; + const addressInfo = { + address: isIPv6 ? "::1" : "127.0.0.1", + family: isIPv6 ? "IPv6" : "IPv4", + port: this.connectionOptions.port + }; + this.address = () => addressInfo; + this.emit( + "lookup", + null, + addressInfo.address, + addressInfo.family === "IPv6" ? 6 : 4, + this.connectionOptions.host + ); + this.emit("connect"); + this.emit("ready"); + if (this.baseUrl.protocol === "https:") { + this.emit("secure"); + this.emit("secureConnect"); + this.emit( + "session", + this.connectionOptions.session || Buffer.from("mock-session-renegotiate") + ); + this.emit("session", Buffer.from("mock-session-resume")); + } + } + flushWriteBuffer() { + for (const writeCall of this.writeBuffer) { + if (typeof writeCall[2] === "function") { + writeCall[2](); + writeCall[2] = void 0; + } + } + } + onRequestBody(chunk) { + invariant( + this.requestStream, + "Failed to write to a request stream: stream does not exist" + ); + this.requestStream.push(chunk); + } + onRequestEnd() { + if (this.requestStream) { + this.requestStream.push(null); + } + } + onResponseBody(chunk) { + invariant( + this.responseStream, + "Failed to write to a response stream: stream does not exist" + ); + this.responseStream.push(chunk); + } + onResponseEnd() { + if (this.responseStream) { + this.responseStream.push(null); + } + } +}; + +// src/interceptors/ClientRequest/agents.ts +import http from "http"; +import https from "https"; +var MockAgent = class extends http.Agent { + constructor(options) { + super(); + this.customAgent = options.customAgent; + this.onRequest = options.onRequest; + this.onResponse = options.onResponse; + } + createConnection(options, callback) { + const createConnection = this.customAgent instanceof http.Agent ? this.customAgent.createConnection : super.createConnection; + const createConnectionOptions = this.customAgent instanceof http.Agent ? { + ...options, + ...this.customAgent.options + } : options; + const socket = new MockHttpSocket({ + connectionOptions: options, + createConnection: createConnection.bind( + this.customAgent || this, + createConnectionOptions, + callback + ), + onRequest: this.onRequest.bind(this), + onResponse: this.onResponse.bind(this) + }); + return socket; + } +}; +var MockHttpsAgent = class extends https.Agent { + constructor(options) { + super(); + this.customAgent = options.customAgent; + this.onRequest = options.onRequest; + this.onResponse = options.onResponse; + } + createConnection(options, callback) { + const createConnection = this.customAgent instanceof https.Agent ? this.customAgent.createConnection : super.createConnection; + const createConnectionOptions = this.customAgent instanceof https.Agent ? { + ...options, + ...this.customAgent.options + } : options; + const socket = new MockHttpSocket({ + connectionOptions: options, + createConnection: createConnection.bind( + this.customAgent || this, + createConnectionOptions, + callback + ), + onRequest: this.onRequest.bind(this), + onResponse: this.onResponse.bind(this) + }); + return socket; + } +}; + +// src/interceptors/ClientRequest/utils/normalizeClientRequestArgs.ts +import { urlToHttpOptions } from "url"; +import { + Agent as HttpAgent, + globalAgent as httpGlobalAgent +} from "http"; +import { + Agent as HttpsAgent, + globalAgent as httpsGlobalAgent +} from "https"; +import { + URL as URL2, + parse as parseUrl +} from "url"; +import { Logger as Logger3 } from "@open-draft/logger"; + +// src/utils/getUrlByRequestOptions.ts +import { Agent } from "http"; +import { Logger } from "@open-draft/logger"; +var logger = new Logger("utils getUrlByRequestOptions"); +var DEFAULT_PATH = "/"; +var DEFAULT_PROTOCOL = "http:"; +var DEFAULT_HOSTNAME = "localhost"; +var SSL_PORT = 443; +function getAgent(options) { + return options.agent instanceof Agent ? options.agent : void 0; +} +function getProtocolByRequestOptions(options) { + var _a; + if (options.protocol) { + return options.protocol; + } + const agent = getAgent(options); + const agentProtocol = agent == null ? void 0 : agent.protocol; + if (agentProtocol) { + return agentProtocol; + } + const port = getPortByRequestOptions(options); + const isSecureRequest = options.cert || port === SSL_PORT; + return isSecureRequest ? "https:" : ((_a = options.uri) == null ? void 0 : _a.protocol) || DEFAULT_PROTOCOL; +} +function getPortByRequestOptions(options) { + if (options.port) { + return Number(options.port); + } + const agent = getAgent(options); + if (agent == null ? void 0 : agent.options.port) { + return Number(agent.options.port); + } + if (agent == null ? void 0 : agent.defaultPort) { + return Number(agent.defaultPort); + } + return void 0; +} +function getAuthByRequestOptions(options) { + if (options.auth) { + const [username, password] = options.auth.split(":"); + return { username, password }; + } +} +function isRawIPv6Address(host) { + return host.includes(":") && !host.startsWith("[") && !host.endsWith("]"); +} +function getHostname(options) { + let host = options.hostname || options.host; + if (host) { + if (isRawIPv6Address(host)) { + host = `[${host}]`; + } + return new URL(`http://${host}`).hostname; + } + return DEFAULT_HOSTNAME; +} +function getUrlByRequestOptions(options) { + logger.info("request options", options); + if (options.uri) { + logger.info( + 'constructing url from explicitly provided "options.uri": %s', + options.uri + ); + return new URL(options.uri.href); + } + logger.info("figuring out url from request options..."); + const protocol = getProtocolByRequestOptions(options); + logger.info("protocol", protocol); + const port = getPortByRequestOptions(options); + logger.info("port", port); + const hostname = getHostname(options); + logger.info("hostname", hostname); + const path = options.path || DEFAULT_PATH; + logger.info("path", path); + const credentials = getAuthByRequestOptions(options); + logger.info("credentials", credentials); + const authString = credentials ? `${credentials.username}:${credentials.password}@` : ""; + logger.info("auth string:", authString); + const portString = typeof port !== "undefined" ? `:${port}` : ""; + const url = new URL(`${protocol}//${hostname}${portString}${path}`); + url.username = (credentials == null ? void 0 : credentials.username) || ""; + url.password = (credentials == null ? void 0 : credentials.password) || ""; + logger.info("created url:", url); + return url; +} + +// src/utils/cloneObject.ts +import { Logger as Logger2 } from "@open-draft/logger"; +var logger2 = new Logger2("cloneObject"); +function isPlainObject(obj) { + var _a; + logger2.info("is plain object?", obj); + if (obj == null || !((_a = obj.constructor) == null ? void 0 : _a.name)) { + logger2.info("given object is undefined, not a plain object..."); + return false; + } + logger2.info("checking the object constructor:", obj.constructor.name); + return obj.constructor.name === "Object"; +} +function cloneObject(obj) { + logger2.info("cloning object:", obj); + const enumerableProperties = Object.entries(obj).reduce( + (acc, [key, value]) => { + logger2.info("analyzing key-value pair:", key, value); + acc[key] = isPlainObject(value) ? cloneObject(value) : value; + return acc; + }, + {} + ); + return isPlainObject(obj) ? enumerableProperties : Object.assign(Object.getPrototypeOf(obj), enumerableProperties); +} + +// src/utils/isObject.ts +function isObject(value, loose = false) { + return loose ? Object.prototype.toString.call(value).startsWith("[object ") : Object.prototype.toString.call(value) === "[object Object]"; +} + +// src/interceptors/ClientRequest/utils/normalizeClientRequestArgs.ts +var logger3 = new Logger3("http normalizeClientRequestArgs"); +function resolveRequestOptions(args, url) { + if (typeof args[1] === "undefined" || typeof args[1] === "function") { + logger3.info("request options not provided, deriving from the url", url); + return urlToHttpOptions(url); + } + if (args[1]) { + logger3.info("has custom RequestOptions!", args[1]); + const requestOptionsFromUrl = urlToHttpOptions(url); + logger3.info("derived RequestOptions from the URL:", requestOptionsFromUrl); + logger3.info("cloning RequestOptions..."); + const clonedRequestOptions = cloneObject(args[1]); + logger3.info("successfully cloned RequestOptions!", clonedRequestOptions); + return { + ...requestOptionsFromUrl, + ...clonedRequestOptions + }; + } + logger3.info("using an empty object as request options"); + return {}; +} +function overrideUrlByRequestOptions(url, options) { + url.host = options.host || url.host; + url.hostname = options.hostname || url.hostname; + url.port = options.port ? options.port.toString() : url.port; + if (options.path) { + const parsedOptionsPath = parseUrl(options.path, false); + url.pathname = parsedOptionsPath.pathname || ""; + url.search = parsedOptionsPath.search || ""; + } + return url; +} +function resolveCallback(args) { + return typeof args[1] === "function" ? args[1] : args[2]; +} +function normalizeClientRequestArgs(defaultProtocol, args) { + let url; + let options; + let callback; + logger3.info("arguments", args); + logger3.info("using default protocol:", defaultProtocol); + if (args.length === 0) { + const url2 = new URL2("http://localhost"); + const options2 = resolveRequestOptions(args, url2); + return [url2, options2]; + } + if (typeof args[0] === "string") { + logger3.info("first argument is a location string:", args[0]); + url = new URL2(args[0]); + logger3.info("created a url:", url); + const requestOptionsFromUrl = urlToHttpOptions(url); + logger3.info("request options from url:", requestOptionsFromUrl); + options = resolveRequestOptions(args, url); + logger3.info("resolved request options:", options); + callback = resolveCallback(args); + } else if (args[0] instanceof URL2) { + url = args[0]; + logger3.info("first argument is a URL:", url); + if (typeof args[1] !== "undefined" && isObject(args[1])) { + url = overrideUrlByRequestOptions(url, args[1]); + } + options = resolveRequestOptions(args, url); + logger3.info("derived request options:", options); + callback = resolveCallback(args); + } else if ("hash" in args[0] && !("method" in args[0])) { + const [legacyUrl] = args; + logger3.info("first argument is a legacy URL:", legacyUrl); + if (legacyUrl.hostname === null) { + logger3.info("given legacy URL is relative (no hostname)"); + return isObject(args[1]) ? normalizeClientRequestArgs(defaultProtocol, [ + { path: legacyUrl.path, ...args[1] }, + args[2] + ]) : normalizeClientRequestArgs(defaultProtocol, [ + { path: legacyUrl.path }, + args[1] + ]); + } + logger3.info("given legacy url is absolute"); + const resolvedUrl = new URL2(legacyUrl.href); + return args[1] === void 0 ? normalizeClientRequestArgs(defaultProtocol, [resolvedUrl]) : typeof args[1] === "function" ? normalizeClientRequestArgs(defaultProtocol, [resolvedUrl, args[1]]) : normalizeClientRequestArgs(defaultProtocol, [ + resolvedUrl, + args[1], + args[2] + ]); + } else if (isObject(args[0])) { + options = { ...args[0] }; + logger3.info("first argument is RequestOptions:", options); + options.protocol = options.protocol || defaultProtocol; + logger3.info("normalized request options:", options); + url = getUrlByRequestOptions(options); + logger3.info("created a URL from RequestOptions:", url.href); + callback = resolveCallback(args); + } else { + throw new Error( + `Failed to construct ClientRequest with these parameters: ${args}` + ); + } + options.protocol = options.protocol || url.protocol; + options.method = options.method || "GET"; + if (typeof options.agent === "undefined") { + const agent = options.protocol === "https:" ? new HttpsAgent({ + // Any other value other than false is considered as true, so we don't add this property if undefined. + ..."rejectUnauthorized" in options && { + rejectUnauthorized: options.rejectUnauthorized + } + }) : new HttpAgent(); + options.agent = agent; + logger3.info("resolved fallback agent:", agent); + } + if (!options._defaultAgent) { + logger3.info( + 'has no default agent, setting the default agent for "%s"', + options.protocol + ); + options._defaultAgent = options.protocol === "https:" ? httpsGlobalAgent : httpGlobalAgent; + } + logger3.info("successfully resolved url:", url.href); + logger3.info("successfully resolved options:", options); + logger3.info("successfully resolved callback:", callback); + if (!(url instanceof URL2)) { + url = url.toString(); + } + return [url, options, callback]; +} + +// src/interceptors/ClientRequest/index.ts +var _ClientRequestInterceptor = class extends Interceptor { + constructor() { + super(_ClientRequestInterceptor.symbol); + this.onRequest = async ({ + request, + socket + }) => { + const requestId = Reflect.get(request, kRequestId); + const controller = new RequestController(request); + const isRequestHandled = await handleRequest({ + request, + requestId, + controller, + emitter: this.emitter, + onResponse: (response) => { + socket.respondWith(response); + }, + onRequestError: (response) => { + socket.respondWith(response); + }, + onError: (error) => { + if (error instanceof Error) { + socket.errorWith(error); + } + } + }); + if (!isRequestHandled) { + return socket.passthrough(); + } + }; + this.onResponse = async ({ + requestId, + request, + response, + isMockedResponse + }) => { + return emitAsync(this.emitter, "response", { + requestId, + request, + response, + isMockedResponse + }); + }; + } + setup() { + const { get: originalGet, request: originalRequest } = http2; + const { get: originalHttpsGet, request: originalHttpsRequest } = https2; + const onRequest = this.onRequest.bind(this); + const onResponse = this.onResponse.bind(this); + http2.request = new Proxy(http2.request, { + apply: (target, thisArg, args) => { + const [url, options, callback] = normalizeClientRequestArgs( + "http:", + args + ); + const mockAgent = new MockAgent({ + customAgent: options.agent, + onRequest, + onResponse + }); + options.agent = mockAgent; + return Reflect.apply(target, thisArg, [url, options, callback]); + } + }); + http2.get = new Proxy(http2.get, { + apply: (target, thisArg, args) => { + const [url, options, callback] = normalizeClientRequestArgs( + "http:", + args + ); + const mockAgent = new MockAgent({ + customAgent: options.agent, + onRequest, + onResponse + }); + options.agent = mockAgent; + return Reflect.apply(target, thisArg, [url, options, callback]); + } + }); + https2.request = new Proxy(https2.request, { + apply: (target, thisArg, args) => { + const [url, options, callback] = normalizeClientRequestArgs( + "https:", + args + ); + const mockAgent = new MockHttpsAgent({ + customAgent: options.agent, + onRequest, + onResponse + }); + options.agent = mockAgent; + return Reflect.apply(target, thisArg, [url, options, callback]); + } + }); + https2.get = new Proxy(https2.get, { + apply: (target, thisArg, args) => { + const [url, options, callback] = normalizeClientRequestArgs( + "https:", + args + ); + const mockAgent = new MockHttpsAgent({ + customAgent: options.agent, + onRequest, + onResponse + }); + options.agent = mockAgent; + return Reflect.apply(target, thisArg, [url, options, callback]); + } + }); + recordRawFetchHeaders(); + this.subscriptions.push(() => { + http2.get = originalGet; + http2.request = originalRequest; + https2.get = originalHttpsGet; + https2.request = originalHttpsRequest; + restoreHeadersPrototype(); + }); + } +}; +var ClientRequestInterceptor = _ClientRequestInterceptor; +ClientRequestInterceptor.symbol = Symbol("client-request-interceptor"); + +export { + ClientRequestInterceptor +}; +//# sourceMappingURL=chunk-FWJSC2QD.mjs.map \ No newline at end of file diff --git a/node_modules/@mswjs/interceptors/lib/node/chunk-FWJSC2QD.mjs.map b/node_modules/@mswjs/interceptors/lib/node/chunk-FWJSC2QD.mjs.map new file mode 100644 index 0000000000000000000000000000000000000000..6d8b4f2b85b697e88d270f1a23b36189406e2fe9 --- /dev/null +++ b/node_modules/@mswjs/interceptors/lib/node/chunk-FWJSC2QD.mjs.map @@ -0,0 +1 @@ +{"version":3,"sources":["../../src/interceptors/ClientRequest/index.ts","../../src/interceptors/ClientRequest/MockHttpSocket.ts","../../src/interceptors/Socket/MockSocket.ts","../../src/interceptors/Socket/utils/normalizeSocketWriteArgs.ts","../../src/interceptors/Socket/utils/baseUrlFromConnectionOptions.ts","../../src/interceptors/ClientRequest/utils/recordRawHeaders.ts","../../src/interceptors/ClientRequest/agents.ts","../../src/interceptors/ClientRequest/utils/normalizeClientRequestArgs.ts","../../src/utils/getUrlByRequestOptions.ts","../../src/utils/cloneObject.ts","../../src/utils/isObject.ts"],"sourcesContent":["import http from 'node:http'\nimport https from 'node:https'\nimport { Interceptor } from '../../Interceptor'\nimport type { HttpRequestEventMap } from '../../glossary'\nimport {\n kRequestId,\n MockHttpSocketRequestCallback,\n MockHttpSocketResponseCallback,\n} from './MockHttpSocket'\nimport { MockAgent, MockHttpsAgent } from './agents'\nimport { RequestController } from '../../RequestController'\nimport { emitAsync } from '../../utils/emitAsync'\nimport { normalizeClientRequestArgs } from './utils/normalizeClientRequestArgs'\nimport { handleRequest } from '../../utils/handleRequest'\nimport {\n recordRawFetchHeaders,\n restoreHeadersPrototype,\n} from './utils/recordRawHeaders'\n\nexport class ClientRequestInterceptor extends Interceptor {\n static symbol = Symbol('client-request-interceptor')\n\n constructor() {\n super(ClientRequestInterceptor.symbol)\n }\n\n protected setup(): void {\n const { get: originalGet, request: originalRequest } = http\n const { get: originalHttpsGet, request: originalHttpsRequest } = https\n\n const onRequest = this.onRequest.bind(this)\n const onResponse = this.onResponse.bind(this)\n\n http.request = new Proxy(http.request, {\n apply: (target, thisArg, args: Parameters) => {\n const [url, options, callback] = normalizeClientRequestArgs(\n 'http:',\n args\n )\n const mockAgent = new MockAgent({\n customAgent: options.agent,\n onRequest,\n onResponse,\n })\n options.agent = mockAgent\n\n return Reflect.apply(target, thisArg, [url, options, callback])\n },\n })\n\n http.get = new Proxy(http.get, {\n apply: (target, thisArg, args: Parameters) => {\n const [url, options, callback] = normalizeClientRequestArgs(\n 'http:',\n args\n )\n\n const mockAgent = new MockAgent({\n customAgent: options.agent,\n onRequest,\n onResponse,\n })\n options.agent = mockAgent\n\n return Reflect.apply(target, thisArg, [url, options, callback])\n },\n })\n\n //\n // HTTPS.\n //\n\n https.request = new Proxy(https.request, {\n apply: (target, thisArg, args: Parameters) => {\n const [url, options, callback] = normalizeClientRequestArgs(\n 'https:',\n args\n )\n\n const mockAgent = new MockHttpsAgent({\n customAgent: options.agent,\n onRequest,\n onResponse,\n })\n options.agent = mockAgent\n\n return Reflect.apply(target, thisArg, [url, options, callback])\n },\n })\n\n https.get = new Proxy(https.get, {\n apply: (target, thisArg, args: Parameters) => {\n const [url, options, callback] = normalizeClientRequestArgs(\n 'https:',\n args\n )\n\n const mockAgent = new MockHttpsAgent({\n customAgent: options.agent,\n onRequest,\n onResponse,\n })\n options.agent = mockAgent\n\n return Reflect.apply(target, thisArg, [url, options, callback])\n },\n })\n\n // Spy on `Header.prototype.set` and `Header.prototype.append` calls\n // and record the raw header names provided. This is to support\n // `IncomingMessage.prototype.rawHeaders`.\n recordRawFetchHeaders()\n\n this.subscriptions.push(() => {\n http.get = originalGet\n http.request = originalRequest\n\n https.get = originalHttpsGet\n https.request = originalHttpsRequest\n\n restoreHeadersPrototype()\n })\n }\n\n private onRequest: MockHttpSocketRequestCallback = async ({\n request,\n socket,\n }) => {\n const requestId = Reflect.get(request, kRequestId)\n const controller = new RequestController(request)\n\n const isRequestHandled = await handleRequest({\n request,\n requestId,\n controller,\n emitter: this.emitter,\n onResponse: (response) => {\n socket.respondWith(response)\n },\n onRequestError: (response) => {\n socket.respondWith(response)\n },\n onError: (error) => {\n if (error instanceof Error) {\n socket.errorWith(error)\n }\n },\n })\n\n if (!isRequestHandled) {\n return socket.passthrough()\n }\n }\n\n public onResponse: MockHttpSocketResponseCallback = async ({\n requestId,\n request,\n response,\n isMockedResponse,\n }) => {\n // Return the promise to when all the response event listeners\n // are finished.\n return emitAsync(this.emitter, 'response', {\n requestId,\n request,\n response,\n isMockedResponse,\n })\n }\n}\n","import net from 'node:net'\nimport {\n HTTPParser,\n type RequestHeadersCompleteCallback,\n type ResponseHeadersCompleteCallback,\n} from '_http_common'\nimport { STATUS_CODES, IncomingMessage, ServerResponse } from 'node:http'\nimport { Readable } from 'node:stream'\nimport { invariant } from 'outvariant'\nimport { INTERNAL_REQUEST_ID_HEADER_NAME } from '../../Interceptor'\nimport { MockSocket } from '../Socket/MockSocket'\nimport type { NormalizedSocketWriteArgs } from '../Socket/utils/normalizeSocketWriteArgs'\nimport { isPropertyAccessible } from '../../utils/isPropertyAccessible'\nimport { baseUrlFromConnectionOptions } from '../Socket/utils/baseUrlFromConnectionOptions'\nimport { createServerErrorResponse } from '../../utils/responseUtils'\nimport { createRequestId } from '../../createRequestId'\nimport { getRawFetchHeaders } from './utils/recordRawHeaders'\nimport { FetchResponse } from '../../utils/fetchUtils'\n\ntype HttpConnectionOptions = any\n\nexport type MockHttpSocketRequestCallback = (args: {\n requestId: string\n request: Request\n socket: MockHttpSocket\n}) => void\n\nexport type MockHttpSocketResponseCallback = (args: {\n requestId: string\n request: Request\n response: Response\n isMockedResponse: boolean\n socket: MockHttpSocket\n}) => Promise\n\ninterface MockHttpSocketOptions {\n connectionOptions: HttpConnectionOptions\n createConnection: () => net.Socket\n onRequest: MockHttpSocketRequestCallback\n onResponse: MockHttpSocketResponseCallback\n}\n\nexport const kRequestId = Symbol('kRequestId')\n\nexport class MockHttpSocket extends MockSocket {\n private connectionOptions: HttpConnectionOptions\n private createConnection: () => net.Socket\n private baseUrl: URL\n\n private onRequest: MockHttpSocketRequestCallback\n private onResponse: MockHttpSocketResponseCallback\n private responseListenersPromise?: Promise\n\n private writeBuffer: Array = []\n private request?: Request\n private requestParser: HTTPParser<0>\n private requestStream?: Readable\n private shouldKeepAlive?: boolean\n\n private socketState: 'unknown' | 'mock' | 'passthrough' = 'unknown'\n private responseParser: HTTPParser<1>\n private responseStream?: Readable\n private originalSocket?: net.Socket\n\n constructor(options: MockHttpSocketOptions) {\n super({\n write: (chunk, encoding, callback) => {\n // Buffer the writes so they can be flushed in case of the original connection\n // and when reading the request body in the interceptor. If the connection has\n // been established, no need to buffer the chunks anymore, they will be forwarded.\n if (this.socketState !== 'passthrough') {\n this.writeBuffer.push([chunk, encoding, callback])\n }\n\n if (chunk) {\n /**\n * Forward any writes to the mock socket to the underlying original socket.\n * This ensures functional duplex connections, like WebSocket.\n * @see https://github.com/mswjs/interceptors/issues/682\n */\n if (this.socketState === 'passthrough') {\n this.originalSocket?.write(chunk, encoding, callback)\n }\n\n this.requestParser.execute(\n Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk, encoding)\n )\n }\n },\n read: (chunk) => {\n if (chunk !== null) {\n /**\n * @todo We need to free the parser if the connection has been\n * upgraded to a non-HTTP protocol. It won't be able to parse data\n * from that point onward anyway. No need to keep it in memory.\n */\n this.responseParser.execute(\n Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk)\n )\n }\n },\n })\n\n this.connectionOptions = options.connectionOptions\n this.createConnection = options.createConnection\n this.onRequest = options.onRequest\n this.onResponse = options.onResponse\n\n this.baseUrl = baseUrlFromConnectionOptions(this.connectionOptions)\n\n // Request parser.\n this.requestParser = new HTTPParser()\n this.requestParser.initialize(HTTPParser.REQUEST, {})\n this.requestParser[HTTPParser.kOnHeadersComplete] =\n this.onRequestStart.bind(this)\n this.requestParser[HTTPParser.kOnBody] = this.onRequestBody.bind(this)\n this.requestParser[HTTPParser.kOnMessageComplete] =\n this.onRequestEnd.bind(this)\n\n // Response parser.\n this.responseParser = new HTTPParser()\n this.responseParser.initialize(HTTPParser.RESPONSE, {})\n this.responseParser[HTTPParser.kOnHeadersComplete] =\n this.onResponseStart.bind(this)\n this.responseParser[HTTPParser.kOnBody] = this.onResponseBody.bind(this)\n this.responseParser[HTTPParser.kOnMessageComplete] =\n this.onResponseEnd.bind(this)\n\n // Once the socket is finished, nothing can write to it\n // anymore. It has also flushed any buffered chunks.\n this.once('finish', () => this.requestParser.free())\n\n if (this.baseUrl.protocol === 'https:') {\n Reflect.set(this, 'encrypted', true)\n // The server certificate is not the same as a CA\n // passed to the TLS socket connection options.\n Reflect.set(this, 'authorized', false)\n Reflect.set(this, 'getProtocol', () => 'TLSv1.3')\n Reflect.set(this, 'getSession', () => undefined)\n Reflect.set(this, 'isSessionReused', () => false)\n }\n }\n\n public emit(event: string | symbol, ...args: any[]): boolean {\n const emitEvent = super.emit.bind(this, event as any, ...args)\n\n if (this.responseListenersPromise) {\n this.responseListenersPromise.finally(emitEvent)\n return this.listenerCount(event) > 0\n }\n\n return emitEvent()\n }\n\n public destroy(error?: Error | undefined): this {\n // Destroy the response parser when the socket gets destroyed.\n // Normally, we shoud listen to the \"close\" event but it\n // can be suppressed by using the \"emitClose: false\" option.\n this.responseParser.free()\n\n if (error) {\n this.emit('error', error)\n }\n\n return super.destroy(error)\n }\n\n /**\n * Establish this Socket connection as-is and pipe\n * its data/events through this Socket.\n */\n public passthrough(): void {\n this.socketState = 'passthrough'\n\n if (this.destroyed) {\n return\n }\n\n const socket = this.createConnection()\n this.originalSocket = socket\n\n // If the developer destroys the socket, destroy the original connection.\n this.once('error', (error) => {\n socket.destroy(error)\n })\n\n this.address = socket.address.bind(socket)\n\n // Flush the buffered \"socket.write()\" calls onto\n // the original socket instance (i.e. write request body).\n // Exhaust the \"requestBuffer\" in case this Socket\n // gets reused for different requests.\n let writeArgs: NormalizedSocketWriteArgs | undefined\n let headersWritten = false\n\n while ((writeArgs = this.writeBuffer.shift())) {\n if (writeArgs !== undefined) {\n if (!headersWritten) {\n const [chunk, encoding, callback] = writeArgs\n const chunkString = chunk.toString()\n const chunkBeforeRequestHeaders = chunkString.slice(\n 0,\n chunkString.indexOf('\\r\\n') + 2\n )\n const chunkAfterRequestHeaders = chunkString.slice(\n chunk.indexOf('\\r\\n\\r\\n')\n )\n const rawRequestHeaders = getRawFetchHeaders(this.request!.headers)\n const requestHeadersString = rawRequestHeaders\n // Skip the internal request ID deduplication header.\n .filter(([name]) => {\n return name.toLowerCase() !== INTERNAL_REQUEST_ID_HEADER_NAME\n })\n .map(([name, value]) => `${name}: ${value}`)\n .join('\\r\\n')\n\n // Modify the HTTP request message headers\n // to reflect any changes to the request headers\n // from the \"request\" event listener.\n const headersChunk = `${chunkBeforeRequestHeaders}${requestHeadersString}${chunkAfterRequestHeaders}`\n socket.write(headersChunk, encoding, callback)\n headersWritten = true\n continue\n }\n\n socket.write(...writeArgs)\n }\n }\n\n // Forward TLS Socket properties onto this Socket instance\n // in the case of a TLS/SSL connection.\n if (Reflect.get(socket, 'encrypted')) {\n const tlsProperties = [\n 'encrypted',\n 'authorized',\n 'getProtocol',\n 'getSession',\n 'isSessionReused',\n ]\n\n tlsProperties.forEach((propertyName) => {\n Object.defineProperty(this, propertyName, {\n enumerable: true,\n get: () => {\n const value = Reflect.get(socket, propertyName)\n return typeof value === 'function' ? value.bind(socket) : value\n },\n })\n })\n }\n\n socket\n .on('lookup', (...args) => this.emit('lookup', ...args))\n .on('connect', () => {\n this.connecting = socket.connecting\n this.emit('connect')\n })\n .on('secureConnect', () => this.emit('secureConnect'))\n .on('secure', () => this.emit('secure'))\n .on('session', (session) => this.emit('session', session))\n .on('ready', () => this.emit('ready'))\n .on('drain', () => this.emit('drain'))\n .on('data', (chunk) => {\n // Push the original response to this socket\n // so it triggers the HTTP response parser. This unifies\n // the handling pipeline for original and mocked response.\n this.push(chunk)\n })\n .on('error', (error) => {\n Reflect.set(this, '_hadError', Reflect.get(socket, '_hadError'))\n this.emit('error', error)\n })\n .on('resume', () => this.emit('resume'))\n .on('timeout', () => this.emit('timeout'))\n .on('prefinish', () => this.emit('prefinish'))\n .on('finish', () => this.emit('finish'))\n .on('close', (hadError) => this.emit('close', hadError))\n .on('end', () => this.emit('end'))\n }\n\n /**\n * Convert the given Fetch API `Response` instance to an\n * HTTP message and push it to the socket.\n */\n public async respondWith(response: Response): Promise {\n // Ignore the mocked response if the socket has been destroyed\n // (e.g. aborted or timed out),\n if (this.destroyed) {\n return\n }\n\n // Handle \"type: error\" responses.\n if (isPropertyAccessible(response, 'type') && response.type === 'error') {\n this.errorWith(new TypeError('Network error'))\n return\n }\n\n // First, emit all the connection events\n // to emulate a successful connection.\n this.mockConnect()\n this.socketState = 'mock'\n\n // Flush the write buffer to trigger write callbacks\n // if it hasn't been flushed already (e.g. someone started reading request stream).\n this.flushWriteBuffer()\n\n // Create a `ServerResponse` instance to delegate HTTP message parsing,\n // Transfer-Encoding, and other things to Node.js internals.\n const serverResponse = new ServerResponse(new IncomingMessage(this))\n\n /**\n * Assign a mock socket instance to the server response to\n * spy on the response chunk writes. Push the transformed response chunks\n * to this `MockHttpSocket` instance to trigger the \"data\" event.\n * @note Providing the same `MockSocket` instance when creating `ServerResponse`\n * does not have the same effect.\n * @see https://github.com/nodejs/node/blob/10099bb3f7fd97bb9dd9667188426866b3098e07/test/parallel/test-http-server-response-standalone.js#L32\n */\n serverResponse.assignSocket(\n new MockSocket({\n write: (chunk, encoding, callback) => {\n this.push(chunk, encoding)\n callback?.()\n },\n read() {},\n })\n )\n\n /**\n * @note Remove the `Connection` and `Date` response headers\n * injected by `ServerResponse` by default. Those are required\n * from the server but the interceptor is NOT technically a server.\n * It's confusing to add response headers that the developer didn't\n * specify themselves. They can always add these if they wish.\n * @see https://www.rfc-editor.org/rfc/rfc9110#field.date\n * @see https://www.rfc-editor.org/rfc/rfc9110#field.connection\n */\n serverResponse.removeHeader('connection')\n serverResponse.removeHeader('date')\n\n const rawResponseHeaders = getRawFetchHeaders(response.headers)\n\n /**\n * @note Call `.writeHead` in order to set the raw response headers\n * in the same case as they were provided by the developer. Using\n * `.setHeader()`/`.appendHeader()` normalizes header names.\n */\n serverResponse.writeHead(\n response.status,\n response.statusText || STATUS_CODES[response.status],\n rawResponseHeaders\n )\n\n // If the developer destroy the socket, gracefully destroy the response.\n this.once('error', () => {\n serverResponse.destroy()\n })\n\n if (response.body) {\n try {\n const reader = response.body.getReader()\n\n while (true) {\n const { done, value } = await reader.read()\n\n if (done) {\n serverResponse.end()\n break\n }\n\n serverResponse.write(value)\n }\n } catch (error) {\n // Coerce response stream errors to 500 responses.\n this.respondWith(createServerErrorResponse(error))\n return\n }\n } else {\n serverResponse.end()\n }\n\n // Close the socket if the connection wasn't marked as keep-alive.\n if (!this.shouldKeepAlive) {\n this.emit('readable')\n\n /**\n * @todo @fixme This is likely a hack.\n * Since we push null to the socket, it never propagates to the\n * parser, and the parser never calls \"onResponseEnd\" to close\n * the response stream. We are closing the stream here manually\n * but that shouldn't be the case.\n */\n this.responseStream?.push(null)\n this.push(null)\n }\n }\n\n /**\n * Close this socket connection with the given error.\n */\n public errorWith(error?: Error): void {\n this.destroy(error)\n }\n\n private mockConnect(): void {\n // Calling this method immediately puts the socket\n // into the connected state.\n this.connecting = false\n\n const isIPv6 =\n net.isIPv6(this.connectionOptions.hostname) ||\n this.connectionOptions.family === 6\n const addressInfo = {\n address: isIPv6 ? '::1' : '127.0.0.1',\n family: isIPv6 ? 'IPv6' : 'IPv4',\n port: this.connectionOptions.port,\n }\n // Return fake address information for the socket.\n this.address = () => addressInfo\n this.emit(\n 'lookup',\n null,\n addressInfo.address,\n addressInfo.family === 'IPv6' ? 6 : 4,\n this.connectionOptions.host\n )\n this.emit('connect')\n this.emit('ready')\n\n if (this.baseUrl.protocol === 'https:') {\n this.emit('secure')\n this.emit('secureConnect')\n\n // A single TLS connection is represented by two \"session\" events.\n this.emit(\n 'session',\n this.connectionOptions.session ||\n Buffer.from('mock-session-renegotiate')\n )\n this.emit('session', Buffer.from('mock-session-resume'))\n }\n }\n\n private flushWriteBuffer(): void {\n for (const writeCall of this.writeBuffer) {\n if (typeof writeCall[2] === 'function') {\n writeCall[2]()\n /**\n * @note Remove the callback from the write call\n * so it doesn't get called twice on passthrough\n * if `request.end()` was called within `request.write()`.\n * @see https://github.com/mswjs/interceptors/issues/684\n */\n writeCall[2] = undefined\n }\n }\n }\n\n private onRequestStart: RequestHeadersCompleteCallback = (\n versionMajor,\n versionMinor,\n rawHeaders,\n _,\n path,\n __,\n ___,\n ____,\n shouldKeepAlive\n ) => {\n this.shouldKeepAlive = shouldKeepAlive\n\n const url = new URL(path, this.baseUrl)\n const method = this.connectionOptions.method?.toUpperCase() || 'GET'\n const headers = FetchResponse.parseRawHeaders(rawHeaders)\n const canHaveBody = method !== 'GET' && method !== 'HEAD'\n\n // Translate the basic authorization in the URL to the request header.\n // Constructing a Request instance with a URL containing auth is no-op.\n if (url.username || url.password) {\n if (!headers.has('authorization')) {\n headers.set('authorization', `Basic ${url.username}:${url.password}`)\n }\n url.username = ''\n url.password = ''\n }\n\n // Create a new stream for each request.\n // If this Socket is reused for multiple requests,\n // this ensures that each request gets its own stream.\n // One Socket instance can only handle one request at a time.\n if (canHaveBody) {\n this.requestStream = new Readable({\n /**\n * @note Provide the `read()` method so a `Readable` could be\n * used as the actual request body (the stream calls \"read()\").\n * We control the queue in the onRequestBody/End functions.\n */\n read: () => {\n // If the user attempts to read the request body,\n // flush the write buffer to trigger the callbacks.\n // This way, if the request stream ends in the write callback,\n // it will indeed end correctly.\n this.flushWriteBuffer()\n },\n })\n }\n\n const requestId = createRequestId()\n this.request = new Request(url, {\n method,\n headers,\n credentials: 'same-origin',\n // @ts-expect-error Undocumented Fetch property.\n duplex: canHaveBody ? 'half' : undefined,\n body: canHaveBody ? (Readable.toWeb(this.requestStream!) as any) : null,\n })\n\n Reflect.set(this.request, kRequestId, requestId)\n\n // Skip handling the request that's already being handled\n // by another (parent) interceptor. For example, XMLHttpRequest\n // is often implemented via ClientRequest in Node.js (e.g. JSDOM).\n // In that case, XHR interceptor will bubble down to the ClientRequest\n // interceptor. No need to try to handle that request again.\n /**\n * @fixme Stop relying on the \"X-Request-Id\" request header\n * to figure out if one interceptor has been invoked within another.\n * @see https://github.com/mswjs/interceptors/issues/378\n */\n if (this.request.headers.has(INTERNAL_REQUEST_ID_HEADER_NAME)) {\n this.passthrough()\n return\n }\n\n this.onRequest({\n requestId,\n request: this.request,\n socket: this,\n })\n }\n\n private onRequestBody(chunk: Buffer): void {\n invariant(\n this.requestStream,\n 'Failed to write to a request stream: stream does not exist'\n )\n\n this.requestStream.push(chunk)\n }\n\n private onRequestEnd(): void {\n // Request end can be called for requests without body.\n if (this.requestStream) {\n this.requestStream.push(null)\n }\n }\n\n private onResponseStart: ResponseHeadersCompleteCallback = (\n versionMajor,\n versionMinor,\n rawHeaders,\n method,\n url,\n status,\n statusText\n ) => {\n const headers = FetchResponse.parseRawHeaders(rawHeaders)\n\n const response = new FetchResponse(\n /**\n * @note The Fetch API response instance exposed to the consumer\n * is created over the response stream of the HTTP parser. It is NOT\n * related to the Socket instance. This way, you can read response body\n * in response listener while the Socket instance delays the emission\n * of \"end\" and other events until those response listeners are finished.\n */\n FetchResponse.isResponseWithBody(status)\n ? (Readable.toWeb(\n (this.responseStream = new Readable({ read() {} }))\n ) as any)\n : null,\n {\n url,\n status,\n statusText,\n headers,\n }\n )\n\n invariant(\n this.request,\n 'Failed to handle a response: request does not exist'\n )\n\n /**\n * @fixme Stop relying on the \"X-Request-Id\" request header\n * to figure out if one interceptor has been invoked within another.\n * @see https://github.com/mswjs/interceptors/issues/378\n */\n if (this.request.headers.has(INTERNAL_REQUEST_ID_HEADER_NAME)) {\n return\n }\n\n this.responseListenersPromise = this.onResponse({\n response,\n isMockedResponse: this.socketState === 'mock',\n requestId: Reflect.get(this.request, kRequestId),\n request: this.request,\n socket: this,\n })\n }\n\n private onResponseBody(chunk: Buffer) {\n invariant(\n this.responseStream,\n 'Failed to write to a response stream: stream does not exist'\n )\n\n this.responseStream.push(chunk)\n }\n\n private onResponseEnd(): void {\n // Response end can be called for responses without body.\n if (this.responseStream) {\n this.responseStream.push(null)\n }\n }\n}\n","import net from 'node:net'\nimport {\n normalizeSocketWriteArgs,\n type WriteArgs,\n type WriteCallback,\n} from './utils/normalizeSocketWriteArgs'\n\nexport interface MockSocketOptions {\n write: (\n chunk: Buffer | string,\n encoding: BufferEncoding | undefined,\n callback?: WriteCallback\n ) => void\n\n read: (chunk: Buffer, encoding: BufferEncoding | undefined) => void\n}\n\nexport class MockSocket extends net.Socket {\n public connecting: boolean\n\n constructor(protected readonly options: MockSocketOptions) {\n super()\n this.connecting = false\n this.connect()\n\n this._final = (callback) => {\n callback(null)\n }\n }\n\n public connect() {\n // The connection will remain pending until\n // the consumer decides to handle it.\n this.connecting = true\n return this\n }\n\n public write(...args: Array): boolean {\n const [chunk, encoding, callback] = normalizeSocketWriteArgs(\n args as WriteArgs\n )\n this.options.write(chunk, encoding, callback)\n return true\n }\n\n public end(...args: Array) {\n const [chunk, encoding, callback] = normalizeSocketWriteArgs(\n args as WriteArgs\n )\n this.options.write(chunk, encoding, callback)\n return super.end.apply(this, args as any)\n }\n\n public push(chunk: any, encoding?: BufferEncoding): boolean {\n this.options.read(chunk, encoding)\n return super.push(chunk, encoding)\n }\n}\n","export type WriteCallback = (error?: Error | null) => void\n\nexport type WriteArgs =\n | [chunk: unknown, callback?: WriteCallback]\n | [chunk: unknown, encoding: BufferEncoding, callback?: WriteCallback]\n\nexport type NormalizedSocketWriteArgs = [\n chunk: any,\n encoding?: BufferEncoding,\n callback?: WriteCallback,\n]\n\n/**\n * Normalizes the arguments provided to the `Writable.prototype.write()`\n * and `Writable.prototype.end()`.\n */\nexport function normalizeSocketWriteArgs(\n args: WriteArgs\n): NormalizedSocketWriteArgs {\n const normalized: NormalizedSocketWriteArgs = [args[0], undefined, undefined]\n\n if (typeof args[1] === 'string') {\n normalized[1] = args[1]\n } else if (typeof args[1] === 'function') {\n normalized[2] = args[1]\n }\n\n if (typeof args[2] === 'function') {\n normalized[2] = args[2]\n }\n\n return normalized\n}\n","export function baseUrlFromConnectionOptions(options: any): URL {\n if ('href' in options) {\n return new URL(options.href)\n }\n\n const protocol = options.port === 443 ? 'https:' : 'http:'\n const host = options.host\n\n const url = new URL(`${protocol}//${host}`)\n\n if (options.port) {\n url.port = options.port.toString()\n }\n\n if (options.path) {\n url.pathname = options.path\n }\n\n if (options.auth) {\n const [username, password] = options.auth.split(':')\n url.username = username\n url.password = password\n }\n\n return url\n}\n","type HeaderTuple = [string, string]\ntype RawHeaders = Array\ntype SetHeaderBehavior = 'set' | 'append'\n\nconst kRawHeaders = Symbol('kRawHeaders')\nconst kRestorePatches = Symbol('kRestorePatches')\n\nfunction recordRawHeader(\n headers: Headers,\n args: HeaderTuple,\n behavior: SetHeaderBehavior\n) {\n ensureRawHeadersSymbol(headers, [])\n const rawHeaders = Reflect.get(headers, kRawHeaders) as RawHeaders\n\n if (behavior === 'set') {\n // When recording a set header, ensure we remove any matching existing headers.\n for (let index = rawHeaders.length - 1; index >= 0; index--) {\n if (rawHeaders[index][0].toLowerCase() === args[0].toLowerCase()) {\n rawHeaders.splice(index, 1)\n }\n }\n }\n\n rawHeaders.push(args)\n}\n\n/**\n * Define the raw headers symbol on the given `Headers` instance.\n * If the symbol already exists, this function does nothing.\n */\nfunction ensureRawHeadersSymbol(\n headers: Headers,\n rawHeaders: RawHeaders\n): void {\n if (Reflect.has(headers, kRawHeaders)) {\n return\n }\n\n defineRawHeadersSymbol(headers, rawHeaders)\n}\n\n/**\n * Define the raw headers symbol on the given `Headers` instance.\n * If the symbol already exists, it gets overridden.\n */\nfunction defineRawHeadersSymbol(headers: Headers, rawHeaders: RawHeaders) {\n Object.defineProperty(headers, kRawHeaders, {\n value: rawHeaders,\n enumerable: false,\n // Mark the symbol as configurable so its value can be overridden.\n // Overrides happen when merging raw headers from multiple sources.\n // E.g. new Request(new Request(url, { headers }), { headers })\n configurable: true,\n })\n}\n\n/**\n * Patch the global `Headers` class to store raw headers.\n * This is for compatibility with `IncomingMessage.prototype.rawHeaders`.\n *\n * @note Node.js has their own raw headers symbol but it\n * only records the first header name in case of multi-value headers.\n * Any other headers are normalized before comparing. This makes it\n * incompatible with the `rawHeaders` format.\n *\n * let h = new Headers()\n * h.append('X-Custom', 'one')\n * h.append('x-custom', 'two')\n * h[Symbol('headers map')] // Map { 'X-Custom' => 'one, two' }\n */\nexport function recordRawFetchHeaders() {\n // Prevent patching the Headers prototype multiple times.\n if (Reflect.get(Headers, kRestorePatches)) {\n return Reflect.get(Headers, kRestorePatches)\n }\n\n const {\n Headers: OriginalHeaders,\n Request: OriginalRequest,\n Response: OriginalResponse,\n } = globalThis\n const { set, append, delete: headersDeleteMethod } = Headers.prototype\n\n Object.defineProperty(Headers, kRestorePatches, {\n value: () => {\n Headers.prototype.set = set\n Headers.prototype.append = append\n Headers.prototype.delete = headersDeleteMethod\n globalThis.Headers = OriginalHeaders\n\n globalThis.Request = OriginalRequest\n globalThis.Response = OriginalResponse\n\n Reflect.deleteProperty(Headers, kRestorePatches)\n },\n enumerable: false,\n /**\n * @note Mark this property as configurable\n * so we can delete it using `Reflect.delete` during cleanup.\n */\n configurable: true,\n })\n\n Object.defineProperty(globalThis, 'Headers', {\n enumerable: true,\n writable: true,\n value: new Proxy(Headers, {\n construct(target, args, newTarget) {\n const headersInit = args[0] || []\n\n if (\n headersInit instanceof Headers &&\n Reflect.has(headersInit, kRawHeaders)\n ) {\n const headers = Reflect.construct(\n target,\n [Reflect.get(headersInit, kRawHeaders)],\n newTarget\n )\n ensureRawHeadersSymbol(headers, [\n /**\n * @note Spread the retrieved headers to clone them.\n * This prevents multiple Headers instances from pointing\n * at the same internal \"rawHeaders\" array.\n */\n ...Reflect.get(headersInit, kRawHeaders),\n ])\n return headers\n }\n\n const headers = Reflect.construct(target, args, newTarget)\n\n // Request/Response constructors will set the symbol\n // upon creating a new instance, using the raw developer\n // input as the raw headers. Skip the symbol altogether\n // in those cases because the input to Headers will be normalized.\n if (!Reflect.has(headers, kRawHeaders)) {\n const rawHeadersInit = Array.isArray(headersInit)\n ? headersInit\n : Object.entries(headersInit)\n ensureRawHeadersSymbol(headers, rawHeadersInit)\n }\n\n return headers\n },\n }),\n })\n\n Headers.prototype.set = new Proxy(Headers.prototype.set, {\n apply(target, thisArg, args: HeaderTuple) {\n recordRawHeader(thisArg, args, 'set')\n return Reflect.apply(target, thisArg, args)\n },\n })\n\n Headers.prototype.append = new Proxy(Headers.prototype.append, {\n apply(target, thisArg, args: HeaderTuple) {\n recordRawHeader(thisArg, args, 'append')\n return Reflect.apply(target, thisArg, args)\n },\n })\n\n Headers.prototype.delete = new Proxy(Headers.prototype.delete, {\n apply(target, thisArg, args: [string]) {\n const rawHeaders = Reflect.get(thisArg, kRawHeaders) as RawHeaders\n\n if (rawHeaders) {\n for (let index = rawHeaders.length - 1; index >= 0; index--) {\n if (rawHeaders[index][0].toLowerCase() === args[0].toLowerCase()) {\n rawHeaders.splice(index, 1)\n }\n }\n }\n\n return Reflect.apply(target, thisArg, args)\n },\n })\n\n Object.defineProperty(globalThis, 'Request', {\n enumerable: true,\n writable: true,\n value: new Proxy(Request, {\n construct(target, args, newTarget) {\n const request = Reflect.construct(target, args, newTarget)\n const inferredRawHeaders: RawHeaders = []\n\n // Infer raw headers from a `Request` instance used as init.\n if (typeof args[0] === 'object' && args[0].headers != null) {\n inferredRawHeaders.push(...inferRawHeaders(args[0].headers))\n }\n\n // Infer raw headers from the \"headers\" init argument.\n if (typeof args[1] === 'object' && args[1].headers != null) {\n inferredRawHeaders.push(...inferRawHeaders(args[1].headers))\n }\n\n if (inferredRawHeaders.length > 0) {\n ensureRawHeadersSymbol(request.headers, inferredRawHeaders)\n }\n\n return request\n },\n }),\n })\n\n Object.defineProperty(globalThis, 'Response', {\n enumerable: true,\n writable: true,\n value: new Proxy(Response, {\n construct(target, args, newTarget) {\n const response = Reflect.construct(target, args, newTarget)\n\n if (typeof args[1] === 'object' && args[1].headers != null) {\n ensureRawHeadersSymbol(\n response.headers,\n inferRawHeaders(args[1].headers)\n )\n }\n\n return response\n },\n }),\n })\n}\n\nexport function restoreHeadersPrototype() {\n if (!Reflect.get(Headers, kRestorePatches)) {\n return\n }\n\n Reflect.get(Headers, kRestorePatches)()\n}\n\nexport function getRawFetchHeaders(headers: Headers): RawHeaders {\n // If the raw headers recording failed for some reason,\n // use the normalized header entries instead.\n if (!Reflect.has(headers, kRawHeaders)) {\n return Array.from(headers.entries())\n }\n\n const rawHeaders = Reflect.get(headers, kRawHeaders) as RawHeaders\n return rawHeaders.length > 0 ? rawHeaders : Array.from(headers.entries())\n}\n\n/**\n * Infers the raw headers from the given `HeadersInit` provided\n * to the Request/Response constructor.\n *\n * If the `init.headers` is a Headers instance, use it directly.\n * That means the headers were created standalone and already have\n * the raw headers stored.\n * If the `init.headers` is a HeadersInit, create a new Headers\n * instace out of it.\n */\nfunction inferRawHeaders(headers: HeadersInit): RawHeaders {\n if (headers instanceof Headers) {\n return Reflect.get(headers, kRawHeaders) || []\n }\n\n return Reflect.get(new Headers(headers), kRawHeaders)\n}\n","import net from 'node:net'\nimport http from 'node:http'\nimport https from 'node:https'\nimport {\n MockHttpSocket,\n type MockHttpSocketRequestCallback,\n type MockHttpSocketResponseCallback,\n} from './MockHttpSocket'\n\ndeclare module 'node:http' {\n interface Agent {\n options?: http.AgentOptions\n createConnection(options: any, callback: any): net.Socket\n }\n}\n\ninterface MockAgentOptions {\n customAgent?: http.RequestOptions['agent']\n onRequest: MockHttpSocketRequestCallback\n onResponse: MockHttpSocketResponseCallback\n}\n\nexport class MockAgent extends http.Agent {\n private customAgent?: http.RequestOptions['agent']\n private onRequest: MockHttpSocketRequestCallback\n private onResponse: MockHttpSocketResponseCallback\n\n constructor(options: MockAgentOptions) {\n super()\n this.customAgent = options.customAgent\n this.onRequest = options.onRequest\n this.onResponse = options.onResponse\n }\n\n public createConnection(options: any, callback: any): net.Socket {\n const createConnection =\n this.customAgent instanceof http.Agent\n ? this.customAgent.createConnection\n : super.createConnection\n\n const createConnectionOptions =\n this.customAgent instanceof http.Agent\n ? {\n ...options,\n ...this.customAgent.options,\n }\n : options\n\n const socket = new MockHttpSocket({\n connectionOptions: options,\n createConnection: createConnection.bind(\n this.customAgent || this,\n createConnectionOptions,\n callback\n ),\n onRequest: this.onRequest.bind(this),\n onResponse: this.onResponse.bind(this),\n })\n\n return socket\n }\n}\n\nexport class MockHttpsAgent extends https.Agent {\n private customAgent?: https.RequestOptions['agent']\n private onRequest: MockHttpSocketRequestCallback\n private onResponse: MockHttpSocketResponseCallback\n\n constructor(options: MockAgentOptions) {\n super()\n this.customAgent = options.customAgent\n this.onRequest = options.onRequest\n this.onResponse = options.onResponse\n }\n\n public createConnection(options: any, callback: any): net.Socket {\n const createConnection =\n this.customAgent instanceof https.Agent\n ? this.customAgent.createConnection\n : super.createConnection\n\n const createConnectionOptions =\n this.customAgent instanceof https.Agent\n ? {\n ...options,\n ...this.customAgent.options,\n }\n : options\n\n const socket = new MockHttpSocket({\n connectionOptions: options,\n createConnection: createConnection.bind(\n this.customAgent || this,\n createConnectionOptions,\n callback\n ),\n onRequest: this.onRequest.bind(this),\n onResponse: this.onResponse.bind(this),\n })\n\n return socket\n }\n}\n","import { urlToHttpOptions } from 'node:url'\nimport {\n Agent as HttpAgent,\n globalAgent as httpGlobalAgent,\n IncomingMessage,\n} from 'node:http'\nimport {\n RequestOptions,\n Agent as HttpsAgent,\n globalAgent as httpsGlobalAgent,\n} from 'node:https'\nimport {\n /**\n * @note Use the Node.js URL instead of the global URL\n * because environments like JSDOM may override the global,\n * breaking the compatibility with Node.js.\n * @see https://github.com/node-fetch/node-fetch/issues/1376#issuecomment-966435555\n */\n URL,\n Url as LegacyURL,\n parse as parseUrl,\n} from 'node:url'\nimport { Logger } from '@open-draft/logger'\nimport {\n ResolvedRequestOptions,\n getUrlByRequestOptions,\n} from '../../../utils/getUrlByRequestOptions'\nimport { cloneObject } from '../../../utils/cloneObject'\nimport { isObject } from '../../../utils/isObject'\n\nconst logger = new Logger('http normalizeClientRequestArgs')\n\nexport type HttpRequestCallback = (response: IncomingMessage) => void\n\nexport type ClientRequestArgs =\n // Request without any arguments is also possible.\n | []\n | [string | URL | LegacyURL, HttpRequestCallback?]\n | [string | URL | LegacyURL, RequestOptions, HttpRequestCallback?]\n | [RequestOptions, HttpRequestCallback?]\n\nfunction resolveRequestOptions(\n args: ClientRequestArgs,\n url: URL\n): RequestOptions {\n // Calling `fetch` provides only URL to `ClientRequest`\n // without any `RequestOptions` or callback.\n if (typeof args[1] === 'undefined' || typeof args[1] === 'function') {\n logger.info('request options not provided, deriving from the url', url)\n return urlToHttpOptions(url)\n }\n\n if (args[1]) {\n logger.info('has custom RequestOptions!', args[1])\n const requestOptionsFromUrl = urlToHttpOptions(url)\n\n logger.info('derived RequestOptions from the URL:', requestOptionsFromUrl)\n\n /**\n * Clone the request options to lock their state\n * at the moment they are provided to `ClientRequest`.\n * @see https://github.com/mswjs/interceptors/issues/86\n */\n logger.info('cloning RequestOptions...')\n const clonedRequestOptions = cloneObject(args[1])\n logger.info('successfully cloned RequestOptions!', clonedRequestOptions)\n\n return {\n ...requestOptionsFromUrl,\n ...clonedRequestOptions,\n }\n }\n\n logger.info('using an empty object as request options')\n return {} as RequestOptions\n}\n\n/**\n * Overrides the given `URL` instance with the explicit properties provided\n * on the `RequestOptions` object. The options object takes precedence,\n * and will replace URL properties like \"host\", \"path\", and \"port\", if specified.\n */\nfunction overrideUrlByRequestOptions(url: URL, options: RequestOptions): URL {\n url.host = options.host || url.host\n url.hostname = options.hostname || url.hostname\n url.port = options.port ? options.port.toString() : url.port\n\n if (options.path) {\n const parsedOptionsPath = parseUrl(options.path, false)\n url.pathname = parsedOptionsPath.pathname || ''\n url.search = parsedOptionsPath.search || ''\n }\n\n return url\n}\n\nfunction resolveCallback(\n args: ClientRequestArgs\n): HttpRequestCallback | undefined {\n return typeof args[1] === 'function' ? args[1] : args[2]\n}\n\nexport type NormalizedClientRequestArgs = [\n url: URL,\n options: ResolvedRequestOptions,\n callback?: HttpRequestCallback\n]\n\n/**\n * Normalizes parameters given to a `http.request` call\n * so it always has a `URL` and `RequestOptions`.\n */\nexport function normalizeClientRequestArgs(\n defaultProtocol: string,\n args: ClientRequestArgs\n): NormalizedClientRequestArgs {\n let url: URL\n let options: ResolvedRequestOptions\n let callback: HttpRequestCallback | undefined\n\n logger.info('arguments', args)\n logger.info('using default protocol:', defaultProtocol)\n\n // Support \"http.request()\" calls without any arguments.\n // That call results in a \"GET http://localhost\" request.\n if (args.length === 0) {\n const url = new URL('http://localhost')\n const options = resolveRequestOptions(args, url)\n return [url, options]\n }\n\n // Convert a url string into a URL instance\n // and derive request options from it.\n if (typeof args[0] === 'string') {\n logger.info('first argument is a location string:', args[0])\n\n url = new URL(args[0])\n logger.info('created a url:', url)\n\n const requestOptionsFromUrl = urlToHttpOptions(url)\n logger.info('request options from url:', requestOptionsFromUrl)\n\n options = resolveRequestOptions(args, url)\n logger.info('resolved request options:', options)\n\n callback = resolveCallback(args)\n }\n // Handle a given URL instance as-is\n // and derive request options from it.\n else if (args[0] instanceof URL) {\n url = args[0]\n logger.info('first argument is a URL:', url)\n\n // Check if the second provided argument is RequestOptions.\n // If it is, check if \"options.path\" was set and rewrite it\n // on the input URL.\n // Do this before resolving options from the URL below\n // to prevent query string from being duplicated in the path.\n if (typeof args[1] !== 'undefined' && isObject(args[1])) {\n url = overrideUrlByRequestOptions(url, args[1])\n }\n\n options = resolveRequestOptions(args, url)\n logger.info('derived request options:', options)\n\n callback = resolveCallback(args)\n }\n // Handle a legacy URL instance and re-normalize from either a RequestOptions object\n // or a WHATWG URL.\n else if ('hash' in args[0] && !('method' in args[0])) {\n const [legacyUrl] = args\n logger.info('first argument is a legacy URL:', legacyUrl)\n\n if (legacyUrl.hostname === null) {\n /**\n * We are dealing with a relative url, so use the path as an \"option\" and\n * merge in any existing options, giving priority to exising options -- i.e. a path in any\n * existing options will take precedence over the one contained in the url. This is consistent\n * with the behaviour in ClientRequest.\n * @see https://github.com/nodejs/node/blob/d84f1312915fe45fe0febe888db692c74894c382/lib/_http_client.js#L122\n */\n logger.info('given legacy URL is relative (no hostname)')\n\n return isObject(args[1])\n ? normalizeClientRequestArgs(defaultProtocol, [\n { path: legacyUrl.path, ...args[1] },\n args[2],\n ])\n : normalizeClientRequestArgs(defaultProtocol, [\n { path: legacyUrl.path },\n args[1] as HttpRequestCallback,\n ])\n }\n\n logger.info('given legacy url is absolute')\n\n // We are dealing with an absolute URL, so convert to WHATWG and try again.\n const resolvedUrl = new URL(legacyUrl.href)\n\n return args[1] === undefined\n ? normalizeClientRequestArgs(defaultProtocol, [resolvedUrl])\n : typeof args[1] === 'function'\n ? normalizeClientRequestArgs(defaultProtocol, [resolvedUrl, args[1]])\n : normalizeClientRequestArgs(defaultProtocol, [\n resolvedUrl,\n args[1],\n args[2],\n ])\n }\n // Handle a given \"RequestOptions\" object as-is\n // and derive the URL instance from it.\n else if (isObject(args[0])) {\n options = { ...(args[0] as any) }\n logger.info('first argument is RequestOptions:', options)\n\n // When handling a \"RequestOptions\" object without an explicit \"protocol\",\n // infer the protocol from the request issuing module (http/https).\n options.protocol = options.protocol || defaultProtocol\n logger.info('normalized request options:', options)\n\n url = getUrlByRequestOptions(options)\n logger.info('created a URL from RequestOptions:', url.href)\n\n callback = resolveCallback(args)\n } else {\n throw new Error(\n `Failed to construct ClientRequest with these parameters: ${args}`\n )\n }\n\n options.protocol = options.protocol || url.protocol\n options.method = options.method || 'GET'\n\n /**\n * Infer a fallback agent from the URL protocol.\n * The interception is done on the \"ClientRequest\" level (\"NodeClientRequest\")\n * and it may miss the correct agent. Always align the agent\n * with the URL protocol, if not provided.\n *\n * @note Respect the \"agent: false\" value.\n */\n if (typeof options.agent === 'undefined') {\n const agent =\n options.protocol === 'https:'\n ? new HttpsAgent({\n // Any other value other than false is considered as true, so we don't add this property if undefined.\n ...('rejectUnauthorized' in options && {\n rejectUnauthorized: options.rejectUnauthorized,\n }),\n })\n : new HttpAgent()\n\n options.agent = agent\n logger.info('resolved fallback agent:', agent)\n }\n\n /**\n * Ensure that the default Agent is always set.\n * This prevents the protocol mismatch for requests with { agent: false },\n * where the global Agent is inferred.\n * @see https://github.com/mswjs/msw/issues/1150\n * @see https://github.com/nodejs/node/blob/418ff70b810f0e7112d48baaa72932a56cfa213b/lib/_http_client.js#L130\n * @see https://github.com/nodejs/node/blob/418ff70b810f0e7112d48baaa72932a56cfa213b/lib/_http_client.js#L157-L159\n */\n if (!options._defaultAgent) {\n logger.info(\n 'has no default agent, setting the default agent for \"%s\"',\n options.protocol\n )\n\n options._defaultAgent =\n options.protocol === 'https:' ? httpsGlobalAgent : httpGlobalAgent\n }\n\n logger.info('successfully resolved url:', url.href)\n logger.info('successfully resolved options:', options)\n logger.info('successfully resolved callback:', callback)\n\n /**\n * @note If the user-provided URL is not a valid URL in Node.js,\n * (e.g. the one provided by the JSDOM polyfills), case it to\n * string. Otherwise, this throws on Node.js incompatibility\n * (`ERR_INVALID_ARG_TYPE` on the connection listener)\n * @see https://github.com/node-fetch/node-fetch/issues/1376#issuecomment-966435555\n */\n if (!(url instanceof URL)) {\n url = (url as any).toString()\n }\n\n return [url, options, callback]\n}\n","import { Agent } from 'http'\nimport { RequestOptions, Agent as HttpsAgent } from 'https'\nimport { Logger } from '@open-draft/logger'\n\nconst logger = new Logger('utils getUrlByRequestOptions')\n\n// Request instance constructed by the \"request\" library\n// has a \"self\" property that has a \"uri\" field. This is\n// reproducible by performing a \"XMLHttpRequest\" request in JSDOM.\nexport interface RequestSelf {\n uri?: URL\n}\n\nexport type ResolvedRequestOptions = RequestOptions & RequestSelf\n\nexport const DEFAULT_PATH = '/'\nconst DEFAULT_PROTOCOL = 'http:'\nconst DEFAULT_HOSTNAME = 'localhost'\nconst SSL_PORT = 443\n\nfunction getAgent(\n options: ResolvedRequestOptions\n): Agent | HttpsAgent | undefined {\n return options.agent instanceof Agent ? options.agent : undefined\n}\n\nfunction getProtocolByRequestOptions(options: ResolvedRequestOptions): string {\n if (options.protocol) {\n return options.protocol\n }\n\n const agent = getAgent(options)\n const agentProtocol = (agent as RequestOptions)?.protocol\n\n if (agentProtocol) {\n return agentProtocol\n }\n\n const port = getPortByRequestOptions(options)\n const isSecureRequest = options.cert || port === SSL_PORT\n\n return isSecureRequest ? 'https:' : options.uri?.protocol || DEFAULT_PROTOCOL\n}\n\nfunction getPortByRequestOptions(\n options: ResolvedRequestOptions\n): number | undefined {\n // Use the explicitly provided port.\n if (options.port) {\n return Number(options.port)\n }\n\n // Otherwise, try to resolve port from the agent.\n const agent = getAgent(options)\n\n if ((agent as HttpsAgent)?.options.port) {\n return Number((agent as HttpsAgent).options.port)\n }\n\n if ((agent as RequestOptions)?.defaultPort) {\n return Number((agent as RequestOptions).defaultPort)\n }\n\n // Lastly, return undefined indicating that the port\n // must inferred from the protocol. Do not infer it here.\n return undefined\n}\n\ninterface RequestAuth {\n username: string\n password: string\n}\n\nfunction getAuthByRequestOptions(\n options: ResolvedRequestOptions\n): RequestAuth | undefined {\n if (options.auth) {\n const [username, password] = options.auth.split(':')\n return { username, password }\n }\n}\n\n/**\n * Returns true if host looks like an IPv6 address without surrounding brackets\n * It assumes any host containing `:` is definitely not IPv4 and probably IPv6,\n * but note that this could include invalid IPv6 addresses as well.\n */\nfunction isRawIPv6Address(host: string): boolean {\n return host.includes(':') && !host.startsWith('[') && !host.endsWith(']')\n}\n\nfunction getHostname(options: ResolvedRequestOptions): string | undefined {\n let host = options.hostname || options.host\n\n if (host) {\n if (isRawIPv6Address(host)) {\n host = `[${host}]`\n }\n\n // Check the presence of the port, and if it's present,\n // remove it from the host, returning a hostname.\n return new URL(`http://${host}`).hostname\n }\n\n return DEFAULT_HOSTNAME\n}\n\n/**\n * Creates a `URL` instance from a given `RequestOptions` object.\n */\nexport function getUrlByRequestOptions(options: ResolvedRequestOptions): URL {\n logger.info('request options', options)\n\n if (options.uri) {\n logger.info(\n 'constructing url from explicitly provided \"options.uri\": %s',\n options.uri\n )\n return new URL(options.uri.href)\n }\n\n logger.info('figuring out url from request options...')\n\n const protocol = getProtocolByRequestOptions(options)\n logger.info('protocol', protocol)\n\n const port = getPortByRequestOptions(options)\n logger.info('port', port)\n\n const hostname = getHostname(options)\n logger.info('hostname', hostname)\n\n const path = options.path || DEFAULT_PATH\n logger.info('path', path)\n\n const credentials = getAuthByRequestOptions(options)\n logger.info('credentials', credentials)\n\n const authString = credentials\n ? `${credentials.username}:${credentials.password}@`\n : ''\n logger.info('auth string:', authString)\n\n const portString = typeof port !== 'undefined' ? `:${port}` : ''\n const url = new URL(`${protocol}//${hostname}${portString}${path}`)\n url.username = credentials?.username || ''\n url.password = credentials?.password || ''\n\n logger.info('created url:', url)\n\n return url\n}\n","import { Logger } from '@open-draft/logger'\n\nconst logger = new Logger('cloneObject')\n\nfunction isPlainObject(obj?: Record): boolean {\n logger.info('is plain object?', obj)\n\n if (obj == null || !obj.constructor?.name) {\n logger.info('given object is undefined, not a plain object...')\n return false\n }\n\n logger.info('checking the object constructor:', obj.constructor.name)\n return obj.constructor.name === 'Object'\n}\n\nexport function cloneObject>(\n obj: ObjectType\n): ObjectType {\n logger.info('cloning object:', obj)\n\n const enumerableProperties = Object.entries(obj).reduce>(\n (acc, [key, value]) => {\n logger.info('analyzing key-value pair:', key, value)\n\n // Recursively clone only plain objects, omitting class instances.\n acc[key] = isPlainObject(value) ? cloneObject(value) : value\n return acc\n },\n {}\n )\n\n return isPlainObject(obj)\n ? enumerableProperties\n : Object.assign(Object.getPrototypeOf(obj), enumerableProperties)\n}\n","/**\n * Determines if a given value is an instance of object.\n */\nexport function isObject(value: any, loose = false): value is T {\n return loose\n ? Object.prototype.toString.call(value).startsWith('[object ')\n : Object.prototype.toString.call(value) === '[object Object]'\n}\n"],"mappings":"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","names":["http","https","net","headers","net","URL","Logger","Logger","logger","logger","Logger","url","URL","options","http","https"]} \ No newline at end of file diff --git a/node_modules/@mswjs/interceptors/lib/node/chunk-I7HQIBT7.mjs b/node_modules/@mswjs/interceptors/lib/node/chunk-I7HQIBT7.mjs new file mode 100644 index 0000000000000000000000000000000000000000..5db4fec284ab8b3d43233b96c2cd2f997928f5dd --- /dev/null +++ b/node_modules/@mswjs/interceptors/lib/node/chunk-I7HQIBT7.mjs @@ -0,0 +1,245 @@ +// src/Interceptor.ts +import { Logger } from "@open-draft/logger"; +import { Emitter } from "strict-event-emitter"; +var INTERNAL_REQUEST_ID_HEADER_NAME = "x-interceptors-internal-request-id"; +function getGlobalSymbol(symbol) { + return ( + // @ts-ignore https://github.com/Microsoft/TypeScript/issues/24587 + globalThis[symbol] || void 0 + ); +} +function setGlobalSymbol(symbol, value) { + globalThis[symbol] = value; +} +function deleteGlobalSymbol(symbol) { + delete globalThis[symbol]; +} +var InterceptorReadyState = /* @__PURE__ */ ((InterceptorReadyState2) => { + InterceptorReadyState2["INACTIVE"] = "INACTIVE"; + InterceptorReadyState2["APPLYING"] = "APPLYING"; + InterceptorReadyState2["APPLIED"] = "APPLIED"; + InterceptorReadyState2["DISPOSING"] = "DISPOSING"; + InterceptorReadyState2["DISPOSED"] = "DISPOSED"; + return InterceptorReadyState2; +})(InterceptorReadyState || {}); +var Interceptor = class { + constructor(symbol) { + this.symbol = symbol; + this.readyState = "INACTIVE" /* INACTIVE */; + this.emitter = new Emitter(); + this.subscriptions = []; + this.logger = new Logger(symbol.description); + this.emitter.setMaxListeners(0); + this.logger.info("constructing the interceptor..."); + } + /** + * Determine if this interceptor can be applied + * in the current environment. + */ + checkEnvironment() { + return true; + } + /** + * Apply this interceptor to the current process. + * Returns an already running interceptor instance if it's present. + */ + apply() { + const logger = this.logger.extend("apply"); + logger.info("applying the interceptor..."); + if (this.readyState === "APPLIED" /* APPLIED */) { + logger.info("intercepted already applied!"); + return; + } + const shouldApply = this.checkEnvironment(); + if (!shouldApply) { + logger.info("the interceptor cannot be applied in this environment!"); + return; + } + this.readyState = "APPLYING" /* APPLYING */; + const runningInstance = this.getInstance(); + if (runningInstance) { + logger.info("found a running instance, reusing..."); + this.on = (event, listener) => { + logger.info('proxying the "%s" listener', event); + runningInstance.emitter.addListener(event, listener); + this.subscriptions.push(() => { + runningInstance.emitter.removeListener(event, listener); + logger.info('removed proxied "%s" listener!', event); + }); + return this; + }; + this.readyState = "APPLIED" /* APPLIED */; + return; + } + logger.info("no running instance found, setting up a new instance..."); + this.setup(); + this.setInstance(); + this.readyState = "APPLIED" /* APPLIED */; + } + /** + * Setup the module augments and stubs necessary for this interceptor. + * This method is not run if there's a running interceptor instance + * to prevent instantiating an interceptor multiple times. + */ + setup() { + } + /** + * Listen to the interceptor's public events. + */ + on(event, listener) { + const logger = this.logger.extend("on"); + if (this.readyState === "DISPOSING" /* DISPOSING */ || this.readyState === "DISPOSED" /* DISPOSED */) { + logger.info("cannot listen to events, already disposed!"); + return this; + } + logger.info('adding "%s" event listener:', event, listener); + this.emitter.on(event, listener); + return this; + } + once(event, listener) { + this.emitter.once(event, listener); + return this; + } + off(event, listener) { + this.emitter.off(event, listener); + return this; + } + removeAllListeners(event) { + this.emitter.removeAllListeners(event); + return this; + } + /** + * Disposes of any side-effects this interceptor has introduced. + */ + dispose() { + const logger = this.logger.extend("dispose"); + if (this.readyState === "DISPOSED" /* DISPOSED */) { + logger.info("cannot dispose, already disposed!"); + return; + } + logger.info("disposing the interceptor..."); + this.readyState = "DISPOSING" /* DISPOSING */; + if (!this.getInstance()) { + logger.info("no interceptors running, skipping dispose..."); + return; + } + this.clearInstance(); + logger.info("global symbol deleted:", getGlobalSymbol(this.symbol)); + if (this.subscriptions.length > 0) { + logger.info("disposing of %d subscriptions...", this.subscriptions.length); + for (const dispose of this.subscriptions) { + dispose(); + } + this.subscriptions = []; + logger.info("disposed of all subscriptions!", this.subscriptions.length); + } + this.emitter.removeAllListeners(); + logger.info("destroyed the listener!"); + this.readyState = "DISPOSED" /* DISPOSED */; + } + getInstance() { + var _a; + const instance = getGlobalSymbol(this.symbol); + this.logger.info("retrieved global instance:", (_a = instance == null ? void 0 : instance.constructor) == null ? void 0 : _a.name); + return instance; + } + setInstance() { + setGlobalSymbol(this.symbol, this); + this.logger.info("set global instance!", this.symbol.description); + } + clearInstance() { + deleteGlobalSymbol(this.symbol); + this.logger.info("cleared global instance!", this.symbol.description); + } +}; + +// src/createRequestId.ts +function createRequestId() { + return Math.random().toString(16).slice(2); +} + +// src/utils/fetchUtils.ts +var _FetchResponse = class extends Response { + static isConfigurableStatusCode(status) { + return status >= 200 && status <= 599; + } + static isRedirectResponse(status) { + return _FetchResponse.STATUS_CODES_WITH_REDIRECT.includes(status); + } + /** + * Returns a boolean indicating whether the given response status + * code represents a response that can have a body. + */ + static isResponseWithBody(status) { + return !_FetchResponse.STATUS_CODES_WITHOUT_BODY.includes(status); + } + static setUrl(url, response) { + if (!url) { + return; + } + if (response.url != "") { + return; + } + Object.defineProperty(response, "url", { + value: url, + enumerable: true, + configurable: true, + writable: false + }); + } + /** + * Parses the given raw HTTP headers into a Fetch API `Headers` instance. + */ + static parseRawHeaders(rawHeaders) { + const headers = new Headers(); + for (let line = 0; line < rawHeaders.length; line += 2) { + headers.append(rawHeaders[line], rawHeaders[line + 1]); + } + return headers; + } + constructor(body, init = {}) { + var _a; + const status = (_a = init.status) != null ? _a : 200; + const safeStatus = _FetchResponse.isConfigurableStatusCode(status) ? status : 200; + const finalBody = _FetchResponse.isResponseWithBody(status) ? body : null; + super(finalBody, { + ...init, + status: safeStatus + }); + if (status !== safeStatus) { + const stateSymbol = Object.getOwnPropertySymbols(this).find( + (symbol) => symbol.description === "state" + ); + if (stateSymbol) { + const state = Reflect.get(this, stateSymbol); + Reflect.set(state, "status", status); + } else { + Object.defineProperty(this, "status", { + value: status, + enumerable: true, + configurable: true, + writable: false + }); + } + } + _FetchResponse.setUrl(init.url, this); + } +}; +var FetchResponse = _FetchResponse; +/** + * Response status codes for responses that cannot have body. + * @see https://fetch.spec.whatwg.org/#statuses + */ +FetchResponse.STATUS_CODES_WITHOUT_BODY = [101, 103, 204, 205, 304]; +FetchResponse.STATUS_CODES_WITH_REDIRECT = [301, 302, 303, 307, 308]; + +export { + INTERNAL_REQUEST_ID_HEADER_NAME, + getGlobalSymbol, + deleteGlobalSymbol, + InterceptorReadyState, + Interceptor, + createRequestId, + FetchResponse +}; +//# sourceMappingURL=chunk-I7HQIBT7.mjs.map \ No newline at end of file diff --git a/node_modules/@mswjs/interceptors/lib/node/chunk-I7HQIBT7.mjs.map b/node_modules/@mswjs/interceptors/lib/node/chunk-I7HQIBT7.mjs.map new file mode 100644 index 0000000000000000000000000000000000000000..1e38f2cb4f1ae059426f386c9ae8ba9a1c342160 --- /dev/null +++ b/node_modules/@mswjs/interceptors/lib/node/chunk-I7HQIBT7.mjs.map @@ -0,0 +1 @@ +{"version":3,"sources":["../../src/Interceptor.ts","../../src/createRequestId.ts","../../src/utils/fetchUtils.ts"],"sourcesContent":["import { Logger } from '@open-draft/logger'\nimport { Emitter, Listener } from 'strict-event-emitter'\n\nexport type InterceptorEventMap = Record\nexport type InterceptorSubscription = () => void\n\n/**\n * Request header name to detect when a single request\n * is being handled by nested interceptors (XHR -> ClientRequest).\n * Obscure by design to prevent collisions with user-defined headers.\n * Ideally, come up with the Interceptor-level mechanism for this.\n * @see https://github.com/mswjs/interceptors/issues/378\n */\nexport const INTERNAL_REQUEST_ID_HEADER_NAME =\n 'x-interceptors-internal-request-id'\n\nexport function getGlobalSymbol(symbol: Symbol): V | undefined {\n return (\n // @ts-ignore https://github.com/Microsoft/TypeScript/issues/24587\n globalThis[symbol] || undefined\n )\n}\n\nfunction setGlobalSymbol(symbol: Symbol, value: any): void {\n // @ts-ignore\n globalThis[symbol] = value\n}\n\nexport function deleteGlobalSymbol(symbol: Symbol): void {\n // @ts-ignore\n delete globalThis[symbol]\n}\n\nexport enum InterceptorReadyState {\n INACTIVE = 'INACTIVE',\n APPLYING = 'APPLYING',\n APPLIED = 'APPLIED',\n DISPOSING = 'DISPOSING',\n DISPOSED = 'DISPOSED',\n}\n\nexport type ExtractEventNames> =\n Events extends Record ? EventName : never\n\nexport class Interceptor {\n protected emitter: Emitter\n protected subscriptions: Array\n protected logger: Logger\n\n public readyState: InterceptorReadyState\n\n constructor(private readonly symbol: symbol) {\n this.readyState = InterceptorReadyState.INACTIVE\n\n this.emitter = new Emitter()\n this.subscriptions = []\n this.logger = new Logger(symbol.description!)\n\n // Do not limit the maximum number of listeners\n // so not to limit the maximum amount of parallel events emitted.\n this.emitter.setMaxListeners(0)\n\n this.logger.info('constructing the interceptor...')\n }\n\n /**\n * Determine if this interceptor can be applied\n * in the current environment.\n */\n protected checkEnvironment(): boolean {\n return true\n }\n\n /**\n * Apply this interceptor to the current process.\n * Returns an already running interceptor instance if it's present.\n */\n public apply(): void {\n const logger = this.logger.extend('apply')\n logger.info('applying the interceptor...')\n\n if (this.readyState === InterceptorReadyState.APPLIED) {\n logger.info('intercepted already applied!')\n return\n }\n\n const shouldApply = this.checkEnvironment()\n\n if (!shouldApply) {\n logger.info('the interceptor cannot be applied in this environment!')\n return\n }\n\n this.readyState = InterceptorReadyState.APPLYING\n\n // Whenever applying a new interceptor, check if it hasn't been applied already.\n // This enables to apply the same interceptor multiple times, for example from a different\n // interceptor, only proxying events but keeping the stubs in a single place.\n const runningInstance = this.getInstance()\n\n if (runningInstance) {\n logger.info('found a running instance, reusing...')\n\n // Proxy any listeners you set on this instance to the running instance.\n this.on = (event, listener) => {\n logger.info('proxying the \"%s\" listener', event)\n\n // Add listeners to the running instance so they appear\n // at the top of the event listeners list and are executed first.\n runningInstance.emitter.addListener(event, listener)\n\n // Ensure that once this interceptor instance is disposed,\n // it removes all listeners it has appended to the running interceptor instance.\n this.subscriptions.push(() => {\n runningInstance.emitter.removeListener(event, listener)\n logger.info('removed proxied \"%s\" listener!', event)\n })\n\n return this\n }\n\n this.readyState = InterceptorReadyState.APPLIED\n\n return\n }\n\n logger.info('no running instance found, setting up a new instance...')\n\n // Setup the interceptor.\n this.setup()\n\n // Store the newly applied interceptor instance globally.\n this.setInstance()\n\n this.readyState = InterceptorReadyState.APPLIED\n }\n\n /**\n * Setup the module augments and stubs necessary for this interceptor.\n * This method is not run if there's a running interceptor instance\n * to prevent instantiating an interceptor multiple times.\n */\n protected setup(): void {}\n\n /**\n * Listen to the interceptor's public events.\n */\n public on>(\n event: EventName,\n listener: Listener\n ): this {\n const logger = this.logger.extend('on')\n\n if (\n this.readyState === InterceptorReadyState.DISPOSING ||\n this.readyState === InterceptorReadyState.DISPOSED\n ) {\n logger.info('cannot listen to events, already disposed!')\n return this\n }\n\n logger.info('adding \"%s\" event listener:', event, listener)\n\n this.emitter.on(event, listener)\n return this\n }\n\n public once>(\n event: EventName,\n listener: Listener\n ): this {\n this.emitter.once(event, listener)\n return this\n }\n\n public off>(\n event: EventName,\n listener: Listener\n ): this {\n this.emitter.off(event, listener)\n return this\n }\n\n public removeAllListeners>(\n event?: EventName\n ): this {\n this.emitter.removeAllListeners(event)\n return this\n }\n\n /**\n * Disposes of any side-effects this interceptor has introduced.\n */\n public dispose(): void {\n const logger = this.logger.extend('dispose')\n\n if (this.readyState === InterceptorReadyState.DISPOSED) {\n logger.info('cannot dispose, already disposed!')\n return\n }\n\n logger.info('disposing the interceptor...')\n this.readyState = InterceptorReadyState.DISPOSING\n\n if (!this.getInstance()) {\n logger.info('no interceptors running, skipping dispose...')\n return\n }\n\n // Delete the global symbol as soon as possible,\n // indicating that the interceptor is no longer running.\n this.clearInstance()\n\n logger.info('global symbol deleted:', getGlobalSymbol(this.symbol))\n\n if (this.subscriptions.length > 0) {\n logger.info('disposing of %d subscriptions...', this.subscriptions.length)\n\n for (const dispose of this.subscriptions) {\n dispose()\n }\n\n this.subscriptions = []\n\n logger.info('disposed of all subscriptions!', this.subscriptions.length)\n }\n\n this.emitter.removeAllListeners()\n logger.info('destroyed the listener!')\n\n this.readyState = InterceptorReadyState.DISPOSED\n }\n\n private getInstance(): this | undefined {\n const instance = getGlobalSymbol(this.symbol)\n this.logger.info('retrieved global instance:', instance?.constructor?.name)\n return instance\n }\n\n private setInstance(): void {\n setGlobalSymbol(this.symbol, this)\n this.logger.info('set global instance!', this.symbol.description)\n }\n\n private clearInstance(): void {\n deleteGlobalSymbol(this.symbol)\n this.logger.info('cleared global instance!', this.symbol.description)\n }\n}\n","/**\n * Generate a random ID string to represent a request.\n * @example\n * createRequestId()\n * // \"f774b6c9c600f\"\n */\nexport function createRequestId(): string {\n return Math.random().toString(16).slice(2)\n}\n","export interface FetchResponseInit extends ResponseInit {\n url?: string\n}\n\nexport class FetchResponse extends Response {\n /**\n * Response status codes for responses that cannot have body.\n * @see https://fetch.spec.whatwg.org/#statuses\n */\n static readonly STATUS_CODES_WITHOUT_BODY = [101, 103, 204, 205, 304]\n\n static readonly STATUS_CODES_WITH_REDIRECT = [301, 302, 303, 307, 308]\n\n static isConfigurableStatusCode(status: number): boolean {\n return status >= 200 && status <= 599\n }\n\n static isRedirectResponse(status: number): boolean {\n return FetchResponse.STATUS_CODES_WITH_REDIRECT.includes(status)\n }\n\n /**\n * Returns a boolean indicating whether the given response status\n * code represents a response that can have a body.\n */\n static isResponseWithBody(status: number): boolean {\n return !FetchResponse.STATUS_CODES_WITHOUT_BODY.includes(status)\n }\n\n static setUrl(url: string | undefined, response: Response): void {\n if (!url) {\n return\n }\n\n if (response.url != '') {\n return\n }\n\n Object.defineProperty(response, 'url', {\n value: url,\n enumerable: true,\n configurable: true,\n writable: false,\n })\n }\n\n /**\n * Parses the given raw HTTP headers into a Fetch API `Headers` instance.\n */\n static parseRawHeaders(rawHeaders: Array): Headers {\n const headers = new Headers()\n for (let line = 0; line < rawHeaders.length; line += 2) {\n headers.append(rawHeaders[line], rawHeaders[line + 1])\n }\n return headers\n }\n\n constructor(body?: BodyInit | null, init: FetchResponseInit = {}) {\n const status = init.status ?? 200\n const safeStatus = FetchResponse.isConfigurableStatusCode(status)\n ? status\n : 200\n const finalBody = FetchResponse.isResponseWithBody(status) ? body : null\n\n super(finalBody, {\n ...init,\n status: safeStatus,\n })\n\n if (status !== safeStatus) {\n /**\n * @note Undici keeps an internal \"Symbol(state)\" that holds\n * the actual value of response status. Update that in Node.js.\n */\n const stateSymbol = Object.getOwnPropertySymbols(this).find(\n (symbol) => symbol.description === 'state'\n )\n if (stateSymbol) {\n const state = Reflect.get(this, stateSymbol) as object\n Reflect.set(state, 'status', status)\n } else {\n Object.defineProperty(this, 'status', {\n value: status,\n enumerable: true,\n configurable: true,\n writable: false,\n })\n }\n }\n\n FetchResponse.setUrl(init.url, this)\n }\n}\n"],"mappings":"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","names":["InterceptorReadyState"]} \ No newline at end of file diff --git a/node_modules/@mswjs/interceptors/lib/node/chunk-LCA4FKWY.js b/node_modules/@mswjs/interceptors/lib/node/chunk-LCA4FKWY.js new file mode 100644 index 0000000000000000000000000000000000000000..e386d612dfd5093945e36e87445535b32e4c8b82 --- /dev/null +++ b/node_modules/@mswjs/interceptors/lib/node/chunk-LCA4FKWY.js @@ -0,0 +1,844 @@ +"use strict";Object.defineProperty(exports, "__esModule", {value: true}); + + + +var _chunkLK6DILFKjs = require('./chunk-LK6DILFK.js'); + + +var _chunkPFGO5BSMjs = require('./chunk-PFGO5BSM.js'); + + +var _chunk73NOP3T5js = require('./chunk-73NOP3T5.js'); + + + +var _chunk6L3PFBGTjs = require('./chunk-6L3PFBGT.js'); + + + + + +var _chunkWZTE4PCOjs = require('./chunk-WZTE4PCO.js'); + +// src/interceptors/XMLHttpRequest/index.ts +var _outvariant = require('outvariant'); + +// src/interceptors/XMLHttpRequest/XMLHttpRequestController.ts + +var _isnodeprocess = require('is-node-process'); + +// src/interceptors/XMLHttpRequest/utils/concatArrayBuffer.ts +function concatArrayBuffer(left, right) { + const result = new Uint8Array(left.byteLength + right.byteLength); + result.set(left, 0); + result.set(right, left.byteLength); + return result; +} + +// src/interceptors/XMLHttpRequest/polyfills/EventPolyfill.ts +var EventPolyfill = class { + constructor(type, options) { + this.NONE = 0; + this.CAPTURING_PHASE = 1; + this.AT_TARGET = 2; + this.BUBBLING_PHASE = 3; + this.type = ""; + this.srcElement = null; + this.currentTarget = null; + this.eventPhase = 0; + this.isTrusted = true; + this.composed = false; + this.cancelable = true; + this.defaultPrevented = false; + this.bubbles = true; + this.lengthComputable = true; + this.loaded = 0; + this.total = 0; + this.cancelBubble = false; + this.returnValue = true; + this.type = type; + this.target = (options == null ? void 0 : options.target) || null; + this.currentTarget = (options == null ? void 0 : options.currentTarget) || null; + this.timeStamp = Date.now(); + } + composedPath() { + return []; + } + initEvent(type, bubbles, cancelable) { + this.type = type; + this.bubbles = !!bubbles; + this.cancelable = !!cancelable; + } + preventDefault() { + this.defaultPrevented = true; + } + stopPropagation() { + } + stopImmediatePropagation() { + } +}; + +// src/interceptors/XMLHttpRequest/polyfills/ProgressEventPolyfill.ts +var ProgressEventPolyfill = class extends EventPolyfill { + constructor(type, init) { + super(type); + this.lengthComputable = (init == null ? void 0 : init.lengthComputable) || false; + this.composed = (init == null ? void 0 : init.composed) || false; + this.loaded = (init == null ? void 0 : init.loaded) || 0; + this.total = (init == null ? void 0 : init.total) || 0; + } +}; + +// src/interceptors/XMLHttpRequest/utils/createEvent.ts +var SUPPORTS_PROGRESS_EVENT = typeof ProgressEvent !== "undefined"; +function createEvent(target, type, init) { + const progressEvents = [ + "error", + "progress", + "loadstart", + "loadend", + "load", + "timeout", + "abort" + ]; + const ProgressEventClass = SUPPORTS_PROGRESS_EVENT ? ProgressEvent : ProgressEventPolyfill; + const event = progressEvents.includes(type) ? new ProgressEventClass(type, { + lengthComputable: true, + loaded: (init == null ? void 0 : init.loaded) || 0, + total: (init == null ? void 0 : init.total) || 0 + }) : new EventPolyfill(type, { + target, + currentTarget: target + }); + return event; +} + +// src/utils/findPropertySource.ts +function findPropertySource(target, propertyName) { + if (!(propertyName in target)) { + return null; + } + const hasProperty = Object.prototype.hasOwnProperty.call(target, propertyName); + if (hasProperty) { + return target; + } + const prototype = Reflect.getPrototypeOf(target); + return prototype ? findPropertySource(prototype, propertyName) : null; +} + +// src/utils/createProxy.ts +function createProxy(target, options) { + const proxy = new Proxy(target, optionsToProxyHandler(options)); + return proxy; +} +function optionsToProxyHandler(options) { + const { constructorCall, methodCall, getProperty, setProperty } = options; + const handler = {}; + if (typeof constructorCall !== "undefined") { + handler.construct = function(target, args, newTarget) { + const next = Reflect.construct.bind(null, target, args, newTarget); + return constructorCall.call(newTarget, args, next); + }; + } + handler.set = function(target, propertyName, nextValue) { + const next = () => { + const propertySource = findPropertySource(target, propertyName) || target; + const ownDescriptors = Reflect.getOwnPropertyDescriptor( + propertySource, + propertyName + ); + if (typeof (ownDescriptors == null ? void 0 : ownDescriptors.set) !== "undefined") { + ownDescriptors.set.apply(target, [nextValue]); + return true; + } + return Reflect.defineProperty(propertySource, propertyName, { + writable: true, + enumerable: true, + configurable: true, + value: nextValue + }); + }; + if (typeof setProperty !== "undefined") { + return setProperty.call(target, [propertyName, nextValue], next); + } + return next(); + }; + handler.get = function(target, propertyName, receiver) { + const next = () => target[propertyName]; + const value = typeof getProperty !== "undefined" ? getProperty.call(target, [propertyName, receiver], next) : next(); + if (typeof value === "function") { + return (...args) => { + const next2 = value.bind(target, ...args); + if (typeof methodCall !== "undefined") { + return methodCall.call(target, [propertyName, args], next2); + } + return next2(); + }; + } + return value; + }; + return handler; +} + +// src/interceptors/XMLHttpRequest/utils/isDomParserSupportedType.ts +function isDomParserSupportedType(type) { + const supportedTypes = [ + "application/xhtml+xml", + "application/xml", + "image/svg+xml", + "text/html", + "text/xml" + ]; + return supportedTypes.some((supportedType) => { + return type.startsWith(supportedType); + }); +} + +// src/utils/parseJson.ts +function parseJson(data) { + try { + const json = JSON.parse(data); + return json; + } catch (_) { + return null; + } +} + +// src/interceptors/XMLHttpRequest/utils/createResponse.ts +function createResponse(request, body) { + const responseBodyOrNull = _chunkWZTE4PCOjs.FetchResponse.isResponseWithBody(request.status) ? body : null; + return new (0, _chunkWZTE4PCOjs.FetchResponse)(responseBodyOrNull, { + url: request.responseURL, + status: request.status, + statusText: request.statusText, + headers: createHeadersFromXMLHttpReqestHeaders( + request.getAllResponseHeaders() + ) + }); +} +function createHeadersFromXMLHttpReqestHeaders(headersString) { + const headers = new Headers(); + const lines = headersString.split(/[\r\n]+/); + for (const line of lines) { + if (line.trim() === "") { + continue; + } + const [name, ...parts] = line.split(": "); + const value = parts.join(": "); + headers.append(name, value); + } + return headers; +} + +// src/interceptors/XMLHttpRequest/utils/getBodyByteLength.ts +async function getBodyByteLength(input) { + const explicitContentLength = input.headers.get("content-length"); + if (explicitContentLength != null && explicitContentLength !== "") { + return Number(explicitContentLength); + } + const buffer = await input.arrayBuffer(); + return buffer.byteLength; +} + +// src/interceptors/XMLHttpRequest/XMLHttpRequestController.ts +var kIsRequestHandled = Symbol("kIsRequestHandled"); +var IS_NODE = _isnodeprocess.isNodeProcess.call(void 0, ); +var kFetchRequest = Symbol("kFetchRequest"); +var XMLHttpRequestController = class { + constructor(initialRequest, logger) { + this.initialRequest = initialRequest; + this.logger = logger; + this.method = "GET"; + this.url = null; + this[kIsRequestHandled] = false; + this.events = /* @__PURE__ */ new Map(); + this.uploadEvents = /* @__PURE__ */ new Map(); + this.requestId = _chunkWZTE4PCOjs.createRequestId.call(void 0, ); + this.requestHeaders = new Headers(); + this.responseBuffer = new Uint8Array(); + this.request = createProxy(initialRequest, { + setProperty: ([propertyName, nextValue], invoke) => { + switch (propertyName) { + case "ontimeout": { + const eventName = propertyName.slice( + 2 + ); + this.request.addEventListener(eventName, nextValue); + return invoke(); + } + default: { + return invoke(); + } + } + }, + methodCall: ([methodName, args], invoke) => { + var _a; + switch (methodName) { + case "open": { + const [method, url] = args; + if (typeof url === "undefined") { + this.method = "GET"; + this.url = toAbsoluteUrl(method); + } else { + this.method = method; + this.url = toAbsoluteUrl(url); + } + this.logger = this.logger.extend(`${this.method} ${this.url.href}`); + this.logger.info("open", this.method, this.url.href); + return invoke(); + } + case "addEventListener": { + const [eventName, listener] = args; + this.registerEvent(eventName, listener); + this.logger.info("addEventListener", eventName, listener); + return invoke(); + } + case "setRequestHeader": { + const [name, value] = args; + this.requestHeaders.set(name, value); + this.logger.info("setRequestHeader", name, value); + return invoke(); + } + case "send": { + const [body] = args; + this.request.addEventListener("load", () => { + if (typeof this.onResponse !== "undefined") { + const fetchResponse = createResponse( + this.request, + /** + * The `response` property is the right way to read + * the ambiguous response body, as the request's "responseType" may differ. + * @see https://xhr.spec.whatwg.org/#the-response-attribute + */ + this.request.response + ); + this.onResponse.call(this, { + response: fetchResponse, + isMockedResponse: this[kIsRequestHandled], + request: fetchRequest, + requestId: this.requestId + }); + } + }); + const requestBody = typeof body === "string" ? _chunkLK6DILFKjs.encodeBuffer.call(void 0, body) : body; + const fetchRequest = this.toFetchApiRequest(requestBody); + this[kFetchRequest] = fetchRequest.clone(); + const onceRequestSettled = ((_a = this.onRequest) == null ? void 0 : _a.call(this, { + request: fetchRequest, + requestId: this.requestId + })) || Promise.resolve(); + onceRequestSettled.finally(() => { + if (!this[kIsRequestHandled]) { + this.logger.info( + "request callback settled but request has not been handled (readystate %d), performing as-is...", + this.request.readyState + ); + if (IS_NODE) { + this.request.setRequestHeader( + _chunkWZTE4PCOjs.INTERNAL_REQUEST_ID_HEADER_NAME, + this.requestId + ); + } + return invoke(); + } + }); + break; + } + default: { + return invoke(); + } + } + } + }); + define( + this.request, + "upload", + createProxy(this.request.upload, { + setProperty: ([propertyName, nextValue], invoke) => { + switch (propertyName) { + case "onloadstart": + case "onprogress": + case "onaboart": + case "onerror": + case "onload": + case "ontimeout": + case "onloadend": { + const eventName = propertyName.slice( + 2 + ); + this.registerUploadEvent(eventName, nextValue); + } + } + return invoke(); + }, + methodCall: ([methodName, args], invoke) => { + switch (methodName) { + case "addEventListener": { + const [eventName, listener] = args; + this.registerUploadEvent(eventName, listener); + this.logger.info("upload.addEventListener", eventName, listener); + return invoke(); + } + } + } + }) + ); + } + registerEvent(eventName, listener) { + const prevEvents = this.events.get(eventName) || []; + const nextEvents = prevEvents.concat(listener); + this.events.set(eventName, nextEvents); + this.logger.info('registered event "%s"', eventName, listener); + } + registerUploadEvent(eventName, listener) { + const prevEvents = this.uploadEvents.get(eventName) || []; + const nextEvents = prevEvents.concat(listener); + this.uploadEvents.set(eventName, nextEvents); + this.logger.info('registered upload event "%s"', eventName, listener); + } + /** + * Responds to the current request with the given + * Fetch API `Response` instance. + */ + async respondWith(response) { + this[kIsRequestHandled] = true; + if (this[kFetchRequest]) { + const totalRequestBodyLength = await getBodyByteLength( + this[kFetchRequest] + ); + this.trigger("loadstart", this.request.upload, { + loaded: 0, + total: totalRequestBodyLength + }); + this.trigger("progress", this.request.upload, { + loaded: totalRequestBodyLength, + total: totalRequestBodyLength + }); + this.trigger("load", this.request.upload, { + loaded: totalRequestBodyLength, + total: totalRequestBodyLength + }); + this.trigger("loadend", this.request.upload, { + loaded: totalRequestBodyLength, + total: totalRequestBodyLength + }); + } + this.logger.info( + "responding with a mocked response: %d %s", + response.status, + response.statusText + ); + define(this.request, "status", response.status); + define(this.request, "statusText", response.statusText); + define(this.request, "responseURL", this.url.href); + this.request.getResponseHeader = new Proxy(this.request.getResponseHeader, { + apply: (_, __, args) => { + this.logger.info("getResponseHeader", args[0]); + if (this.request.readyState < this.request.HEADERS_RECEIVED) { + this.logger.info("headers not received yet, returning null"); + return null; + } + const headerValue = response.headers.get(args[0]); + this.logger.info( + 'resolved response header "%s" to', + args[0], + headerValue + ); + return headerValue; + } + }); + this.request.getAllResponseHeaders = new Proxy( + this.request.getAllResponseHeaders, + { + apply: () => { + this.logger.info("getAllResponseHeaders"); + if (this.request.readyState < this.request.HEADERS_RECEIVED) { + this.logger.info("headers not received yet, returning empty string"); + return ""; + } + const headersList = Array.from(response.headers.entries()); + const allHeaders = headersList.map(([headerName, headerValue]) => { + return `${headerName}: ${headerValue}`; + }).join("\r\n"); + this.logger.info("resolved all response headers to", allHeaders); + return allHeaders; + } + } + ); + Object.defineProperties(this.request, { + response: { + enumerable: true, + configurable: false, + get: () => this.response + }, + responseText: { + enumerable: true, + configurable: false, + get: () => this.responseText + }, + responseXML: { + enumerable: true, + configurable: false, + get: () => this.responseXML + } + }); + const totalResponseBodyLength = await getBodyByteLength(response.clone()); + this.logger.info("calculated response body length", totalResponseBodyLength); + this.trigger("loadstart", this.request, { + loaded: 0, + total: totalResponseBodyLength + }); + this.setReadyState(this.request.HEADERS_RECEIVED); + this.setReadyState(this.request.LOADING); + const finalizeResponse = () => { + this.logger.info("finalizing the mocked response..."); + this.setReadyState(this.request.DONE); + this.trigger("load", this.request, { + loaded: this.responseBuffer.byteLength, + total: totalResponseBodyLength + }); + this.trigger("loadend", this.request, { + loaded: this.responseBuffer.byteLength, + total: totalResponseBodyLength + }); + }; + if (response.body) { + this.logger.info("mocked response has body, streaming..."); + const reader = response.body.getReader(); + const readNextResponseBodyChunk = async () => { + const { value, done } = await reader.read(); + if (done) { + this.logger.info("response body stream done!"); + finalizeResponse(); + return; + } + if (value) { + this.logger.info("read response body chunk:", value); + this.responseBuffer = concatArrayBuffer(this.responseBuffer, value); + this.trigger("progress", this.request, { + loaded: this.responseBuffer.byteLength, + total: totalResponseBodyLength + }); + } + readNextResponseBodyChunk(); + }; + readNextResponseBodyChunk(); + } else { + finalizeResponse(); + } + } + responseBufferToText() { + return _chunkLK6DILFKjs.decodeBuffer.call(void 0, this.responseBuffer); + } + get response() { + this.logger.info( + "getResponse (responseType: %s)", + this.request.responseType + ); + if (this.request.readyState !== this.request.DONE) { + return null; + } + switch (this.request.responseType) { + case "json": { + const responseJson = parseJson(this.responseBufferToText()); + this.logger.info("resolved response JSON", responseJson); + return responseJson; + } + case "arraybuffer": { + const arrayBuffer = _chunkLK6DILFKjs.toArrayBuffer.call(void 0, this.responseBuffer); + this.logger.info("resolved response ArrayBuffer", arrayBuffer); + return arrayBuffer; + } + case "blob": { + const mimeType = this.request.getResponseHeader("Content-Type") || "text/plain"; + const responseBlob = new Blob([this.responseBufferToText()], { + type: mimeType + }); + this.logger.info( + "resolved response Blob (mime type: %s)", + responseBlob, + mimeType + ); + return responseBlob; + } + default: { + const responseText = this.responseBufferToText(); + this.logger.info( + 'resolving "%s" response type as text', + this.request.responseType, + responseText + ); + return responseText; + } + } + } + get responseText() { + _outvariant.invariant.call(void 0, + this.request.responseType === "" || this.request.responseType === "text", + "InvalidStateError: The object is in invalid state." + ); + if (this.request.readyState !== this.request.LOADING && this.request.readyState !== this.request.DONE) { + return ""; + } + const responseText = this.responseBufferToText(); + this.logger.info('getResponseText: "%s"', responseText); + return responseText; + } + get responseXML() { + _outvariant.invariant.call(void 0, + this.request.responseType === "" || this.request.responseType === "document", + "InvalidStateError: The object is in invalid state." + ); + if (this.request.readyState !== this.request.DONE) { + return null; + } + const contentType = this.request.getResponseHeader("Content-Type") || ""; + if (typeof DOMParser === "undefined") { + console.warn( + "Cannot retrieve XMLHttpRequest response body as XML: DOMParser is not defined. You are likely using an environment that is not browser or does not polyfill browser globals correctly." + ); + return null; + } + if (isDomParserSupportedType(contentType)) { + return new DOMParser().parseFromString( + this.responseBufferToText(), + contentType + ); + } + return null; + } + errorWith(error) { + this[kIsRequestHandled] = true; + this.logger.info("responding with an error"); + this.setReadyState(this.request.DONE); + this.trigger("error", this.request); + this.trigger("loadend", this.request); + } + /** + * Transitions this request's `readyState` to the given one. + */ + setReadyState(nextReadyState) { + this.logger.info( + "setReadyState: %d -> %d", + this.request.readyState, + nextReadyState + ); + if (this.request.readyState === nextReadyState) { + this.logger.info("ready state identical, skipping transition..."); + return; + } + define(this.request, "readyState", nextReadyState); + this.logger.info("set readyState to: %d", nextReadyState); + if (nextReadyState !== this.request.UNSENT) { + this.logger.info('triggerring "readystatechange" event...'); + this.trigger("readystatechange", this.request); + } + } + /** + * Triggers given event on the `XMLHttpRequest` instance. + */ + trigger(eventName, target, options) { + const callback = target[`on${eventName}`]; + const event = createEvent(target, eventName, options); + this.logger.info('trigger "%s"', eventName, options || ""); + if (typeof callback === "function") { + this.logger.info('found a direct "%s" callback, calling...', eventName); + callback.call(target, event); + } + const events = target instanceof XMLHttpRequestUpload ? this.uploadEvents : this.events; + for (const [registeredEventName, listeners] of events) { + if (registeredEventName === eventName) { + this.logger.info( + 'found %d listener(s) for "%s" event, calling...', + listeners.length, + eventName + ); + listeners.forEach((listener) => listener.call(target, event)); + } + } + } + /** + * Converts this `XMLHttpRequest` instance into a Fetch API `Request` instance. + */ + toFetchApiRequest(body) { + this.logger.info("converting request to a Fetch API Request..."); + const resolvedBody = body instanceof Document ? body.documentElement.innerText : body; + const fetchRequest = new Request(this.url.href, { + method: this.method, + headers: this.requestHeaders, + /** + * @see https://xhr.spec.whatwg.org/#cross-origin-credentials + */ + credentials: this.request.withCredentials ? "include" : "same-origin", + body: ["GET", "HEAD"].includes(this.method.toUpperCase()) ? null : resolvedBody + }); + const proxyHeaders = createProxy(fetchRequest.headers, { + methodCall: ([methodName, args], invoke) => { + switch (methodName) { + case "append": + case "set": { + const [headerName, headerValue] = args; + this.request.setRequestHeader(headerName, headerValue); + break; + } + case "delete": { + const [headerName] = args; + console.warn( + `XMLHttpRequest: Cannot remove a "${headerName}" header from the Fetch API representation of the "${fetchRequest.method} ${fetchRequest.url}" request. XMLHttpRequest headers cannot be removed.` + ); + break; + } + } + return invoke(); + } + }); + define(fetchRequest, "headers", proxyHeaders); + this.logger.info("converted request to a Fetch API Request!", fetchRequest); + return fetchRequest; + } +}; +kIsRequestHandled, kFetchRequest; +function toAbsoluteUrl(url) { + if (typeof location === "undefined") { + return new URL(url); + } + return new URL(url.toString(), location.href); +} +function define(target, property, value) { + Reflect.defineProperty(target, property, { + // Ensure writable properties to allow redefining readonly properties. + writable: true, + enumerable: true, + value + }); +} + +// src/interceptors/XMLHttpRequest/XMLHttpRequestProxy.ts +function createXMLHttpRequestProxy({ + emitter, + logger +}) { + const XMLHttpRequestProxy = new Proxy(globalThis.XMLHttpRequest, { + construct(target, args, newTarget) { + logger.info("constructed new XMLHttpRequest"); + const originalRequest = Reflect.construct( + target, + args, + newTarget + ); + const prototypeDescriptors = Object.getOwnPropertyDescriptors( + target.prototype + ); + for (const propertyName in prototypeDescriptors) { + Reflect.defineProperty( + originalRequest, + propertyName, + prototypeDescriptors[propertyName] + ); + } + const xhrRequestController = new XMLHttpRequestController( + originalRequest, + logger + ); + xhrRequestController.onRequest = async function({ request, requestId }) { + const controller = new (0, _chunk6L3PFBGTjs.RequestController)(request); + this.logger.info("awaiting mocked response..."); + this.logger.info( + 'emitting the "request" event for %s listener(s)...', + emitter.listenerCount("request") + ); + const isRequestHandled = await _chunk6L3PFBGTjs.handleRequest.call(void 0, { + request, + requestId, + controller, + emitter, + onResponse: async (response) => { + await this.respondWith(response); + }, + onRequestError: () => { + this.errorWith(new TypeError("Network error")); + }, + onError: (error) => { + this.logger.info("request errored!", { error }); + if (error instanceof Error) { + this.errorWith(error); + } + } + }); + if (!isRequestHandled) { + this.logger.info( + "no mocked response received, performing request as-is..." + ); + } + }; + xhrRequestController.onResponse = async function({ + response, + isMockedResponse, + request, + requestId + }) { + this.logger.info( + 'emitting the "response" event for %s listener(s)...', + emitter.listenerCount("response") + ); + emitter.emit("response", { + response, + isMockedResponse, + request, + requestId + }); + }; + return xhrRequestController.request; + } + }); + return XMLHttpRequestProxy; +} + +// src/interceptors/XMLHttpRequest/index.ts +var _XMLHttpRequestInterceptor = class extends _chunkWZTE4PCOjs.Interceptor { + constructor() { + super(_XMLHttpRequestInterceptor.interceptorSymbol); + } + checkEnvironment() { + return _chunkPFGO5BSMjs.hasConfigurableGlobal.call(void 0, "XMLHttpRequest"); + } + setup() { + const logger = this.logger.extend("setup"); + logger.info('patching "XMLHttpRequest" module...'); + const PureXMLHttpRequest = globalThis.XMLHttpRequest; + _outvariant.invariant.call(void 0, + !PureXMLHttpRequest[_chunk73NOP3T5js.IS_PATCHED_MODULE], + 'Failed to patch the "XMLHttpRequest" module: already patched.' + ); + globalThis.XMLHttpRequest = createXMLHttpRequestProxy({ + emitter: this.emitter, + logger: this.logger + }); + logger.info( + 'native "XMLHttpRequest" module patched!', + globalThis.XMLHttpRequest.name + ); + Object.defineProperty(globalThis.XMLHttpRequest, _chunk73NOP3T5js.IS_PATCHED_MODULE, { + enumerable: true, + configurable: true, + value: true + }); + this.subscriptions.push(() => { + Object.defineProperty(globalThis.XMLHttpRequest, _chunk73NOP3T5js.IS_PATCHED_MODULE, { + value: void 0 + }); + globalThis.XMLHttpRequest = PureXMLHttpRequest; + logger.info( + 'native "XMLHttpRequest" module restored!', + globalThis.XMLHttpRequest.name + ); + }); + } +}; +var XMLHttpRequestInterceptor = _XMLHttpRequestInterceptor; +XMLHttpRequestInterceptor.interceptorSymbol = Symbol("xhr"); + + + +exports.XMLHttpRequestInterceptor = XMLHttpRequestInterceptor; +//# sourceMappingURL=chunk-LCA4FKWY.js.map \ No newline at end of file diff --git a/node_modules/@mswjs/interceptors/lib/node/chunk-LCA4FKWY.js.map b/node_modules/@mswjs/interceptors/lib/node/chunk-LCA4FKWY.js.map new file mode 100644 index 0000000000000000000000000000000000000000..dcd5d0b31b357e198244c80da143f952a0b74c92 --- /dev/null +++ b/node_modules/@mswjs/interceptors/lib/node/chunk-LCA4FKWY.js.map @@ -0,0 +1 @@ +{"version":3,"sources":["../../src/interceptors/XMLHttpRequest/index.ts","../../src/interceptors/XMLHttpRequest/XMLHttpRequestController.ts","../../src/interceptors/XMLHttpRequest/utils/concatArrayBuffer.ts","../../src/interceptors/XMLHttpRequest/polyfills/EventPolyfill.ts","../../src/interceptors/XMLHttpRequest/polyfills/ProgressEventPolyfill.ts","../../src/interceptors/XMLHttpRequest/utils/createEvent.ts","../../src/utils/findPropertySource.ts","../../src/utils/createProxy.ts","../../src/interceptors/XMLHttpRequest/utils/isDomParserSupportedType.ts","../../src/utils/parseJson.ts","../../src/interceptors/XMLHttpRequest/utils/createResponse.ts","../../src/interceptors/XMLHttpRequest/utils/getBodyByteLength.ts","../../src/interceptors/XMLHttpRequest/XMLHttpRequestProxy.ts"],"names":["invariant","next"],"mappings":"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","sourcesContent":["import { invariant } from 'outvariant'\nimport { Emitter } from 'strict-event-emitter'\nimport { HttpRequestEventMap, IS_PATCHED_MODULE } from '../../glossary'\nimport { Interceptor } from '../../Interceptor'\nimport { createXMLHttpRequestProxy } from './XMLHttpRequestProxy'\nimport { hasConfigurableGlobal } from '../../utils/hasConfigurableGlobal'\n\nexport type XMLHttpRequestEmitter = Emitter\n\nexport class XMLHttpRequestInterceptor extends Interceptor {\n static interceptorSymbol = Symbol('xhr')\n\n constructor() {\n super(XMLHttpRequestInterceptor.interceptorSymbol)\n }\n\n protected checkEnvironment() {\n return hasConfigurableGlobal('XMLHttpRequest')\n }\n\n protected setup() {\n const logger = this.logger.extend('setup')\n\n logger.info('patching \"XMLHttpRequest\" module...')\n\n const PureXMLHttpRequest = globalThis.XMLHttpRequest\n\n invariant(\n !(PureXMLHttpRequest as any)[IS_PATCHED_MODULE],\n 'Failed to patch the \"XMLHttpRequest\" module: already patched.'\n )\n\n globalThis.XMLHttpRequest = createXMLHttpRequestProxy({\n emitter: this.emitter,\n logger: this.logger,\n })\n\n logger.info(\n 'native \"XMLHttpRequest\" module patched!',\n globalThis.XMLHttpRequest.name\n )\n\n Object.defineProperty(globalThis.XMLHttpRequest, IS_PATCHED_MODULE, {\n enumerable: true,\n configurable: true,\n value: true,\n })\n\n this.subscriptions.push(() => {\n Object.defineProperty(globalThis.XMLHttpRequest, IS_PATCHED_MODULE, {\n value: undefined,\n })\n\n globalThis.XMLHttpRequest = PureXMLHttpRequest\n logger.info(\n 'native \"XMLHttpRequest\" module restored!',\n globalThis.XMLHttpRequest.name\n )\n })\n }\n}\n","import { invariant } from 'outvariant'\nimport { isNodeProcess } from 'is-node-process'\nimport type { Logger } from '@open-draft/logger'\nimport { concatArrayBuffer } from './utils/concatArrayBuffer'\nimport { createEvent } from './utils/createEvent'\nimport {\n decodeBuffer,\n encodeBuffer,\n toArrayBuffer,\n} from '../../utils/bufferUtils'\nimport { createProxy } from '../../utils/createProxy'\nimport { isDomParserSupportedType } from './utils/isDomParserSupportedType'\nimport { parseJson } from '../../utils/parseJson'\nimport { createResponse } from './utils/createResponse'\nimport { INTERNAL_REQUEST_ID_HEADER_NAME } from '../../Interceptor'\nimport { createRequestId } from '../../createRequestId'\nimport { getBodyByteLength } from './utils/getBodyByteLength'\n\nconst kIsRequestHandled = Symbol('kIsRequestHandled')\nconst IS_NODE = isNodeProcess()\nconst kFetchRequest = Symbol('kFetchRequest')\n\n/**\n * An `XMLHttpRequest` instance controller that allows us\n * to handle any given request instance (e.g. responding to it).\n */\nexport class XMLHttpRequestController {\n public request: XMLHttpRequest\n public requestId: string\n public onRequest?: (\n this: XMLHttpRequestController,\n args: {\n request: Request\n requestId: string\n }\n ) => Promise\n public onResponse?: (\n this: XMLHttpRequestController,\n args: {\n response: Response\n isMockedResponse: boolean\n request: Request\n requestId: string\n }\n ) => void;\n\n [kIsRequestHandled]: boolean;\n [kFetchRequest]?: Request\n private method: string = 'GET'\n private url: URL = null as any\n private requestHeaders: Headers\n private responseBuffer: Uint8Array\n private events: Map>\n private uploadEvents: Map<\n keyof XMLHttpRequestEventTargetEventMap,\n Array\n >\n\n constructor(readonly initialRequest: XMLHttpRequest, public logger: Logger) {\n this[kIsRequestHandled] = false\n\n this.events = new Map()\n this.uploadEvents = new Map()\n this.requestId = createRequestId()\n this.requestHeaders = new Headers()\n this.responseBuffer = new Uint8Array()\n\n this.request = createProxy(initialRequest, {\n setProperty: ([propertyName, nextValue], invoke) => {\n switch (propertyName) {\n case 'ontimeout': {\n const eventName = propertyName.slice(\n 2\n ) as keyof XMLHttpRequestEventTargetEventMap\n\n /**\n * @note Proxy callbacks to event listeners because JSDOM has trouble\n * translating these properties to callbacks. It seemed to be operating\n * on events exclusively.\n */\n this.request.addEventListener(eventName, nextValue as any)\n\n return invoke()\n }\n\n default: {\n return invoke()\n }\n }\n },\n methodCall: ([methodName, args], invoke) => {\n switch (methodName) {\n case 'open': {\n const [method, url] = args as [string, string | undefined]\n\n if (typeof url === 'undefined') {\n this.method = 'GET'\n this.url = toAbsoluteUrl(method)\n } else {\n this.method = method\n this.url = toAbsoluteUrl(url)\n }\n\n this.logger = this.logger.extend(`${this.method} ${this.url.href}`)\n this.logger.info('open', this.method, this.url.href)\n\n return invoke()\n }\n\n case 'addEventListener': {\n const [eventName, listener] = args as [\n keyof XMLHttpRequestEventTargetEventMap,\n Function\n ]\n\n this.registerEvent(eventName, listener)\n this.logger.info('addEventListener', eventName, listener)\n\n return invoke()\n }\n\n case 'setRequestHeader': {\n const [name, value] = args as [string, string]\n this.requestHeaders.set(name, value)\n\n this.logger.info('setRequestHeader', name, value)\n\n return invoke()\n }\n\n case 'send': {\n const [body] = args as [\n body?: XMLHttpRequestBodyInit | Document | null\n ]\n\n this.request.addEventListener('load', () => {\n if (typeof this.onResponse !== 'undefined') {\n // Create a Fetch API Response representation of whichever\n // response this XMLHttpRequest received. Note those may\n // be either a mocked and the original response.\n const fetchResponse = createResponse(\n this.request,\n /**\n * The `response` property is the right way to read\n * the ambiguous response body, as the request's \"responseType\" may differ.\n * @see https://xhr.spec.whatwg.org/#the-response-attribute\n */\n this.request.response\n )\n\n // Notify the consumer about the response.\n this.onResponse.call(this, {\n response: fetchResponse,\n isMockedResponse: this[kIsRequestHandled],\n request: fetchRequest,\n requestId: this.requestId!,\n })\n }\n })\n\n const requestBody =\n typeof body === 'string' ? encodeBuffer(body) : body\n\n // Delegate request handling to the consumer.\n const fetchRequest = this.toFetchApiRequest(requestBody)\n this[kFetchRequest] = fetchRequest.clone()\n\n const onceRequestSettled =\n this.onRequest?.call(this, {\n request: fetchRequest,\n requestId: this.requestId!,\n }) || Promise.resolve()\n\n onceRequestSettled.finally(() => {\n // If the consumer didn't handle the request (called `.respondWith()`) perform it as-is.\n if (!this[kIsRequestHandled]) {\n this.logger.info(\n 'request callback settled but request has not been handled (readystate %d), performing as-is...',\n this.request.readyState\n )\n\n /**\n * @note Set the intercepted request ID on the original request in Node.js\n * so that if it triggers any other interceptors, they don't attempt\n * to process it once again.\n *\n * For instance, XMLHttpRequest is often implemented via \"http.ClientRequest\"\n * and we don't want for both XHR and ClientRequest interceptors to\n * handle the same request at the same time (e.g. emit the \"response\" event twice).\n */\n if (IS_NODE) {\n this.request.setRequestHeader(\n INTERNAL_REQUEST_ID_HEADER_NAME,\n this.requestId!\n )\n }\n\n return invoke()\n }\n })\n\n break\n }\n\n default: {\n return invoke()\n }\n }\n },\n })\n\n /**\n * Proxy the `.upload` property to gather the event listeners/callbacks.\n */\n define(\n this.request,\n 'upload',\n createProxy(this.request.upload, {\n setProperty: ([propertyName, nextValue], invoke) => {\n switch (propertyName) {\n case 'onloadstart':\n case 'onprogress':\n case 'onaboart':\n case 'onerror':\n case 'onload':\n case 'ontimeout':\n case 'onloadend': {\n const eventName = propertyName.slice(\n 2\n ) as keyof XMLHttpRequestEventTargetEventMap\n\n this.registerUploadEvent(eventName, nextValue as Function)\n }\n }\n\n return invoke()\n },\n methodCall: ([methodName, args], invoke) => {\n switch (methodName) {\n case 'addEventListener': {\n const [eventName, listener] = args as [\n keyof XMLHttpRequestEventTargetEventMap,\n Function\n ]\n this.registerUploadEvent(eventName, listener)\n this.logger.info('upload.addEventListener', eventName, listener)\n\n return invoke()\n }\n }\n },\n })\n )\n }\n\n private registerEvent(\n eventName: keyof XMLHttpRequestEventTargetEventMap,\n listener: Function\n ): void {\n const prevEvents = this.events.get(eventName) || []\n const nextEvents = prevEvents.concat(listener)\n this.events.set(eventName, nextEvents)\n\n this.logger.info('registered event \"%s\"', eventName, listener)\n }\n\n private registerUploadEvent(\n eventName: keyof XMLHttpRequestEventTargetEventMap,\n listener: Function\n ): void {\n const prevEvents = this.uploadEvents.get(eventName) || []\n const nextEvents = prevEvents.concat(listener)\n this.uploadEvents.set(eventName, nextEvents)\n\n this.logger.info('registered upload event \"%s\"', eventName, listener)\n }\n\n /**\n * Responds to the current request with the given\n * Fetch API `Response` instance.\n */\n public async respondWith(response: Response): Promise {\n /**\n * @note Since `XMLHttpRequestController` delegates the handling of the responses\n * to the \"load\" event listener that doesn't distinguish between the mocked and original\n * responses, mark the request that had a mocked response with a corresponding symbol.\n *\n * Mark this request as having a mocked response immediately since\n * calculating request/response total body length is asynchronous.\n */\n this[kIsRequestHandled] = true\n\n /**\n * Dispatch request upload events for requests with a body.\n * @see https://github.com/mswjs/interceptors/issues/573\n */\n if (this[kFetchRequest]) {\n const totalRequestBodyLength = await getBodyByteLength(\n this[kFetchRequest]\n )\n\n this.trigger('loadstart', this.request.upload, {\n loaded: 0,\n total: totalRequestBodyLength,\n })\n this.trigger('progress', this.request.upload, {\n loaded: totalRequestBodyLength,\n total: totalRequestBodyLength,\n })\n this.trigger('load', this.request.upload, {\n loaded: totalRequestBodyLength,\n total: totalRequestBodyLength,\n })\n this.trigger('loadend', this.request.upload, {\n loaded: totalRequestBodyLength,\n total: totalRequestBodyLength,\n })\n }\n\n this.logger.info(\n 'responding with a mocked response: %d %s',\n response.status,\n response.statusText\n )\n\n define(this.request, 'status', response.status)\n define(this.request, 'statusText', response.statusText)\n define(this.request, 'responseURL', this.url.href)\n\n this.request.getResponseHeader = new Proxy(this.request.getResponseHeader, {\n apply: (_, __, args: [name: string]) => {\n this.logger.info('getResponseHeader', args[0])\n\n if (this.request.readyState < this.request.HEADERS_RECEIVED) {\n this.logger.info('headers not received yet, returning null')\n\n // Headers not received yet, nothing to return.\n return null\n }\n\n const headerValue = response.headers.get(args[0])\n this.logger.info(\n 'resolved response header \"%s\" to',\n args[0],\n headerValue\n )\n\n return headerValue\n },\n })\n\n this.request.getAllResponseHeaders = new Proxy(\n this.request.getAllResponseHeaders,\n {\n apply: () => {\n this.logger.info('getAllResponseHeaders')\n\n if (this.request.readyState < this.request.HEADERS_RECEIVED) {\n this.logger.info('headers not received yet, returning empty string')\n\n // Headers not received yet, nothing to return.\n return ''\n }\n\n const headersList = Array.from(response.headers.entries())\n const allHeaders = headersList\n .map(([headerName, headerValue]) => {\n return `${headerName}: ${headerValue}`\n })\n .join('\\r\\n')\n\n this.logger.info('resolved all response headers to', allHeaders)\n\n return allHeaders\n },\n }\n )\n\n // Update the response getters to resolve against the mocked response.\n Object.defineProperties(this.request, {\n response: {\n enumerable: true,\n configurable: false,\n get: () => this.response,\n },\n responseText: {\n enumerable: true,\n configurable: false,\n get: () => this.responseText,\n },\n responseXML: {\n enumerable: true,\n configurable: false,\n get: () => this.responseXML,\n },\n })\n\n const totalResponseBodyLength = await getBodyByteLength(response.clone())\n\n this.logger.info('calculated response body length', totalResponseBodyLength)\n\n this.trigger('loadstart', this.request, {\n loaded: 0,\n total: totalResponseBodyLength,\n })\n\n this.setReadyState(this.request.HEADERS_RECEIVED)\n this.setReadyState(this.request.LOADING)\n\n const finalizeResponse = () => {\n this.logger.info('finalizing the mocked response...')\n\n this.setReadyState(this.request.DONE)\n\n this.trigger('load', this.request, {\n loaded: this.responseBuffer.byteLength,\n total: totalResponseBodyLength,\n })\n\n this.trigger('loadend', this.request, {\n loaded: this.responseBuffer.byteLength,\n total: totalResponseBodyLength,\n })\n }\n\n if (response.body) {\n this.logger.info('mocked response has body, streaming...')\n\n const reader = response.body.getReader()\n\n const readNextResponseBodyChunk = async () => {\n const { value, done } = await reader.read()\n\n if (done) {\n this.logger.info('response body stream done!')\n finalizeResponse()\n return\n }\n\n if (value) {\n this.logger.info('read response body chunk:', value)\n this.responseBuffer = concatArrayBuffer(this.responseBuffer, value)\n\n this.trigger('progress', this.request, {\n loaded: this.responseBuffer.byteLength,\n total: totalResponseBodyLength,\n })\n }\n\n readNextResponseBodyChunk()\n }\n\n readNextResponseBodyChunk()\n } else {\n finalizeResponse()\n }\n }\n\n private responseBufferToText(): string {\n return decodeBuffer(this.responseBuffer)\n }\n\n get response(): unknown {\n this.logger.info(\n 'getResponse (responseType: %s)',\n this.request.responseType\n )\n\n if (this.request.readyState !== this.request.DONE) {\n return null\n }\n\n switch (this.request.responseType) {\n case 'json': {\n const responseJson = parseJson(this.responseBufferToText())\n this.logger.info('resolved response JSON', responseJson)\n\n return responseJson\n }\n\n case 'arraybuffer': {\n const arrayBuffer = toArrayBuffer(this.responseBuffer)\n this.logger.info('resolved response ArrayBuffer', arrayBuffer)\n\n return arrayBuffer\n }\n\n case 'blob': {\n const mimeType =\n this.request.getResponseHeader('Content-Type') || 'text/plain'\n const responseBlob = new Blob([this.responseBufferToText()], {\n type: mimeType,\n })\n\n this.logger.info(\n 'resolved response Blob (mime type: %s)',\n responseBlob,\n mimeType\n )\n\n return responseBlob\n }\n\n default: {\n const responseText = this.responseBufferToText()\n this.logger.info(\n 'resolving \"%s\" response type as text',\n this.request.responseType,\n responseText\n )\n\n return responseText\n }\n }\n }\n\n get responseText(): string {\n /**\n * Throw when trying to read the response body as text when the\n * \"responseType\" doesn't expect text. This just respects the spec better.\n * @see https://xhr.spec.whatwg.org/#the-responsetext-attribute\n */\n invariant(\n this.request.responseType === '' || this.request.responseType === 'text',\n 'InvalidStateError: The object is in invalid state.'\n )\n\n if (\n this.request.readyState !== this.request.LOADING &&\n this.request.readyState !== this.request.DONE\n ) {\n return ''\n }\n\n const responseText = this.responseBufferToText()\n this.logger.info('getResponseText: \"%s\"', responseText)\n\n return responseText\n }\n\n get responseXML(): Document | null {\n invariant(\n this.request.responseType === '' ||\n this.request.responseType === 'document',\n 'InvalidStateError: The object is in invalid state.'\n )\n\n if (this.request.readyState !== this.request.DONE) {\n return null\n }\n\n const contentType = this.request.getResponseHeader('Content-Type') || ''\n\n if (typeof DOMParser === 'undefined') {\n console.warn(\n 'Cannot retrieve XMLHttpRequest response body as XML: DOMParser is not defined. You are likely using an environment that is not browser or does not polyfill browser globals correctly.'\n )\n return null\n }\n\n if (isDomParserSupportedType(contentType)) {\n return new DOMParser().parseFromString(\n this.responseBufferToText(),\n contentType\n )\n }\n\n return null\n }\n\n public errorWith(error?: Error): void {\n /**\n * @note Mark this request as handled even if it received a mock error.\n * This prevents the controller from trying to perform this request as-is.\n */\n this[kIsRequestHandled] = true\n this.logger.info('responding with an error')\n\n this.setReadyState(this.request.DONE)\n this.trigger('error', this.request)\n this.trigger('loadend', this.request)\n }\n\n /**\n * Transitions this request's `readyState` to the given one.\n */\n private setReadyState(nextReadyState: number): void {\n this.logger.info(\n 'setReadyState: %d -> %d',\n this.request.readyState,\n nextReadyState\n )\n\n if (this.request.readyState === nextReadyState) {\n this.logger.info('ready state identical, skipping transition...')\n return\n }\n\n define(this.request, 'readyState', nextReadyState)\n\n this.logger.info('set readyState to: %d', nextReadyState)\n\n if (nextReadyState !== this.request.UNSENT) {\n this.logger.info('triggerring \"readystatechange\" event...')\n\n this.trigger('readystatechange', this.request)\n }\n }\n\n /**\n * Triggers given event on the `XMLHttpRequest` instance.\n */\n private trigger<\n EventName extends keyof (XMLHttpRequestEventTargetEventMap & {\n readystatechange: ProgressEvent\n })\n >(\n eventName: EventName,\n target: XMLHttpRequest | XMLHttpRequestUpload,\n options?: ProgressEventInit\n ): void {\n const callback = (target as XMLHttpRequest)[`on${eventName}`]\n const event = createEvent(target, eventName, options)\n\n this.logger.info('trigger \"%s\"', eventName, options || '')\n\n // Invoke direct callbacks.\n if (typeof callback === 'function') {\n this.logger.info('found a direct \"%s\" callback, calling...', eventName)\n callback.call(target as XMLHttpRequest, event)\n }\n\n // Invoke event listeners.\n const events =\n target instanceof XMLHttpRequestUpload ? this.uploadEvents : this.events\n\n for (const [registeredEventName, listeners] of events) {\n if (registeredEventName === eventName) {\n this.logger.info(\n 'found %d listener(s) for \"%s\" event, calling...',\n listeners.length,\n eventName\n )\n\n listeners.forEach((listener) => listener.call(target, event))\n }\n }\n }\n\n /**\n * Converts this `XMLHttpRequest` instance into a Fetch API `Request` instance.\n */\n private toFetchApiRequest(\n body: XMLHttpRequestBodyInit | Document | null | undefined\n ): Request {\n this.logger.info('converting request to a Fetch API Request...')\n\n // If the `Document` is used as the body of this XMLHttpRequest,\n // set its inner text as the Fetch API Request body.\n const resolvedBody =\n body instanceof Document ? body.documentElement.innerText : body\n\n const fetchRequest = new Request(this.url.href, {\n method: this.method,\n headers: this.requestHeaders,\n /**\n * @see https://xhr.spec.whatwg.org/#cross-origin-credentials\n */\n credentials: this.request.withCredentials ? 'include' : 'same-origin',\n body: ['GET', 'HEAD'].includes(this.method.toUpperCase())\n ? null\n : resolvedBody,\n })\n\n const proxyHeaders = createProxy(fetchRequest.headers, {\n methodCall: ([methodName, args], invoke) => {\n // Forward the latest state of the internal request headers\n // because the interceptor might have modified them\n // without responding to the request.\n switch (methodName) {\n case 'append':\n case 'set': {\n const [headerName, headerValue] = args as [string, string]\n this.request.setRequestHeader(headerName, headerValue)\n break\n }\n\n case 'delete': {\n const [headerName] = args as [string]\n console.warn(\n `XMLHttpRequest: Cannot remove a \"${headerName}\" header from the Fetch API representation of the \"${fetchRequest.method} ${fetchRequest.url}\" request. XMLHttpRequest headers cannot be removed.`\n )\n break\n }\n }\n\n return invoke()\n },\n })\n define(fetchRequest, 'headers', proxyHeaders)\n\n this.logger.info('converted request to a Fetch API Request!', fetchRequest)\n\n return fetchRequest\n }\n}\n\nfunction toAbsoluteUrl(url: string | URL): URL {\n /**\n * @note XMLHttpRequest interceptor may run in environments\n * that implement XMLHttpRequest but don't implement \"location\"\n * (for example, React Native). If that's the case, return the\n * input URL as-is (nothing to be relative to).\n * @see https://github.com/mswjs/msw/issues/1777\n */\n if (typeof location === 'undefined') {\n return new URL(url)\n }\n\n return new URL(url.toString(), location.href)\n}\n\nfunction define(\n target: object,\n property: string | symbol,\n value: unknown\n): void {\n Reflect.defineProperty(target, property, {\n // Ensure writable properties to allow redefining readonly properties.\n writable: true,\n enumerable: true,\n value,\n })\n}\n","/**\n * Concatenate two `Uint8Array` buffers.\n */\nexport function concatArrayBuffer(\n left: Uint8Array,\n right: Uint8Array\n): Uint8Array {\n const result = new Uint8Array(left.byteLength + right.byteLength)\n result.set(left, 0)\n result.set(right, left.byteLength)\n return result\n}\n","export class EventPolyfill implements Event {\n readonly NONE = 0\n readonly CAPTURING_PHASE = 1\n readonly AT_TARGET = 2\n readonly BUBBLING_PHASE = 3\n\n public type: string = ''\n public srcElement: EventTarget | null = null\n public target: EventTarget | null\n public currentTarget: EventTarget | null = null\n public eventPhase: number = 0\n public timeStamp: number\n public isTrusted: boolean = true\n public composed: boolean = false\n public cancelable: boolean = true\n public defaultPrevented: boolean = false\n public bubbles: boolean = true\n public lengthComputable: boolean = true\n public loaded: number = 0\n public total: number = 0\n\n cancelBubble: boolean = false\n returnValue: boolean = true\n\n constructor(\n type: string,\n options?: { target: EventTarget; currentTarget: EventTarget }\n ) {\n this.type = type\n this.target = options?.target || null\n this.currentTarget = options?.currentTarget || null\n this.timeStamp = Date.now()\n }\n\n public composedPath(): EventTarget[] {\n return []\n }\n\n public initEvent(type: string, bubbles?: boolean, cancelable?: boolean) {\n this.type = type\n this.bubbles = !!bubbles\n this.cancelable = !!cancelable\n }\n\n public preventDefault() {\n this.defaultPrevented = true\n }\n\n public stopPropagation() {}\n public stopImmediatePropagation() {}\n}\n","import { EventPolyfill } from './EventPolyfill'\n\nexport class ProgressEventPolyfill extends EventPolyfill {\n readonly lengthComputable: boolean\n readonly composed: boolean\n readonly loaded: number\n readonly total: number\n\n constructor(type: string, init?: ProgressEventInit) {\n super(type)\n\n this.lengthComputable = init?.lengthComputable || false\n this.composed = init?.composed || false\n this.loaded = init?.loaded || 0\n this.total = init?.total || 0\n }\n}\n","import { EventPolyfill } from '../polyfills/EventPolyfill'\nimport { ProgressEventPolyfill } from '../polyfills/ProgressEventPolyfill'\n\nconst SUPPORTS_PROGRESS_EVENT = typeof ProgressEvent !== 'undefined'\n\nexport function createEvent(\n target: XMLHttpRequest | XMLHttpRequestUpload,\n type: string,\n init?: ProgressEventInit\n): EventPolyfill | ProgressEvent {\n const progressEvents = [\n 'error',\n 'progress',\n 'loadstart',\n 'loadend',\n 'load',\n 'timeout',\n 'abort',\n ]\n\n /**\n * `ProgressEvent` is not supported in React Native.\n * @see https://github.com/mswjs/interceptors/issues/40\n */\n const ProgressEventClass = SUPPORTS_PROGRESS_EVENT\n ? ProgressEvent\n : ProgressEventPolyfill\n\n const event = progressEvents.includes(type)\n ? new ProgressEventClass(type, {\n lengthComputable: true,\n loaded: init?.loaded || 0,\n total: init?.total || 0,\n })\n : new EventPolyfill(type, {\n target,\n currentTarget: target,\n })\n\n return event\n}\n","/**\n * Returns the source object of the given property on the target object\n * (the target itself, any parent in its prototype, or null).\n */\nexport function findPropertySource(\n target: object,\n propertyName: string | symbol\n): object | null {\n if (!(propertyName in target)) {\n return null\n }\n\n const hasProperty = Object.prototype.hasOwnProperty.call(target, propertyName)\n if (hasProperty) {\n return target\n }\n\n const prototype = Reflect.getPrototypeOf(target)\n return prototype ? findPropertySource(prototype, propertyName) : null\n}\n","import { findPropertySource } from './findPropertySource'\n\nexport interface ProxyOptions> {\n constructorCall?(args: Array, next: NextFunction): Target\n\n methodCall?(\n this: Target,\n data: [methodName: F, args: Array],\n next: NextFunction\n ): void\n\n setProperty?(\n data: [propertyName: string | symbol, nextValue: unknown],\n next: NextFunction\n ): boolean\n\n getProperty?(\n data: [propertyName: string | symbol, receiver: Target],\n next: NextFunction\n ): void\n}\n\nexport type NextFunction = () => ReturnType\n\nexport function createProxy(\n target: Target,\n options: ProxyOptions\n): Target {\n const proxy = new Proxy(target, optionsToProxyHandler(options))\n\n return proxy\n}\n\nfunction optionsToProxyHandler>(\n options: ProxyOptions\n): ProxyHandler {\n const { constructorCall, methodCall, getProperty, setProperty } = options\n const handler: ProxyHandler = {}\n\n if (typeof constructorCall !== 'undefined') {\n handler.construct = function (target, args, newTarget) {\n const next = Reflect.construct.bind(null, target as any, args, newTarget)\n return constructorCall.call(newTarget, args, next)\n }\n }\n\n handler.set = function (target, propertyName, nextValue) {\n const next = () => {\n const propertySource = findPropertySource(target, propertyName) || target\n const ownDescriptors = Reflect.getOwnPropertyDescriptor(\n propertySource,\n propertyName\n )\n\n // Respect any custom setters present for this property.\n if (typeof ownDescriptors?.set !== 'undefined') {\n ownDescriptors.set.apply(target, [nextValue])\n return true\n }\n\n // Otherwise, set the property on the source.\n return Reflect.defineProperty(propertySource, propertyName, {\n writable: true,\n enumerable: true,\n configurable: true,\n value: nextValue,\n })\n }\n\n if (typeof setProperty !== 'undefined') {\n return setProperty.call(target, [propertyName, nextValue], next)\n }\n\n return next()\n }\n\n handler.get = function (target, propertyName, receiver) {\n /**\n * @note Using `Reflect.get()` here causes \"TypeError: Illegal invocation\".\n */\n const next = () => target[propertyName as any]\n\n const value =\n typeof getProperty !== 'undefined'\n ? getProperty.call(target, [propertyName, receiver], next)\n : next()\n\n if (typeof value === 'function') {\n return (...args: Array) => {\n const next = value.bind(target, ...args)\n\n if (typeof methodCall !== 'undefined') {\n return methodCall.call(target, [propertyName as any, args], next)\n }\n\n return next()\n }\n }\n\n return value\n }\n\n return handler\n}\n","export function isDomParserSupportedType(\n type: string\n): type is DOMParserSupportedType {\n const supportedTypes: Array = [\n 'application/xhtml+xml',\n 'application/xml',\n 'image/svg+xml',\n 'text/html',\n 'text/xml',\n ]\n return supportedTypes.some((supportedType) => {\n return type.startsWith(supportedType)\n })\n}\n","/**\n * Parses a given string into JSON.\n * Gracefully handles invalid JSON by returning `null`.\n */\nexport function parseJson(data: string): Record | null {\n try {\n const json = JSON.parse(data)\n return json\n } catch (_) {\n return null\n }\n}\n","import { FetchResponse } from '../../../utils/fetchUtils'\n\n/**\n * Creates a Fetch API `Response` instance from the given\n * `XMLHttpRequest` instance and a response body.\n */\nexport function createResponse(\n request: XMLHttpRequest,\n body: BodyInit | null\n): Response {\n /**\n * Handle XMLHttpRequest responses that must have null as the\n * response body when represented using Fetch API Response.\n * XMLHttpRequest response will always have an empty string\n * as the \"request.response\" in those cases, resulting in an error\n * when constructing a Response instance.\n * @see https://github.com/mswjs/interceptors/issues/379\n */\n const responseBodyOrNull = FetchResponse.isResponseWithBody(request.status)\n ? body\n : null\n\n return new FetchResponse(responseBodyOrNull, {\n url: request.responseURL,\n status: request.status,\n statusText: request.statusText,\n headers: createHeadersFromXMLHttpReqestHeaders(\n request.getAllResponseHeaders()\n ),\n })\n}\n\nfunction createHeadersFromXMLHttpReqestHeaders(headersString: string): Headers {\n const headers = new Headers()\n\n const lines = headersString.split(/[\\r\\n]+/)\n for (const line of lines) {\n if (line.trim() === '') {\n continue\n }\n\n const [name, ...parts] = line.split(': ')\n const value = parts.join(': ')\n\n headers.append(name, value)\n }\n\n return headers\n}\n","/**\n * Return a total byte length of the given request/response body.\n * If the `Content-Length` header is present, it will be used as the byte length.\n */\nexport async function getBodyByteLength(\n input: Request | Response\n): Promise {\n const explicitContentLength = input.headers.get('content-length')\n\n if (explicitContentLength != null && explicitContentLength !== '') {\n return Number(explicitContentLength)\n }\n\n const buffer = await input.arrayBuffer()\n return buffer.byteLength\n}\n","import type { Logger } from '@open-draft/logger'\nimport { XMLHttpRequestEmitter } from '.'\nimport { RequestController } from '../../RequestController'\nimport { XMLHttpRequestController } from './XMLHttpRequestController'\nimport { handleRequest } from '../../utils/handleRequest'\n\nexport interface XMLHttpRequestProxyOptions {\n emitter: XMLHttpRequestEmitter\n logger: Logger\n}\n\n/**\n * Create a proxied `XMLHttpRequest` class.\n * The proxied class establishes spies on certain methods,\n * allowing us to intercept requests and respond to them.\n */\nexport function createXMLHttpRequestProxy({\n emitter,\n logger,\n}: XMLHttpRequestProxyOptions) {\n const XMLHttpRequestProxy = new Proxy(globalThis.XMLHttpRequest, {\n construct(target, args, newTarget) {\n logger.info('constructed new XMLHttpRequest')\n\n const originalRequest = Reflect.construct(\n target,\n args,\n newTarget\n ) as XMLHttpRequest\n\n /**\n * @note Forward prototype descriptors onto the proxied object.\n * XMLHttpRequest is implemented in JSDOM in a way that assigns\n * a bunch of descriptors, like \"set responseType()\" on the prototype.\n * With this propagation, we make sure that those descriptors trigger\n * when the user operates with the proxied request instance.\n */\n const prototypeDescriptors = Object.getOwnPropertyDescriptors(\n target.prototype\n )\n for (const propertyName in prototypeDescriptors) {\n Reflect.defineProperty(\n originalRequest,\n propertyName,\n prototypeDescriptors[propertyName]\n )\n }\n\n const xhrRequestController = new XMLHttpRequestController(\n originalRequest,\n logger\n )\n\n xhrRequestController.onRequest = async function ({ request, requestId }) {\n const controller = new RequestController(request)\n\n this.logger.info('awaiting mocked response...')\n\n this.logger.info(\n 'emitting the \"request\" event for %s listener(s)...',\n emitter.listenerCount('request')\n )\n\n const isRequestHandled = await handleRequest({\n request,\n requestId,\n controller,\n emitter,\n onResponse: async (response) => {\n await this.respondWith(response)\n },\n onRequestError: () => {\n this.errorWith(new TypeError('Network error'))\n },\n onError: (error) => {\n this.logger.info('request errored!', { error })\n\n if (error instanceof Error) {\n this.errorWith(error)\n }\n },\n })\n\n if (!isRequestHandled) {\n this.logger.info(\n 'no mocked response received, performing request as-is...'\n )\n }\n }\n\n xhrRequestController.onResponse = async function ({\n response,\n isMockedResponse,\n request,\n requestId,\n }) {\n this.logger.info(\n 'emitting the \"response\" event for %s listener(s)...',\n emitter.listenerCount('response')\n )\n\n emitter.emit('response', {\n response,\n isMockedResponse,\n request,\n requestId,\n })\n }\n\n // Return the proxied request from the controller\n // so that the controller can react to the consumer's interactions\n // with this request (opening/sending/etc).\n return xhrRequestController.request\n },\n })\n\n return XMLHttpRequestProxy\n}\n"]} \ No newline at end of file diff --git a/node_modules/@mswjs/interceptors/lib/node/chunk-LEA3MUU3.js b/node_modules/@mswjs/interceptors/lib/node/chunk-LEA3MUU3.js new file mode 100644 index 0000000000000000000000000000000000000000..f543561639e4d2dbf88f5855718f64dc29447709 --- /dev/null +++ b/node_modules/@mswjs/interceptors/lib/node/chunk-LEA3MUU3.js @@ -0,0 +1,310 @@ +"use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +var _chunkPFGO5BSMjs = require('./chunk-PFGO5BSM.js'); + + +var _chunk73NOP3T5js = require('./chunk-73NOP3T5.js'); + + + + +var _chunk6L3PFBGTjs = require('./chunk-6L3PFBGT.js'); + + + + +var _chunkWZTE4PCOjs = require('./chunk-WZTE4PCO.js'); + +// src/interceptors/fetch/index.ts +var _outvariant = require('outvariant'); +var _deferredpromise = require('@open-draft/deferred-promise'); + +// src/utils/canParseUrl.ts +function canParseUrl(url) { + try { + new URL(url); + return true; + } catch (_error) { + return false; + } +} + +// src/interceptors/fetch/utils/createNetworkError.ts +function createNetworkError(cause) { + return Object.assign(new TypeError("Failed to fetch"), { + cause + }); +} + +// src/interceptors/fetch/utils/followRedirect.ts +var REQUEST_BODY_HEADERS = [ + "content-encoding", + "content-language", + "content-location", + "content-type", + "content-length" +]; +var kRedirectCount = Symbol("kRedirectCount"); +async function followFetchRedirect(request, response) { + if (response.status !== 303 && request.body != null) { + return Promise.reject(createNetworkError()); + } + const requestUrl = new URL(request.url); + let locationUrl; + try { + locationUrl = new URL(response.headers.get("location"), request.url); + } catch (error) { + return Promise.reject(createNetworkError(error)); + } + if (!(locationUrl.protocol === "http:" || locationUrl.protocol === "https:")) { + return Promise.reject( + createNetworkError("URL scheme must be a HTTP(S) scheme") + ); + } + if (Reflect.get(request, kRedirectCount) > 20) { + return Promise.reject(createNetworkError("redirect count exceeded")); + } + Object.defineProperty(request, kRedirectCount, { + value: (Reflect.get(request, kRedirectCount) || 0) + 1 + }); + if (request.mode === "cors" && (locationUrl.username || locationUrl.password) && !sameOrigin(requestUrl, locationUrl)) { + return Promise.reject( + createNetworkError('cross origin not allowed for request mode "cors"') + ); + } + const requestInit = {}; + if ([301, 302].includes(response.status) && request.method === "POST" || response.status === 303 && !["HEAD", "GET"].includes(request.method)) { + requestInit.method = "GET"; + requestInit.body = null; + REQUEST_BODY_HEADERS.forEach((headerName) => { + request.headers.delete(headerName); + }); + } + if (!sameOrigin(requestUrl, locationUrl)) { + request.headers.delete("authorization"); + request.headers.delete("proxy-authorization"); + request.headers.delete("cookie"); + request.headers.delete("host"); + } + requestInit.headers = request.headers; + return fetch(new Request(locationUrl, requestInit)); +} +function sameOrigin(left, right) { + if (left.origin === right.origin && left.origin === "null") { + return true; + } + if (left.protocol === right.protocol && left.hostname === right.hostname && left.port === right.port) { + return true; + } + return false; +} + +// src/interceptors/fetch/utils/brotli-decompress.ts +var _zlib = require('zlib'); var _zlib2 = _interopRequireDefault(_zlib); +var BrotliDecompressionStream = class extends TransformStream { + constructor() { + const decompress = _zlib2.default.createBrotliDecompress({ + flush: _zlib2.default.constants.BROTLI_OPERATION_FLUSH, + finishFlush: _zlib2.default.constants.BROTLI_OPERATION_FLUSH + }); + super({ + async transform(chunk, controller) { + const buffer = Buffer.from(chunk); + const decompressed = await new Promise((resolve, reject) => { + decompress.write(buffer, (error) => { + if (error) + reject(error); + }); + decompress.flush(); + decompress.once("data", (data) => resolve(data)); + decompress.once("error", (error) => reject(error)); + decompress.once("end", () => controller.terminate()); + }).catch((error) => { + controller.error(error); + }); + controller.enqueue(decompressed); + } + }); + } +}; + +// src/interceptors/fetch/utils/decompression.ts +var PipelineStream = class extends TransformStream { + constructor(transformStreams, ...strategies) { + super({}, ...strategies); + const readable = [super.readable, ...transformStreams].reduce( + (readable2, transform) => readable2.pipeThrough(transform) + ); + Object.defineProperty(this, "readable", { + get() { + return readable; + } + }); + } +}; +function parseContentEncoding(contentEncoding) { + return contentEncoding.toLowerCase().split(",").map((coding) => coding.trim()); +} +function createDecompressionStream(contentEncoding) { + if (contentEncoding === "") { + return null; + } + const codings = parseContentEncoding(contentEncoding); + if (codings.length === 0) { + return null; + } + const transformers = codings.reduceRight( + (transformers2, coding) => { + if (coding === "gzip" || coding === "x-gzip") { + return transformers2.concat(new DecompressionStream("gzip")); + } else if (coding === "deflate") { + return transformers2.concat(new DecompressionStream("deflate")); + } else if (coding === "br") { + return transformers2.concat(new BrotliDecompressionStream()); + } else { + transformers2.length = 0; + } + return transformers2; + }, + [] + ); + return new PipelineStream(transformers); +} +function decompressResponse(response) { + if (response.body === null) { + return null; + } + const decompressionStream = createDecompressionStream( + response.headers.get("content-encoding") || "" + ); + if (!decompressionStream) { + return null; + } + response.body.pipeTo(decompressionStream.writable); + return decompressionStream.readable; +} + +// src/interceptors/fetch/index.ts +var _FetchInterceptor = class extends _chunkWZTE4PCOjs.Interceptor { + constructor() { + super(_FetchInterceptor.symbol); + } + checkEnvironment() { + return _chunkPFGO5BSMjs.hasConfigurableGlobal.call(void 0, "fetch"); + } + async setup() { + const pureFetch = globalThis.fetch; + _outvariant.invariant.call(void 0, + !pureFetch[_chunk73NOP3T5js.IS_PATCHED_MODULE], + 'Failed to patch the "fetch" module: already patched.' + ); + globalThis.fetch = async (input, init) => { + const requestId = _chunkWZTE4PCOjs.createRequestId.call(void 0, ); + const resolvedInput = typeof input === "string" && typeof location !== "undefined" && !canParseUrl(input) ? new URL(input, location.origin) : input; + const request = new Request(resolvedInput, init); + const responsePromise = new (0, _deferredpromise.DeferredPromise)(); + const controller = new (0, _chunk6L3PFBGTjs.RequestController)(request); + this.logger.info("[%s] %s", request.method, request.url); + this.logger.info("awaiting for the mocked response..."); + this.logger.info( + 'emitting the "request" event for %s listener(s)...', + this.emitter.listenerCount("request") + ); + const isRequestHandled = await _chunk6L3PFBGTjs.handleRequest.call(void 0, { + request, + requestId, + emitter: this.emitter, + controller, + onResponse: async (rawResponse) => { + this.logger.info("received mocked response!", { + rawResponse + }); + const decompressedStream = decompressResponse(rawResponse); + const response = decompressedStream === null ? rawResponse : new (0, _chunkWZTE4PCOjs.FetchResponse)(decompressedStream, rawResponse); + _chunkWZTE4PCOjs.FetchResponse.setUrl(request.url, response); + if (_chunkWZTE4PCOjs.FetchResponse.isRedirectResponse(response.status)) { + if (request.redirect === "error") { + responsePromise.reject(createNetworkError("unexpected redirect")); + return; + } + if (request.redirect === "follow") { + followFetchRedirect(request, response).then( + (response2) => { + responsePromise.resolve(response2); + }, + (reason) => { + responsePromise.reject(reason); + } + ); + return; + } + } + if (this.emitter.listenerCount("response") > 0) { + this.logger.info('emitting the "response" event...'); + await _chunk6L3PFBGTjs.emitAsync.call(void 0, this.emitter, "response", { + // Clone the mocked response for the "response" event listener. + // This way, the listener can read the response and not lock its body + // for the actual fetch consumer. + response: response.clone(), + isMockedResponse: true, + request, + requestId + }); + } + responsePromise.resolve(response); + }, + onRequestError: (response) => { + this.logger.info("request has errored!", { response }); + responsePromise.reject(createNetworkError(response)); + }, + onError: (error) => { + this.logger.info("request has been aborted!", { error }); + responsePromise.reject(error); + } + }); + if (isRequestHandled) { + this.logger.info("request has been handled, returning mock promise..."); + return responsePromise; + } + this.logger.info( + "no mocked response received, performing request as-is..." + ); + return pureFetch(request).then(async (response) => { + this.logger.info("original fetch performed", response); + if (this.emitter.listenerCount("response") > 0) { + this.logger.info('emitting the "response" event...'); + const responseClone = response.clone(); + await _chunk6L3PFBGTjs.emitAsync.call(void 0, this.emitter, "response", { + response: responseClone, + isMockedResponse: false, + request, + requestId + }); + } + return response; + }); + }; + Object.defineProperty(globalThis.fetch, _chunk73NOP3T5js.IS_PATCHED_MODULE, { + enumerable: true, + configurable: true, + value: true + }); + this.subscriptions.push(() => { + Object.defineProperty(globalThis.fetch, _chunk73NOP3T5js.IS_PATCHED_MODULE, { + value: void 0 + }); + globalThis.fetch = pureFetch; + this.logger.info( + 'restored native "globalThis.fetch"!', + globalThis.fetch.name + ); + }); + } +}; +var FetchInterceptor = _FetchInterceptor; +FetchInterceptor.symbol = Symbol("fetch"); + + + +exports.FetchInterceptor = FetchInterceptor; +//# sourceMappingURL=chunk-LEA3MUU3.js.map \ No newline at end of file diff --git a/node_modules/@mswjs/interceptors/lib/node/chunk-LEA3MUU3.js.map b/node_modules/@mswjs/interceptors/lib/node/chunk-LEA3MUU3.js.map new file mode 100644 index 0000000000000000000000000000000000000000..1864a527fa398a98986e2a9c4a179ec206c65bc4 --- /dev/null +++ b/node_modules/@mswjs/interceptors/lib/node/chunk-LEA3MUU3.js.map @@ -0,0 +1 @@ +{"version":3,"sources":["../../src/interceptors/fetch/index.ts","../../src/utils/canParseUrl.ts","../../src/interceptors/fetch/utils/createNetworkError.ts","../../src/interceptors/fetch/utils/followRedirect.ts","../../src/interceptors/fetch/utils/brotli-decompress.ts","../../src/interceptors/fetch/utils/decompression.ts"],"names":["readable","transformers","response"],"mappings":"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","sourcesContent":["import { invariant } from 'outvariant'\nimport { DeferredPromise } from '@open-draft/deferred-promise'\nimport { HttpRequestEventMap, IS_PATCHED_MODULE } from '../../glossary'\nimport { Interceptor } from '../../Interceptor'\nimport { RequestController } from '../../RequestController'\nimport { emitAsync } from '../../utils/emitAsync'\nimport { handleRequest } from '../../utils/handleRequest'\nimport { canParseUrl } from '../../utils/canParseUrl'\nimport { createRequestId } from '../../createRequestId'\nimport { createNetworkError } from './utils/createNetworkError'\nimport { followFetchRedirect } from './utils/followRedirect'\nimport { decompressResponse } from './utils/decompression'\nimport { hasConfigurableGlobal } from '../../utils/hasConfigurableGlobal'\nimport { FetchResponse } from '../../utils/fetchUtils'\n\nexport class FetchInterceptor extends Interceptor {\n static symbol = Symbol('fetch')\n\n constructor() {\n super(FetchInterceptor.symbol)\n }\n\n protected checkEnvironment() {\n return hasConfigurableGlobal('fetch')\n }\n\n protected async setup() {\n const pureFetch = globalThis.fetch\n\n invariant(\n !(pureFetch as any)[IS_PATCHED_MODULE],\n 'Failed to patch the \"fetch\" module: already patched.'\n )\n\n globalThis.fetch = async (input, init) => {\n const requestId = createRequestId()\n\n /**\n * @note Resolve potentially relative request URL\n * against the present `location`. This is mainly\n * for native `fetch` in JSDOM.\n * @see https://github.com/mswjs/msw/issues/1625\n */\n const resolvedInput =\n typeof input === 'string' &&\n typeof location !== 'undefined' &&\n !canParseUrl(input)\n ? new URL(input, location.origin)\n : input\n\n const request = new Request(resolvedInput, init)\n const responsePromise = new DeferredPromise()\n const controller = new RequestController(request)\n\n this.logger.info('[%s] %s', request.method, request.url)\n this.logger.info('awaiting for the mocked response...')\n\n this.logger.info(\n 'emitting the \"request\" event for %s listener(s)...',\n this.emitter.listenerCount('request')\n )\n\n const isRequestHandled = await handleRequest({\n request,\n requestId,\n emitter: this.emitter,\n controller,\n onResponse: async (rawResponse) => {\n this.logger.info('received mocked response!', {\n rawResponse,\n })\n\n // Decompress the mocked response body, if applicable.\n const decompressedStream = decompressResponse(rawResponse)\n const response =\n decompressedStream === null\n ? rawResponse\n : new FetchResponse(decompressedStream, rawResponse)\n\n FetchResponse.setUrl(request.url, response)\n\n /**\n * Undici's handling of following redirect responses.\n * Treat the \"manual\" redirect mode as a regular mocked response.\n * This way, the client can manually follow the redirect it receives.\n * @see https://github.com/nodejs/undici/blob/a6dac3149c505b58d2e6d068b97f4dc993da55f0/lib/web/fetch/index.js#L1173\n */\n if (FetchResponse.isRedirectResponse(response.status)) {\n // Reject the request promise if its `redirect` is set to `error`\n // and it receives a mocked redirect response.\n if (request.redirect === 'error') {\n responsePromise.reject(createNetworkError('unexpected redirect'))\n return\n }\n\n if (request.redirect === 'follow') {\n followFetchRedirect(request, response).then(\n (response) => {\n responsePromise.resolve(response)\n },\n (reason) => {\n responsePromise.reject(reason)\n }\n )\n return\n }\n }\n\n if (this.emitter.listenerCount('response') > 0) {\n this.logger.info('emitting the \"response\" event...')\n\n // Await the response listeners to finish before resolving\n // the response promise. This ensures all your logic finishes\n // before the interceptor resolves the pending response.\n await emitAsync(this.emitter, 'response', {\n // Clone the mocked response for the \"response\" event listener.\n // This way, the listener can read the response and not lock its body\n // for the actual fetch consumer.\n response: response.clone(),\n isMockedResponse: true,\n request,\n requestId,\n })\n }\n\n responsePromise.resolve(response)\n },\n onRequestError: (response) => {\n this.logger.info('request has errored!', { response })\n responsePromise.reject(createNetworkError(response))\n },\n onError: (error) => {\n this.logger.info('request has been aborted!', { error })\n responsePromise.reject(error)\n },\n })\n\n if (isRequestHandled) {\n this.logger.info('request has been handled, returning mock promise...')\n return responsePromise\n }\n\n this.logger.info(\n 'no mocked response received, performing request as-is...'\n )\n\n return pureFetch(request).then(async (response) => {\n this.logger.info('original fetch performed', response)\n\n if (this.emitter.listenerCount('response') > 0) {\n this.logger.info('emitting the \"response\" event...')\n\n const responseClone = response.clone()\n\n await emitAsync(this.emitter, 'response', {\n response: responseClone,\n isMockedResponse: false,\n request,\n requestId,\n })\n }\n\n return response\n })\n }\n\n Object.defineProperty(globalThis.fetch, IS_PATCHED_MODULE, {\n enumerable: true,\n configurable: true,\n value: true,\n })\n\n this.subscriptions.push(() => {\n Object.defineProperty(globalThis.fetch, IS_PATCHED_MODULE, {\n value: undefined,\n })\n\n globalThis.fetch = pureFetch\n\n this.logger.info(\n 'restored native \"globalThis.fetch\"!',\n globalThis.fetch.name\n )\n })\n }\n}\n","/**\n * Returns a boolean indicating whether the given URL string\n * can be parsed into a `URL` instance.\n * A substitute for `URL.canParse()` for Node.js 18.\n */\nexport function canParseUrl(url: string): boolean {\n try {\n new URL(url)\n return true\n } catch (_error) {\n return false\n }\n}\n","export function createNetworkError(cause?: unknown) {\n return Object.assign(new TypeError('Failed to fetch'), {\n cause,\n })\n}\n","import { createNetworkError } from './createNetworkError'\n\nconst REQUEST_BODY_HEADERS = [\n 'content-encoding',\n 'content-language',\n 'content-location',\n 'content-type',\n 'content-length',\n]\n\nconst kRedirectCount = Symbol('kRedirectCount')\n\n/**\n * @see https://github.com/nodejs/undici/blob/a6dac3149c505b58d2e6d068b97f4dc993da55f0/lib/web/fetch/index.js#L1210\n */\nexport async function followFetchRedirect(\n request: Request,\n response: Response\n): Promise {\n if (response.status !== 303 && request.body != null) {\n return Promise.reject(createNetworkError())\n }\n\n const requestUrl = new URL(request.url)\n\n let locationUrl: URL\n try {\n // If the location is a relative URL, use the request URL as the base URL.\n locationUrl = new URL(response.headers.get('location')!, request.url) \n } catch (error) {\n return Promise.reject(createNetworkError(error))\n }\n\n if (\n !(locationUrl.protocol === 'http:' || locationUrl.protocol === 'https:')\n ) {\n return Promise.reject(\n createNetworkError('URL scheme must be a HTTP(S) scheme')\n )\n }\n\n if (Reflect.get(request, kRedirectCount) > 20) {\n return Promise.reject(createNetworkError('redirect count exceeded'))\n }\n\n Object.defineProperty(request, kRedirectCount, {\n value: (Reflect.get(request, kRedirectCount) || 0) + 1,\n })\n\n if (\n request.mode === 'cors' &&\n (locationUrl.username || locationUrl.password) &&\n !sameOrigin(requestUrl, locationUrl)\n ) {\n return Promise.reject(\n createNetworkError('cross origin not allowed for request mode \"cors\"')\n )\n }\n\n const requestInit: RequestInit = {}\n\n if (\n ([301, 302].includes(response.status) && request.method === 'POST') ||\n (response.status === 303 && !['HEAD', 'GET'].includes(request.method))\n ) {\n requestInit.method = 'GET'\n requestInit.body = null\n\n REQUEST_BODY_HEADERS.forEach((headerName) => {\n request.headers.delete(headerName)\n })\n }\n\n if (!sameOrigin(requestUrl, locationUrl)) {\n request.headers.delete('authorization')\n request.headers.delete('proxy-authorization')\n request.headers.delete('cookie')\n request.headers.delete('host')\n }\n\n /**\n * @note Undici \"safely\" extracts the request body.\n * I suspect we cannot dispatch this request again\n * since its body has been read and the stream is locked.\n */\n\n requestInit.headers = request.headers\n return fetch(new Request(locationUrl, requestInit))\n}\n\n/**\n * @see https://github.com/nodejs/undici/blob/a6dac3149c505b58d2e6d068b97f4dc993da55f0/lib/web/fetch/util.js#L761\n */\nfunction sameOrigin(left: URL, right: URL): boolean {\n if (left.origin === right.origin && left.origin === 'null') {\n return true\n }\n\n if (\n left.protocol === right.protocol &&\n left.hostname === right.hostname &&\n left.port === right.port\n ) {\n return true\n }\n\n return false\n}\n","import zlib from 'node:zlib'\n\nexport class BrotliDecompressionStream extends TransformStream {\n constructor() {\n const decompress = zlib.createBrotliDecompress({\n flush: zlib.constants.BROTLI_OPERATION_FLUSH,\n finishFlush: zlib.constants.BROTLI_OPERATION_FLUSH,\n })\n\n super({\n async transform(chunk, controller) {\n const buffer = Buffer.from(chunk)\n\n const decompressed = await new Promise((resolve, reject) => {\n decompress.write(buffer, (error) => {\n if (error) reject(error)\n })\n\n decompress.flush()\n decompress.once('data', (data) => resolve(data))\n decompress.once('error', (error) => reject(error))\n decompress.once('end', () => controller.terminate())\n }).catch((error) => {\n controller.error(error)\n })\n\n controller.enqueue(decompressed)\n },\n })\n }\n}\n","// Import from an internal alias that resolves to different modules\n// depending on the environment. This way, we can keep the fetch interceptor\n// intact while using different strategies for Brotli decompression.\nimport { BrotliDecompressionStream } from 'internal:brotli-decompress'\n\nclass PipelineStream extends TransformStream {\n constructor(\n transformStreams: Array,\n ...strategies: Array\n ) {\n super({}, ...strategies)\n\n const readable = [super.readable as any, ...transformStreams].reduce(\n (readable, transform) => readable.pipeThrough(transform)\n )\n\n Object.defineProperty(this, 'readable', {\n get() {\n return readable\n },\n })\n }\n}\n\nexport function parseContentEncoding(contentEncoding: string): Array {\n return contentEncoding\n .toLowerCase()\n .split(',')\n .map((coding) => coding.trim())\n}\n\nfunction createDecompressionStream(\n contentEncoding: string\n): TransformStream | null {\n if (contentEncoding === '') {\n return null\n }\n\n const codings = parseContentEncoding(contentEncoding)\n\n if (codings.length === 0) {\n return null\n }\n\n const transformers = codings.reduceRight>(\n (transformers, coding) => {\n if (coding === 'gzip' || coding === 'x-gzip') {\n return transformers.concat(new DecompressionStream('gzip'))\n } else if (coding === 'deflate') {\n return transformers.concat(new DecompressionStream('deflate'))\n } else if (coding === 'br') {\n return transformers.concat(new BrotliDecompressionStream())\n } else {\n transformers.length = 0\n }\n\n return transformers\n },\n []\n )\n\n return new PipelineStream(transformers)\n}\n\nexport function decompressResponse(\n response: Response\n): ReadableStream | null {\n if (response.body === null) {\n return null\n }\n\n const decompressionStream = createDecompressionStream(\n response.headers.get('content-encoding') || ''\n )\n\n if (!decompressionStream) {\n return null\n }\n\n // Use `pipeTo` and return the decompression stream's readable\n // instead of `pipeThrough` because that will lock the original\n // response stream, making it unusable as the input to Response.\n response.body.pipeTo(decompressionStream.writable)\n return decompressionStream.readable\n}\n"]} \ No newline at end of file diff --git a/node_modules/@mswjs/interceptors/lib/node/chunk-LK6DILFK.js b/node_modules/@mswjs/interceptors/lib/node/chunk-LK6DILFK.js new file mode 100644 index 0000000000000000000000000000000000000000..f41d9eae5715ee544bf3d8f597fd16e59a271f58 --- /dev/null +++ b/node_modules/@mswjs/interceptors/lib/node/chunk-LK6DILFK.js @@ -0,0 +1,22 @@ +"use strict";Object.defineProperty(exports, "__esModule", {value: true});// src/utils/bufferUtils.ts +var encoder = new TextEncoder(); +function encodeBuffer(text) { + return encoder.encode(text); +} +function decodeBuffer(buffer, encoding) { + const decoder = new TextDecoder(encoding); + return decoder.decode(buffer); +} +function toArrayBuffer(array) { + return array.buffer.slice( + array.byteOffset, + array.byteOffset + array.byteLength + ); +} + + + + + +exports.encodeBuffer = encodeBuffer; exports.decodeBuffer = decodeBuffer; exports.toArrayBuffer = toArrayBuffer; +//# sourceMappingURL=chunk-LK6DILFK.js.map \ No newline at end of file diff --git a/node_modules/@mswjs/interceptors/lib/node/chunk-LK6DILFK.js.map b/node_modules/@mswjs/interceptors/lib/node/chunk-LK6DILFK.js.map new file mode 100644 index 0000000000000000000000000000000000000000..691683680b4e26eecaa7dfe2d0466c8f348eb21f --- /dev/null +++ b/node_modules/@mswjs/interceptors/lib/node/chunk-LK6DILFK.js.map @@ -0,0 +1 @@ +{"version":3,"sources":["../../src/utils/bufferUtils.ts"],"names":[],"mappings":";AAAA,IAAM,UAAU,IAAI,YAAY;AAEzB,SAAS,aAAa,MAA0B;AACrD,SAAO,QAAQ,OAAO,IAAI;AAC5B;AAEO,SAAS,aAAa,QAAqB,UAA2B;AAC3E,QAAM,UAAU,IAAI,YAAY,QAAQ;AACxC,SAAO,QAAQ,OAAO,MAAM;AAC9B;AAOO,SAAS,cAAc,OAAgC;AAC5D,SAAO,MAAM,OAAO;AAAA,IAClB,MAAM;AAAA,IACN,MAAM,aAAa,MAAM;AAAA,EAC3B;AACF","sourcesContent":["const encoder = new TextEncoder()\n\nexport function encodeBuffer(text: string): Uint8Array {\n return encoder.encode(text)\n}\n\nexport function decodeBuffer(buffer: ArrayBuffer, encoding?: string): string {\n const decoder = new TextDecoder(encoding)\n return decoder.decode(buffer)\n}\n\n/**\n * Create an `ArrayBuffer` from the given `Uint8Array`.\n * Takes the byte offset into account to produce the right buffer\n * in the case when the buffer is bigger than the data view.\n */\nexport function toArrayBuffer(array: Uint8Array): ArrayBuffer {\n return array.buffer.slice(\n array.byteOffset,\n array.byteOffset + array.byteLength\n )\n}\n"]} \ No newline at end of file diff --git a/node_modules/@mswjs/interceptors/lib/node/chunk-OMWE7UVM.mjs b/node_modules/@mswjs/interceptors/lib/node/chunk-OMWE7UVM.mjs new file mode 100644 index 0000000000000000000000000000000000000000..aea1e2aab827606fb917cadf9d9e9043990bac69 --- /dev/null +++ b/node_modules/@mswjs/interceptors/lib/node/chunk-OMWE7UVM.mjs @@ -0,0 +1,844 @@ +import { + decodeBuffer, + encodeBuffer, + toArrayBuffer +} from "./chunk-6HYIRFX2.mjs"; +import { + hasConfigurableGlobal +} from "./chunk-TX5GBTFY.mjs"; +import { + IS_PATCHED_MODULE +} from "./chunk-6YM4PLBI.mjs"; +import { + RequestController, + handleRequest +} from "./chunk-5KMS5CTP.mjs"; +import { + FetchResponse, + INTERNAL_REQUEST_ID_HEADER_NAME, + Interceptor, + createRequestId +} from "./chunk-I7HQIBT7.mjs"; + +// src/interceptors/XMLHttpRequest/index.ts +import { invariant as invariant2 } from "outvariant"; + +// src/interceptors/XMLHttpRequest/XMLHttpRequestController.ts +import { invariant } from "outvariant"; +import { isNodeProcess } from "is-node-process"; + +// src/interceptors/XMLHttpRequest/utils/concatArrayBuffer.ts +function concatArrayBuffer(left, right) { + const result = new Uint8Array(left.byteLength + right.byteLength); + result.set(left, 0); + result.set(right, left.byteLength); + return result; +} + +// src/interceptors/XMLHttpRequest/polyfills/EventPolyfill.ts +var EventPolyfill = class { + constructor(type, options) { + this.NONE = 0; + this.CAPTURING_PHASE = 1; + this.AT_TARGET = 2; + this.BUBBLING_PHASE = 3; + this.type = ""; + this.srcElement = null; + this.currentTarget = null; + this.eventPhase = 0; + this.isTrusted = true; + this.composed = false; + this.cancelable = true; + this.defaultPrevented = false; + this.bubbles = true; + this.lengthComputable = true; + this.loaded = 0; + this.total = 0; + this.cancelBubble = false; + this.returnValue = true; + this.type = type; + this.target = (options == null ? void 0 : options.target) || null; + this.currentTarget = (options == null ? void 0 : options.currentTarget) || null; + this.timeStamp = Date.now(); + } + composedPath() { + return []; + } + initEvent(type, bubbles, cancelable) { + this.type = type; + this.bubbles = !!bubbles; + this.cancelable = !!cancelable; + } + preventDefault() { + this.defaultPrevented = true; + } + stopPropagation() { + } + stopImmediatePropagation() { + } +}; + +// src/interceptors/XMLHttpRequest/polyfills/ProgressEventPolyfill.ts +var ProgressEventPolyfill = class extends EventPolyfill { + constructor(type, init) { + super(type); + this.lengthComputable = (init == null ? void 0 : init.lengthComputable) || false; + this.composed = (init == null ? void 0 : init.composed) || false; + this.loaded = (init == null ? void 0 : init.loaded) || 0; + this.total = (init == null ? void 0 : init.total) || 0; + } +}; + +// src/interceptors/XMLHttpRequest/utils/createEvent.ts +var SUPPORTS_PROGRESS_EVENT = typeof ProgressEvent !== "undefined"; +function createEvent(target, type, init) { + const progressEvents = [ + "error", + "progress", + "loadstart", + "loadend", + "load", + "timeout", + "abort" + ]; + const ProgressEventClass = SUPPORTS_PROGRESS_EVENT ? ProgressEvent : ProgressEventPolyfill; + const event = progressEvents.includes(type) ? new ProgressEventClass(type, { + lengthComputable: true, + loaded: (init == null ? void 0 : init.loaded) || 0, + total: (init == null ? void 0 : init.total) || 0 + }) : new EventPolyfill(type, { + target, + currentTarget: target + }); + return event; +} + +// src/utils/findPropertySource.ts +function findPropertySource(target, propertyName) { + if (!(propertyName in target)) { + return null; + } + const hasProperty = Object.prototype.hasOwnProperty.call(target, propertyName); + if (hasProperty) { + return target; + } + const prototype = Reflect.getPrototypeOf(target); + return prototype ? findPropertySource(prototype, propertyName) : null; +} + +// src/utils/createProxy.ts +function createProxy(target, options) { + const proxy = new Proxy(target, optionsToProxyHandler(options)); + return proxy; +} +function optionsToProxyHandler(options) { + const { constructorCall, methodCall, getProperty, setProperty } = options; + const handler = {}; + if (typeof constructorCall !== "undefined") { + handler.construct = function(target, args, newTarget) { + const next = Reflect.construct.bind(null, target, args, newTarget); + return constructorCall.call(newTarget, args, next); + }; + } + handler.set = function(target, propertyName, nextValue) { + const next = () => { + const propertySource = findPropertySource(target, propertyName) || target; + const ownDescriptors = Reflect.getOwnPropertyDescriptor( + propertySource, + propertyName + ); + if (typeof (ownDescriptors == null ? void 0 : ownDescriptors.set) !== "undefined") { + ownDescriptors.set.apply(target, [nextValue]); + return true; + } + return Reflect.defineProperty(propertySource, propertyName, { + writable: true, + enumerable: true, + configurable: true, + value: nextValue + }); + }; + if (typeof setProperty !== "undefined") { + return setProperty.call(target, [propertyName, nextValue], next); + } + return next(); + }; + handler.get = function(target, propertyName, receiver) { + const next = () => target[propertyName]; + const value = typeof getProperty !== "undefined" ? getProperty.call(target, [propertyName, receiver], next) : next(); + if (typeof value === "function") { + return (...args) => { + const next2 = value.bind(target, ...args); + if (typeof methodCall !== "undefined") { + return methodCall.call(target, [propertyName, args], next2); + } + return next2(); + }; + } + return value; + }; + return handler; +} + +// src/interceptors/XMLHttpRequest/utils/isDomParserSupportedType.ts +function isDomParserSupportedType(type) { + const supportedTypes = [ + "application/xhtml+xml", + "application/xml", + "image/svg+xml", + "text/html", + "text/xml" + ]; + return supportedTypes.some((supportedType) => { + return type.startsWith(supportedType); + }); +} + +// src/utils/parseJson.ts +function parseJson(data) { + try { + const json = JSON.parse(data); + return json; + } catch (_) { + return null; + } +} + +// src/interceptors/XMLHttpRequest/utils/createResponse.ts +function createResponse(request, body) { + const responseBodyOrNull = FetchResponse.isResponseWithBody(request.status) ? body : null; + return new FetchResponse(responseBodyOrNull, { + url: request.responseURL, + status: request.status, + statusText: request.statusText, + headers: createHeadersFromXMLHttpReqestHeaders( + request.getAllResponseHeaders() + ) + }); +} +function createHeadersFromXMLHttpReqestHeaders(headersString) { + const headers = new Headers(); + const lines = headersString.split(/[\r\n]+/); + for (const line of lines) { + if (line.trim() === "") { + continue; + } + const [name, ...parts] = line.split(": "); + const value = parts.join(": "); + headers.append(name, value); + } + return headers; +} + +// src/interceptors/XMLHttpRequest/utils/getBodyByteLength.ts +async function getBodyByteLength(input) { + const explicitContentLength = input.headers.get("content-length"); + if (explicitContentLength != null && explicitContentLength !== "") { + return Number(explicitContentLength); + } + const buffer = await input.arrayBuffer(); + return buffer.byteLength; +} + +// src/interceptors/XMLHttpRequest/XMLHttpRequestController.ts +var kIsRequestHandled = Symbol("kIsRequestHandled"); +var IS_NODE = isNodeProcess(); +var kFetchRequest = Symbol("kFetchRequest"); +var XMLHttpRequestController = class { + constructor(initialRequest, logger) { + this.initialRequest = initialRequest; + this.logger = logger; + this.method = "GET"; + this.url = null; + this[kIsRequestHandled] = false; + this.events = /* @__PURE__ */ new Map(); + this.uploadEvents = /* @__PURE__ */ new Map(); + this.requestId = createRequestId(); + this.requestHeaders = new Headers(); + this.responseBuffer = new Uint8Array(); + this.request = createProxy(initialRequest, { + setProperty: ([propertyName, nextValue], invoke) => { + switch (propertyName) { + case "ontimeout": { + const eventName = propertyName.slice( + 2 + ); + this.request.addEventListener(eventName, nextValue); + return invoke(); + } + default: { + return invoke(); + } + } + }, + methodCall: ([methodName, args], invoke) => { + var _a; + switch (methodName) { + case "open": { + const [method, url] = args; + if (typeof url === "undefined") { + this.method = "GET"; + this.url = toAbsoluteUrl(method); + } else { + this.method = method; + this.url = toAbsoluteUrl(url); + } + this.logger = this.logger.extend(`${this.method} ${this.url.href}`); + this.logger.info("open", this.method, this.url.href); + return invoke(); + } + case "addEventListener": { + const [eventName, listener] = args; + this.registerEvent(eventName, listener); + this.logger.info("addEventListener", eventName, listener); + return invoke(); + } + case "setRequestHeader": { + const [name, value] = args; + this.requestHeaders.set(name, value); + this.logger.info("setRequestHeader", name, value); + return invoke(); + } + case "send": { + const [body] = args; + this.request.addEventListener("load", () => { + if (typeof this.onResponse !== "undefined") { + const fetchResponse = createResponse( + this.request, + /** + * The `response` property is the right way to read + * the ambiguous response body, as the request's "responseType" may differ. + * @see https://xhr.spec.whatwg.org/#the-response-attribute + */ + this.request.response + ); + this.onResponse.call(this, { + response: fetchResponse, + isMockedResponse: this[kIsRequestHandled], + request: fetchRequest, + requestId: this.requestId + }); + } + }); + const requestBody = typeof body === "string" ? encodeBuffer(body) : body; + const fetchRequest = this.toFetchApiRequest(requestBody); + this[kFetchRequest] = fetchRequest.clone(); + const onceRequestSettled = ((_a = this.onRequest) == null ? void 0 : _a.call(this, { + request: fetchRequest, + requestId: this.requestId + })) || Promise.resolve(); + onceRequestSettled.finally(() => { + if (!this[kIsRequestHandled]) { + this.logger.info( + "request callback settled but request has not been handled (readystate %d), performing as-is...", + this.request.readyState + ); + if (IS_NODE) { + this.request.setRequestHeader( + INTERNAL_REQUEST_ID_HEADER_NAME, + this.requestId + ); + } + return invoke(); + } + }); + break; + } + default: { + return invoke(); + } + } + } + }); + define( + this.request, + "upload", + createProxy(this.request.upload, { + setProperty: ([propertyName, nextValue], invoke) => { + switch (propertyName) { + case "onloadstart": + case "onprogress": + case "onaboart": + case "onerror": + case "onload": + case "ontimeout": + case "onloadend": { + const eventName = propertyName.slice( + 2 + ); + this.registerUploadEvent(eventName, nextValue); + } + } + return invoke(); + }, + methodCall: ([methodName, args], invoke) => { + switch (methodName) { + case "addEventListener": { + const [eventName, listener] = args; + this.registerUploadEvent(eventName, listener); + this.logger.info("upload.addEventListener", eventName, listener); + return invoke(); + } + } + } + }) + ); + } + registerEvent(eventName, listener) { + const prevEvents = this.events.get(eventName) || []; + const nextEvents = prevEvents.concat(listener); + this.events.set(eventName, nextEvents); + this.logger.info('registered event "%s"', eventName, listener); + } + registerUploadEvent(eventName, listener) { + const prevEvents = this.uploadEvents.get(eventName) || []; + const nextEvents = prevEvents.concat(listener); + this.uploadEvents.set(eventName, nextEvents); + this.logger.info('registered upload event "%s"', eventName, listener); + } + /** + * Responds to the current request with the given + * Fetch API `Response` instance. + */ + async respondWith(response) { + this[kIsRequestHandled] = true; + if (this[kFetchRequest]) { + const totalRequestBodyLength = await getBodyByteLength( + this[kFetchRequest] + ); + this.trigger("loadstart", this.request.upload, { + loaded: 0, + total: totalRequestBodyLength + }); + this.trigger("progress", this.request.upload, { + loaded: totalRequestBodyLength, + total: totalRequestBodyLength + }); + this.trigger("load", this.request.upload, { + loaded: totalRequestBodyLength, + total: totalRequestBodyLength + }); + this.trigger("loadend", this.request.upload, { + loaded: totalRequestBodyLength, + total: totalRequestBodyLength + }); + } + this.logger.info( + "responding with a mocked response: %d %s", + response.status, + response.statusText + ); + define(this.request, "status", response.status); + define(this.request, "statusText", response.statusText); + define(this.request, "responseURL", this.url.href); + this.request.getResponseHeader = new Proxy(this.request.getResponseHeader, { + apply: (_, __, args) => { + this.logger.info("getResponseHeader", args[0]); + if (this.request.readyState < this.request.HEADERS_RECEIVED) { + this.logger.info("headers not received yet, returning null"); + return null; + } + const headerValue = response.headers.get(args[0]); + this.logger.info( + 'resolved response header "%s" to', + args[0], + headerValue + ); + return headerValue; + } + }); + this.request.getAllResponseHeaders = new Proxy( + this.request.getAllResponseHeaders, + { + apply: () => { + this.logger.info("getAllResponseHeaders"); + if (this.request.readyState < this.request.HEADERS_RECEIVED) { + this.logger.info("headers not received yet, returning empty string"); + return ""; + } + const headersList = Array.from(response.headers.entries()); + const allHeaders = headersList.map(([headerName, headerValue]) => { + return `${headerName}: ${headerValue}`; + }).join("\r\n"); + this.logger.info("resolved all response headers to", allHeaders); + return allHeaders; + } + } + ); + Object.defineProperties(this.request, { + response: { + enumerable: true, + configurable: false, + get: () => this.response + }, + responseText: { + enumerable: true, + configurable: false, + get: () => this.responseText + }, + responseXML: { + enumerable: true, + configurable: false, + get: () => this.responseXML + } + }); + const totalResponseBodyLength = await getBodyByteLength(response.clone()); + this.logger.info("calculated response body length", totalResponseBodyLength); + this.trigger("loadstart", this.request, { + loaded: 0, + total: totalResponseBodyLength + }); + this.setReadyState(this.request.HEADERS_RECEIVED); + this.setReadyState(this.request.LOADING); + const finalizeResponse = () => { + this.logger.info("finalizing the mocked response..."); + this.setReadyState(this.request.DONE); + this.trigger("load", this.request, { + loaded: this.responseBuffer.byteLength, + total: totalResponseBodyLength + }); + this.trigger("loadend", this.request, { + loaded: this.responseBuffer.byteLength, + total: totalResponseBodyLength + }); + }; + if (response.body) { + this.logger.info("mocked response has body, streaming..."); + const reader = response.body.getReader(); + const readNextResponseBodyChunk = async () => { + const { value, done } = await reader.read(); + if (done) { + this.logger.info("response body stream done!"); + finalizeResponse(); + return; + } + if (value) { + this.logger.info("read response body chunk:", value); + this.responseBuffer = concatArrayBuffer(this.responseBuffer, value); + this.trigger("progress", this.request, { + loaded: this.responseBuffer.byteLength, + total: totalResponseBodyLength + }); + } + readNextResponseBodyChunk(); + }; + readNextResponseBodyChunk(); + } else { + finalizeResponse(); + } + } + responseBufferToText() { + return decodeBuffer(this.responseBuffer); + } + get response() { + this.logger.info( + "getResponse (responseType: %s)", + this.request.responseType + ); + if (this.request.readyState !== this.request.DONE) { + return null; + } + switch (this.request.responseType) { + case "json": { + const responseJson = parseJson(this.responseBufferToText()); + this.logger.info("resolved response JSON", responseJson); + return responseJson; + } + case "arraybuffer": { + const arrayBuffer = toArrayBuffer(this.responseBuffer); + this.logger.info("resolved response ArrayBuffer", arrayBuffer); + return arrayBuffer; + } + case "blob": { + const mimeType = this.request.getResponseHeader("Content-Type") || "text/plain"; + const responseBlob = new Blob([this.responseBufferToText()], { + type: mimeType + }); + this.logger.info( + "resolved response Blob (mime type: %s)", + responseBlob, + mimeType + ); + return responseBlob; + } + default: { + const responseText = this.responseBufferToText(); + this.logger.info( + 'resolving "%s" response type as text', + this.request.responseType, + responseText + ); + return responseText; + } + } + } + get responseText() { + invariant( + this.request.responseType === "" || this.request.responseType === "text", + "InvalidStateError: The object is in invalid state." + ); + if (this.request.readyState !== this.request.LOADING && this.request.readyState !== this.request.DONE) { + return ""; + } + const responseText = this.responseBufferToText(); + this.logger.info('getResponseText: "%s"', responseText); + return responseText; + } + get responseXML() { + invariant( + this.request.responseType === "" || this.request.responseType === "document", + "InvalidStateError: The object is in invalid state." + ); + if (this.request.readyState !== this.request.DONE) { + return null; + } + const contentType = this.request.getResponseHeader("Content-Type") || ""; + if (typeof DOMParser === "undefined") { + console.warn( + "Cannot retrieve XMLHttpRequest response body as XML: DOMParser is not defined. You are likely using an environment that is not browser or does not polyfill browser globals correctly." + ); + return null; + } + if (isDomParserSupportedType(contentType)) { + return new DOMParser().parseFromString( + this.responseBufferToText(), + contentType + ); + } + return null; + } + errorWith(error) { + this[kIsRequestHandled] = true; + this.logger.info("responding with an error"); + this.setReadyState(this.request.DONE); + this.trigger("error", this.request); + this.trigger("loadend", this.request); + } + /** + * Transitions this request's `readyState` to the given one. + */ + setReadyState(nextReadyState) { + this.logger.info( + "setReadyState: %d -> %d", + this.request.readyState, + nextReadyState + ); + if (this.request.readyState === nextReadyState) { + this.logger.info("ready state identical, skipping transition..."); + return; + } + define(this.request, "readyState", nextReadyState); + this.logger.info("set readyState to: %d", nextReadyState); + if (nextReadyState !== this.request.UNSENT) { + this.logger.info('triggerring "readystatechange" event...'); + this.trigger("readystatechange", this.request); + } + } + /** + * Triggers given event on the `XMLHttpRequest` instance. + */ + trigger(eventName, target, options) { + const callback = target[`on${eventName}`]; + const event = createEvent(target, eventName, options); + this.logger.info('trigger "%s"', eventName, options || ""); + if (typeof callback === "function") { + this.logger.info('found a direct "%s" callback, calling...', eventName); + callback.call(target, event); + } + const events = target instanceof XMLHttpRequestUpload ? this.uploadEvents : this.events; + for (const [registeredEventName, listeners] of events) { + if (registeredEventName === eventName) { + this.logger.info( + 'found %d listener(s) for "%s" event, calling...', + listeners.length, + eventName + ); + listeners.forEach((listener) => listener.call(target, event)); + } + } + } + /** + * Converts this `XMLHttpRequest` instance into a Fetch API `Request` instance. + */ + toFetchApiRequest(body) { + this.logger.info("converting request to a Fetch API Request..."); + const resolvedBody = body instanceof Document ? body.documentElement.innerText : body; + const fetchRequest = new Request(this.url.href, { + method: this.method, + headers: this.requestHeaders, + /** + * @see https://xhr.spec.whatwg.org/#cross-origin-credentials + */ + credentials: this.request.withCredentials ? "include" : "same-origin", + body: ["GET", "HEAD"].includes(this.method.toUpperCase()) ? null : resolvedBody + }); + const proxyHeaders = createProxy(fetchRequest.headers, { + methodCall: ([methodName, args], invoke) => { + switch (methodName) { + case "append": + case "set": { + const [headerName, headerValue] = args; + this.request.setRequestHeader(headerName, headerValue); + break; + } + case "delete": { + const [headerName] = args; + console.warn( + `XMLHttpRequest: Cannot remove a "${headerName}" header from the Fetch API representation of the "${fetchRequest.method} ${fetchRequest.url}" request. XMLHttpRequest headers cannot be removed.` + ); + break; + } + } + return invoke(); + } + }); + define(fetchRequest, "headers", proxyHeaders); + this.logger.info("converted request to a Fetch API Request!", fetchRequest); + return fetchRequest; + } +}; +kIsRequestHandled, kFetchRequest; +function toAbsoluteUrl(url) { + if (typeof location === "undefined") { + return new URL(url); + } + return new URL(url.toString(), location.href); +} +function define(target, property, value) { + Reflect.defineProperty(target, property, { + // Ensure writable properties to allow redefining readonly properties. + writable: true, + enumerable: true, + value + }); +} + +// src/interceptors/XMLHttpRequest/XMLHttpRequestProxy.ts +function createXMLHttpRequestProxy({ + emitter, + logger +}) { + const XMLHttpRequestProxy = new Proxy(globalThis.XMLHttpRequest, { + construct(target, args, newTarget) { + logger.info("constructed new XMLHttpRequest"); + const originalRequest = Reflect.construct( + target, + args, + newTarget + ); + const prototypeDescriptors = Object.getOwnPropertyDescriptors( + target.prototype + ); + for (const propertyName in prototypeDescriptors) { + Reflect.defineProperty( + originalRequest, + propertyName, + prototypeDescriptors[propertyName] + ); + } + const xhrRequestController = new XMLHttpRequestController( + originalRequest, + logger + ); + xhrRequestController.onRequest = async function({ request, requestId }) { + const controller = new RequestController(request); + this.logger.info("awaiting mocked response..."); + this.logger.info( + 'emitting the "request" event for %s listener(s)...', + emitter.listenerCount("request") + ); + const isRequestHandled = await handleRequest({ + request, + requestId, + controller, + emitter, + onResponse: async (response) => { + await this.respondWith(response); + }, + onRequestError: () => { + this.errorWith(new TypeError("Network error")); + }, + onError: (error) => { + this.logger.info("request errored!", { error }); + if (error instanceof Error) { + this.errorWith(error); + } + } + }); + if (!isRequestHandled) { + this.logger.info( + "no mocked response received, performing request as-is..." + ); + } + }; + xhrRequestController.onResponse = async function({ + response, + isMockedResponse, + request, + requestId + }) { + this.logger.info( + 'emitting the "response" event for %s listener(s)...', + emitter.listenerCount("response") + ); + emitter.emit("response", { + response, + isMockedResponse, + request, + requestId + }); + }; + return xhrRequestController.request; + } + }); + return XMLHttpRequestProxy; +} + +// src/interceptors/XMLHttpRequest/index.ts +var _XMLHttpRequestInterceptor = class extends Interceptor { + constructor() { + super(_XMLHttpRequestInterceptor.interceptorSymbol); + } + checkEnvironment() { + return hasConfigurableGlobal("XMLHttpRequest"); + } + setup() { + const logger = this.logger.extend("setup"); + logger.info('patching "XMLHttpRequest" module...'); + const PureXMLHttpRequest = globalThis.XMLHttpRequest; + invariant2( + !PureXMLHttpRequest[IS_PATCHED_MODULE], + 'Failed to patch the "XMLHttpRequest" module: already patched.' + ); + globalThis.XMLHttpRequest = createXMLHttpRequestProxy({ + emitter: this.emitter, + logger: this.logger + }); + logger.info( + 'native "XMLHttpRequest" module patched!', + globalThis.XMLHttpRequest.name + ); + Object.defineProperty(globalThis.XMLHttpRequest, IS_PATCHED_MODULE, { + enumerable: true, + configurable: true, + value: true + }); + this.subscriptions.push(() => { + Object.defineProperty(globalThis.XMLHttpRequest, IS_PATCHED_MODULE, { + value: void 0 + }); + globalThis.XMLHttpRequest = PureXMLHttpRequest; + logger.info( + 'native "XMLHttpRequest" module restored!', + globalThis.XMLHttpRequest.name + ); + }); + } +}; +var XMLHttpRequestInterceptor = _XMLHttpRequestInterceptor; +XMLHttpRequestInterceptor.interceptorSymbol = Symbol("xhr"); + +export { + XMLHttpRequestInterceptor +}; +//# sourceMappingURL=chunk-OMWE7UVM.mjs.map \ No newline at end of file diff --git a/node_modules/@mswjs/interceptors/lib/node/chunk-OMWE7UVM.mjs.map b/node_modules/@mswjs/interceptors/lib/node/chunk-OMWE7UVM.mjs.map new file mode 100644 index 0000000000000000000000000000000000000000..085f069c1950839b00d35ae30608fbf1f37086ae --- /dev/null +++ b/node_modules/@mswjs/interceptors/lib/node/chunk-OMWE7UVM.mjs.map @@ -0,0 +1 @@ +{"version":3,"sources":["../../src/interceptors/XMLHttpRequest/index.ts","../../src/interceptors/XMLHttpRequest/XMLHttpRequestController.ts","../../src/interceptors/XMLHttpRequest/utils/concatArrayBuffer.ts","../../src/interceptors/XMLHttpRequest/polyfills/EventPolyfill.ts","../../src/interceptors/XMLHttpRequest/polyfills/ProgressEventPolyfill.ts","../../src/interceptors/XMLHttpRequest/utils/createEvent.ts","../../src/utils/findPropertySource.ts","../../src/utils/createProxy.ts","../../src/interceptors/XMLHttpRequest/utils/isDomParserSupportedType.ts","../../src/utils/parseJson.ts","../../src/interceptors/XMLHttpRequest/utils/createResponse.ts","../../src/interceptors/XMLHttpRequest/utils/getBodyByteLength.ts","../../src/interceptors/XMLHttpRequest/XMLHttpRequestProxy.ts"],"sourcesContent":["import { invariant } from 'outvariant'\nimport { Emitter } from 'strict-event-emitter'\nimport { HttpRequestEventMap, IS_PATCHED_MODULE } from '../../glossary'\nimport { Interceptor } from '../../Interceptor'\nimport { createXMLHttpRequestProxy } from './XMLHttpRequestProxy'\nimport { hasConfigurableGlobal } from '../../utils/hasConfigurableGlobal'\n\nexport type XMLHttpRequestEmitter = Emitter\n\nexport class XMLHttpRequestInterceptor extends Interceptor {\n static interceptorSymbol = Symbol('xhr')\n\n constructor() {\n super(XMLHttpRequestInterceptor.interceptorSymbol)\n }\n\n protected checkEnvironment() {\n return hasConfigurableGlobal('XMLHttpRequest')\n }\n\n protected setup() {\n const logger = this.logger.extend('setup')\n\n logger.info('patching \"XMLHttpRequest\" module...')\n\n const PureXMLHttpRequest = globalThis.XMLHttpRequest\n\n invariant(\n !(PureXMLHttpRequest as any)[IS_PATCHED_MODULE],\n 'Failed to patch the \"XMLHttpRequest\" module: already patched.'\n )\n\n globalThis.XMLHttpRequest = createXMLHttpRequestProxy({\n emitter: this.emitter,\n logger: this.logger,\n })\n\n logger.info(\n 'native \"XMLHttpRequest\" module patched!',\n globalThis.XMLHttpRequest.name\n )\n\n Object.defineProperty(globalThis.XMLHttpRequest, IS_PATCHED_MODULE, {\n enumerable: true,\n configurable: true,\n value: true,\n })\n\n this.subscriptions.push(() => {\n Object.defineProperty(globalThis.XMLHttpRequest, IS_PATCHED_MODULE, {\n value: undefined,\n })\n\n globalThis.XMLHttpRequest = PureXMLHttpRequest\n logger.info(\n 'native \"XMLHttpRequest\" module restored!',\n globalThis.XMLHttpRequest.name\n )\n })\n }\n}\n","import { invariant } from 'outvariant'\nimport { isNodeProcess } from 'is-node-process'\nimport type { Logger } from '@open-draft/logger'\nimport { concatArrayBuffer } from './utils/concatArrayBuffer'\nimport { createEvent } from './utils/createEvent'\nimport {\n decodeBuffer,\n encodeBuffer,\n toArrayBuffer,\n} from '../../utils/bufferUtils'\nimport { createProxy } from '../../utils/createProxy'\nimport { isDomParserSupportedType } from './utils/isDomParserSupportedType'\nimport { parseJson } from '../../utils/parseJson'\nimport { createResponse } from './utils/createResponse'\nimport { INTERNAL_REQUEST_ID_HEADER_NAME } from '../../Interceptor'\nimport { createRequestId } from '../../createRequestId'\nimport { getBodyByteLength } from './utils/getBodyByteLength'\n\nconst kIsRequestHandled = Symbol('kIsRequestHandled')\nconst IS_NODE = isNodeProcess()\nconst kFetchRequest = Symbol('kFetchRequest')\n\n/**\n * An `XMLHttpRequest` instance controller that allows us\n * to handle any given request instance (e.g. responding to it).\n */\nexport class XMLHttpRequestController {\n public request: XMLHttpRequest\n public requestId: string\n public onRequest?: (\n this: XMLHttpRequestController,\n args: {\n request: Request\n requestId: string\n }\n ) => Promise\n public onResponse?: (\n this: XMLHttpRequestController,\n args: {\n response: Response\n isMockedResponse: boolean\n request: Request\n requestId: string\n }\n ) => void;\n\n [kIsRequestHandled]: boolean;\n [kFetchRequest]?: Request\n private method: string = 'GET'\n private url: URL = null as any\n private requestHeaders: Headers\n private responseBuffer: Uint8Array\n private events: Map>\n private uploadEvents: Map<\n keyof XMLHttpRequestEventTargetEventMap,\n Array\n >\n\n constructor(readonly initialRequest: XMLHttpRequest, public logger: Logger) {\n this[kIsRequestHandled] = false\n\n this.events = new Map()\n this.uploadEvents = new Map()\n this.requestId = createRequestId()\n this.requestHeaders = new Headers()\n this.responseBuffer = new Uint8Array()\n\n this.request = createProxy(initialRequest, {\n setProperty: ([propertyName, nextValue], invoke) => {\n switch (propertyName) {\n case 'ontimeout': {\n const eventName = propertyName.slice(\n 2\n ) as keyof XMLHttpRequestEventTargetEventMap\n\n /**\n * @note Proxy callbacks to event listeners because JSDOM has trouble\n * translating these properties to callbacks. It seemed to be operating\n * on events exclusively.\n */\n this.request.addEventListener(eventName, nextValue as any)\n\n return invoke()\n }\n\n default: {\n return invoke()\n }\n }\n },\n methodCall: ([methodName, args], invoke) => {\n switch (methodName) {\n case 'open': {\n const [method, url] = args as [string, string | undefined]\n\n if (typeof url === 'undefined') {\n this.method = 'GET'\n this.url = toAbsoluteUrl(method)\n } else {\n this.method = method\n this.url = toAbsoluteUrl(url)\n }\n\n this.logger = this.logger.extend(`${this.method} ${this.url.href}`)\n this.logger.info('open', this.method, this.url.href)\n\n return invoke()\n }\n\n case 'addEventListener': {\n const [eventName, listener] = args as [\n keyof XMLHttpRequestEventTargetEventMap,\n Function\n ]\n\n this.registerEvent(eventName, listener)\n this.logger.info('addEventListener', eventName, listener)\n\n return invoke()\n }\n\n case 'setRequestHeader': {\n const [name, value] = args as [string, string]\n this.requestHeaders.set(name, value)\n\n this.logger.info('setRequestHeader', name, value)\n\n return invoke()\n }\n\n case 'send': {\n const [body] = args as [\n body?: XMLHttpRequestBodyInit | Document | null\n ]\n\n this.request.addEventListener('load', () => {\n if (typeof this.onResponse !== 'undefined') {\n // Create a Fetch API Response representation of whichever\n // response this XMLHttpRequest received. Note those may\n // be either a mocked and the original response.\n const fetchResponse = createResponse(\n this.request,\n /**\n * The `response` property is the right way to read\n * the ambiguous response body, as the request's \"responseType\" may differ.\n * @see https://xhr.spec.whatwg.org/#the-response-attribute\n */\n this.request.response\n )\n\n // Notify the consumer about the response.\n this.onResponse.call(this, {\n response: fetchResponse,\n isMockedResponse: this[kIsRequestHandled],\n request: fetchRequest,\n requestId: this.requestId!,\n })\n }\n })\n\n const requestBody =\n typeof body === 'string' ? encodeBuffer(body) : body\n\n // Delegate request handling to the consumer.\n const fetchRequest = this.toFetchApiRequest(requestBody)\n this[kFetchRequest] = fetchRequest.clone()\n\n const onceRequestSettled =\n this.onRequest?.call(this, {\n request: fetchRequest,\n requestId: this.requestId!,\n }) || Promise.resolve()\n\n onceRequestSettled.finally(() => {\n // If the consumer didn't handle the request (called `.respondWith()`) perform it as-is.\n if (!this[kIsRequestHandled]) {\n this.logger.info(\n 'request callback settled but request has not been handled (readystate %d), performing as-is...',\n this.request.readyState\n )\n\n /**\n * @note Set the intercepted request ID on the original request in Node.js\n * so that if it triggers any other interceptors, they don't attempt\n * to process it once again.\n *\n * For instance, XMLHttpRequest is often implemented via \"http.ClientRequest\"\n * and we don't want for both XHR and ClientRequest interceptors to\n * handle the same request at the same time (e.g. emit the \"response\" event twice).\n */\n if (IS_NODE) {\n this.request.setRequestHeader(\n INTERNAL_REQUEST_ID_HEADER_NAME,\n this.requestId!\n )\n }\n\n return invoke()\n }\n })\n\n break\n }\n\n default: {\n return invoke()\n }\n }\n },\n })\n\n /**\n * Proxy the `.upload` property to gather the event listeners/callbacks.\n */\n define(\n this.request,\n 'upload',\n createProxy(this.request.upload, {\n setProperty: ([propertyName, nextValue], invoke) => {\n switch (propertyName) {\n case 'onloadstart':\n case 'onprogress':\n case 'onaboart':\n case 'onerror':\n case 'onload':\n case 'ontimeout':\n case 'onloadend': {\n const eventName = propertyName.slice(\n 2\n ) as keyof XMLHttpRequestEventTargetEventMap\n\n this.registerUploadEvent(eventName, nextValue as Function)\n }\n }\n\n return invoke()\n },\n methodCall: ([methodName, args], invoke) => {\n switch (methodName) {\n case 'addEventListener': {\n const [eventName, listener] = args as [\n keyof XMLHttpRequestEventTargetEventMap,\n Function\n ]\n this.registerUploadEvent(eventName, listener)\n this.logger.info('upload.addEventListener', eventName, listener)\n\n return invoke()\n }\n }\n },\n })\n )\n }\n\n private registerEvent(\n eventName: keyof XMLHttpRequestEventTargetEventMap,\n listener: Function\n ): void {\n const prevEvents = this.events.get(eventName) || []\n const nextEvents = prevEvents.concat(listener)\n this.events.set(eventName, nextEvents)\n\n this.logger.info('registered event \"%s\"', eventName, listener)\n }\n\n private registerUploadEvent(\n eventName: keyof XMLHttpRequestEventTargetEventMap,\n listener: Function\n ): void {\n const prevEvents = this.uploadEvents.get(eventName) || []\n const nextEvents = prevEvents.concat(listener)\n this.uploadEvents.set(eventName, nextEvents)\n\n this.logger.info('registered upload event \"%s\"', eventName, listener)\n }\n\n /**\n * Responds to the current request with the given\n * Fetch API `Response` instance.\n */\n public async respondWith(response: Response): Promise {\n /**\n * @note Since `XMLHttpRequestController` delegates the handling of the responses\n * to the \"load\" event listener that doesn't distinguish between the mocked and original\n * responses, mark the request that had a mocked response with a corresponding symbol.\n *\n * Mark this request as having a mocked response immediately since\n * calculating request/response total body length is asynchronous.\n */\n this[kIsRequestHandled] = true\n\n /**\n * Dispatch request upload events for requests with a body.\n * @see https://github.com/mswjs/interceptors/issues/573\n */\n if (this[kFetchRequest]) {\n const totalRequestBodyLength = await getBodyByteLength(\n this[kFetchRequest]\n )\n\n this.trigger('loadstart', this.request.upload, {\n loaded: 0,\n total: totalRequestBodyLength,\n })\n this.trigger('progress', this.request.upload, {\n loaded: totalRequestBodyLength,\n total: totalRequestBodyLength,\n })\n this.trigger('load', this.request.upload, {\n loaded: totalRequestBodyLength,\n total: totalRequestBodyLength,\n })\n this.trigger('loadend', this.request.upload, {\n loaded: totalRequestBodyLength,\n total: totalRequestBodyLength,\n })\n }\n\n this.logger.info(\n 'responding with a mocked response: %d %s',\n response.status,\n response.statusText\n )\n\n define(this.request, 'status', response.status)\n define(this.request, 'statusText', response.statusText)\n define(this.request, 'responseURL', this.url.href)\n\n this.request.getResponseHeader = new Proxy(this.request.getResponseHeader, {\n apply: (_, __, args: [name: string]) => {\n this.logger.info('getResponseHeader', args[0])\n\n if (this.request.readyState < this.request.HEADERS_RECEIVED) {\n this.logger.info('headers not received yet, returning null')\n\n // Headers not received yet, nothing to return.\n return null\n }\n\n const headerValue = response.headers.get(args[0])\n this.logger.info(\n 'resolved response header \"%s\" to',\n args[0],\n headerValue\n )\n\n return headerValue\n },\n })\n\n this.request.getAllResponseHeaders = new Proxy(\n this.request.getAllResponseHeaders,\n {\n apply: () => {\n this.logger.info('getAllResponseHeaders')\n\n if (this.request.readyState < this.request.HEADERS_RECEIVED) {\n this.logger.info('headers not received yet, returning empty string')\n\n // Headers not received yet, nothing to return.\n return ''\n }\n\n const headersList = Array.from(response.headers.entries())\n const allHeaders = headersList\n .map(([headerName, headerValue]) => {\n return `${headerName}: ${headerValue}`\n })\n .join('\\r\\n')\n\n this.logger.info('resolved all response headers to', allHeaders)\n\n return allHeaders\n },\n }\n )\n\n // Update the response getters to resolve against the mocked response.\n Object.defineProperties(this.request, {\n response: {\n enumerable: true,\n configurable: false,\n get: () => this.response,\n },\n responseText: {\n enumerable: true,\n configurable: false,\n get: () => this.responseText,\n },\n responseXML: {\n enumerable: true,\n configurable: false,\n get: () => this.responseXML,\n },\n })\n\n const totalResponseBodyLength = await getBodyByteLength(response.clone())\n\n this.logger.info('calculated response body length', totalResponseBodyLength)\n\n this.trigger('loadstart', this.request, {\n loaded: 0,\n total: totalResponseBodyLength,\n })\n\n this.setReadyState(this.request.HEADERS_RECEIVED)\n this.setReadyState(this.request.LOADING)\n\n const finalizeResponse = () => {\n this.logger.info('finalizing the mocked response...')\n\n this.setReadyState(this.request.DONE)\n\n this.trigger('load', this.request, {\n loaded: this.responseBuffer.byteLength,\n total: totalResponseBodyLength,\n })\n\n this.trigger('loadend', this.request, {\n loaded: this.responseBuffer.byteLength,\n total: totalResponseBodyLength,\n })\n }\n\n if (response.body) {\n this.logger.info('mocked response has body, streaming...')\n\n const reader = response.body.getReader()\n\n const readNextResponseBodyChunk = async () => {\n const { value, done } = await reader.read()\n\n if (done) {\n this.logger.info('response body stream done!')\n finalizeResponse()\n return\n }\n\n if (value) {\n this.logger.info('read response body chunk:', value)\n this.responseBuffer = concatArrayBuffer(this.responseBuffer, value)\n\n this.trigger('progress', this.request, {\n loaded: this.responseBuffer.byteLength,\n total: totalResponseBodyLength,\n })\n }\n\n readNextResponseBodyChunk()\n }\n\n readNextResponseBodyChunk()\n } else {\n finalizeResponse()\n }\n }\n\n private responseBufferToText(): string {\n return decodeBuffer(this.responseBuffer)\n }\n\n get response(): unknown {\n this.logger.info(\n 'getResponse (responseType: %s)',\n this.request.responseType\n )\n\n if (this.request.readyState !== this.request.DONE) {\n return null\n }\n\n switch (this.request.responseType) {\n case 'json': {\n const responseJson = parseJson(this.responseBufferToText())\n this.logger.info('resolved response JSON', responseJson)\n\n return responseJson\n }\n\n case 'arraybuffer': {\n const arrayBuffer = toArrayBuffer(this.responseBuffer)\n this.logger.info('resolved response ArrayBuffer', arrayBuffer)\n\n return arrayBuffer\n }\n\n case 'blob': {\n const mimeType =\n this.request.getResponseHeader('Content-Type') || 'text/plain'\n const responseBlob = new Blob([this.responseBufferToText()], {\n type: mimeType,\n })\n\n this.logger.info(\n 'resolved response Blob (mime type: %s)',\n responseBlob,\n mimeType\n )\n\n return responseBlob\n }\n\n default: {\n const responseText = this.responseBufferToText()\n this.logger.info(\n 'resolving \"%s\" response type as text',\n this.request.responseType,\n responseText\n )\n\n return responseText\n }\n }\n }\n\n get responseText(): string {\n /**\n * Throw when trying to read the response body as text when the\n * \"responseType\" doesn't expect text. This just respects the spec better.\n * @see https://xhr.spec.whatwg.org/#the-responsetext-attribute\n */\n invariant(\n this.request.responseType === '' || this.request.responseType === 'text',\n 'InvalidStateError: The object is in invalid state.'\n )\n\n if (\n this.request.readyState !== this.request.LOADING &&\n this.request.readyState !== this.request.DONE\n ) {\n return ''\n }\n\n const responseText = this.responseBufferToText()\n this.logger.info('getResponseText: \"%s\"', responseText)\n\n return responseText\n }\n\n get responseXML(): Document | null {\n invariant(\n this.request.responseType === '' ||\n this.request.responseType === 'document',\n 'InvalidStateError: The object is in invalid state.'\n )\n\n if (this.request.readyState !== this.request.DONE) {\n return null\n }\n\n const contentType = this.request.getResponseHeader('Content-Type') || ''\n\n if (typeof DOMParser === 'undefined') {\n console.warn(\n 'Cannot retrieve XMLHttpRequest response body as XML: DOMParser is not defined. You are likely using an environment that is not browser or does not polyfill browser globals correctly.'\n )\n return null\n }\n\n if (isDomParserSupportedType(contentType)) {\n return new DOMParser().parseFromString(\n this.responseBufferToText(),\n contentType\n )\n }\n\n return null\n }\n\n public errorWith(error?: Error): void {\n /**\n * @note Mark this request as handled even if it received a mock error.\n * This prevents the controller from trying to perform this request as-is.\n */\n this[kIsRequestHandled] = true\n this.logger.info('responding with an error')\n\n this.setReadyState(this.request.DONE)\n this.trigger('error', this.request)\n this.trigger('loadend', this.request)\n }\n\n /**\n * Transitions this request's `readyState` to the given one.\n */\n private setReadyState(nextReadyState: number): void {\n this.logger.info(\n 'setReadyState: %d -> %d',\n this.request.readyState,\n nextReadyState\n )\n\n if (this.request.readyState === nextReadyState) {\n this.logger.info('ready state identical, skipping transition...')\n return\n }\n\n define(this.request, 'readyState', nextReadyState)\n\n this.logger.info('set readyState to: %d', nextReadyState)\n\n if (nextReadyState !== this.request.UNSENT) {\n this.logger.info('triggerring \"readystatechange\" event...')\n\n this.trigger('readystatechange', this.request)\n }\n }\n\n /**\n * Triggers given event on the `XMLHttpRequest` instance.\n */\n private trigger<\n EventName extends keyof (XMLHttpRequestEventTargetEventMap & {\n readystatechange: ProgressEvent\n })\n >(\n eventName: EventName,\n target: XMLHttpRequest | XMLHttpRequestUpload,\n options?: ProgressEventInit\n ): void {\n const callback = (target as XMLHttpRequest)[`on${eventName}`]\n const event = createEvent(target, eventName, options)\n\n this.logger.info('trigger \"%s\"', eventName, options || '')\n\n // Invoke direct callbacks.\n if (typeof callback === 'function') {\n this.logger.info('found a direct \"%s\" callback, calling...', eventName)\n callback.call(target as XMLHttpRequest, event)\n }\n\n // Invoke event listeners.\n const events =\n target instanceof XMLHttpRequestUpload ? this.uploadEvents : this.events\n\n for (const [registeredEventName, listeners] of events) {\n if (registeredEventName === eventName) {\n this.logger.info(\n 'found %d listener(s) for \"%s\" event, calling...',\n listeners.length,\n eventName\n )\n\n listeners.forEach((listener) => listener.call(target, event))\n }\n }\n }\n\n /**\n * Converts this `XMLHttpRequest` instance into a Fetch API `Request` instance.\n */\n private toFetchApiRequest(\n body: XMLHttpRequestBodyInit | Document | null | undefined\n ): Request {\n this.logger.info('converting request to a Fetch API Request...')\n\n // If the `Document` is used as the body of this XMLHttpRequest,\n // set its inner text as the Fetch API Request body.\n const resolvedBody =\n body instanceof Document ? body.documentElement.innerText : body\n\n const fetchRequest = new Request(this.url.href, {\n method: this.method,\n headers: this.requestHeaders,\n /**\n * @see https://xhr.spec.whatwg.org/#cross-origin-credentials\n */\n credentials: this.request.withCredentials ? 'include' : 'same-origin',\n body: ['GET', 'HEAD'].includes(this.method.toUpperCase())\n ? null\n : resolvedBody,\n })\n\n const proxyHeaders = createProxy(fetchRequest.headers, {\n methodCall: ([methodName, args], invoke) => {\n // Forward the latest state of the internal request headers\n // because the interceptor might have modified them\n // without responding to the request.\n switch (methodName) {\n case 'append':\n case 'set': {\n const [headerName, headerValue] = args as [string, string]\n this.request.setRequestHeader(headerName, headerValue)\n break\n }\n\n case 'delete': {\n const [headerName] = args as [string]\n console.warn(\n `XMLHttpRequest: Cannot remove a \"${headerName}\" header from the Fetch API representation of the \"${fetchRequest.method} ${fetchRequest.url}\" request. XMLHttpRequest headers cannot be removed.`\n )\n break\n }\n }\n\n return invoke()\n },\n })\n define(fetchRequest, 'headers', proxyHeaders)\n\n this.logger.info('converted request to a Fetch API Request!', fetchRequest)\n\n return fetchRequest\n }\n}\n\nfunction toAbsoluteUrl(url: string | URL): URL {\n /**\n * @note XMLHttpRequest interceptor may run in environments\n * that implement XMLHttpRequest but don't implement \"location\"\n * (for example, React Native). If that's the case, return the\n * input URL as-is (nothing to be relative to).\n * @see https://github.com/mswjs/msw/issues/1777\n */\n if (typeof location === 'undefined') {\n return new URL(url)\n }\n\n return new URL(url.toString(), location.href)\n}\n\nfunction define(\n target: object,\n property: string | symbol,\n value: unknown\n): void {\n Reflect.defineProperty(target, property, {\n // Ensure writable properties to allow redefining readonly properties.\n writable: true,\n enumerable: true,\n value,\n })\n}\n","/**\n * Concatenate two `Uint8Array` buffers.\n */\nexport function concatArrayBuffer(\n left: Uint8Array,\n right: Uint8Array\n): Uint8Array {\n const result = new Uint8Array(left.byteLength + right.byteLength)\n result.set(left, 0)\n result.set(right, left.byteLength)\n return result\n}\n","export class EventPolyfill implements Event {\n readonly NONE = 0\n readonly CAPTURING_PHASE = 1\n readonly AT_TARGET = 2\n readonly BUBBLING_PHASE = 3\n\n public type: string = ''\n public srcElement: EventTarget | null = null\n public target: EventTarget | null\n public currentTarget: EventTarget | null = null\n public eventPhase: number = 0\n public timeStamp: number\n public isTrusted: boolean = true\n public composed: boolean = false\n public cancelable: boolean = true\n public defaultPrevented: boolean = false\n public bubbles: boolean = true\n public lengthComputable: boolean = true\n public loaded: number = 0\n public total: number = 0\n\n cancelBubble: boolean = false\n returnValue: boolean = true\n\n constructor(\n type: string,\n options?: { target: EventTarget; currentTarget: EventTarget }\n ) {\n this.type = type\n this.target = options?.target || null\n this.currentTarget = options?.currentTarget || null\n this.timeStamp = Date.now()\n }\n\n public composedPath(): EventTarget[] {\n return []\n }\n\n public initEvent(type: string, bubbles?: boolean, cancelable?: boolean) {\n this.type = type\n this.bubbles = !!bubbles\n this.cancelable = !!cancelable\n }\n\n public preventDefault() {\n this.defaultPrevented = true\n }\n\n public stopPropagation() {}\n public stopImmediatePropagation() {}\n}\n","import { EventPolyfill } from './EventPolyfill'\n\nexport class ProgressEventPolyfill extends EventPolyfill {\n readonly lengthComputable: boolean\n readonly composed: boolean\n readonly loaded: number\n readonly total: number\n\n constructor(type: string, init?: ProgressEventInit) {\n super(type)\n\n this.lengthComputable = init?.lengthComputable || false\n this.composed = init?.composed || false\n this.loaded = init?.loaded || 0\n this.total = init?.total || 0\n }\n}\n","import { EventPolyfill } from '../polyfills/EventPolyfill'\nimport { ProgressEventPolyfill } from '../polyfills/ProgressEventPolyfill'\n\nconst SUPPORTS_PROGRESS_EVENT = typeof ProgressEvent !== 'undefined'\n\nexport function createEvent(\n target: XMLHttpRequest | XMLHttpRequestUpload,\n type: string,\n init?: ProgressEventInit\n): EventPolyfill | ProgressEvent {\n const progressEvents = [\n 'error',\n 'progress',\n 'loadstart',\n 'loadend',\n 'load',\n 'timeout',\n 'abort',\n ]\n\n /**\n * `ProgressEvent` is not supported in React Native.\n * @see https://github.com/mswjs/interceptors/issues/40\n */\n const ProgressEventClass = SUPPORTS_PROGRESS_EVENT\n ? ProgressEvent\n : ProgressEventPolyfill\n\n const event = progressEvents.includes(type)\n ? new ProgressEventClass(type, {\n lengthComputable: true,\n loaded: init?.loaded || 0,\n total: init?.total || 0,\n })\n : new EventPolyfill(type, {\n target,\n currentTarget: target,\n })\n\n return event\n}\n","/**\n * Returns the source object of the given property on the target object\n * (the target itself, any parent in its prototype, or null).\n */\nexport function findPropertySource(\n target: object,\n propertyName: string | symbol\n): object | null {\n if (!(propertyName in target)) {\n return null\n }\n\n const hasProperty = Object.prototype.hasOwnProperty.call(target, propertyName)\n if (hasProperty) {\n return target\n }\n\n const prototype = Reflect.getPrototypeOf(target)\n return prototype ? findPropertySource(prototype, propertyName) : null\n}\n","import { findPropertySource } from './findPropertySource'\n\nexport interface ProxyOptions> {\n constructorCall?(args: Array, next: NextFunction): Target\n\n methodCall?(\n this: Target,\n data: [methodName: F, args: Array],\n next: NextFunction\n ): void\n\n setProperty?(\n data: [propertyName: string | symbol, nextValue: unknown],\n next: NextFunction\n ): boolean\n\n getProperty?(\n data: [propertyName: string | symbol, receiver: Target],\n next: NextFunction\n ): void\n}\n\nexport type NextFunction = () => ReturnType\n\nexport function createProxy(\n target: Target,\n options: ProxyOptions\n): Target {\n const proxy = new Proxy(target, optionsToProxyHandler(options))\n\n return proxy\n}\n\nfunction optionsToProxyHandler>(\n options: ProxyOptions\n): ProxyHandler {\n const { constructorCall, methodCall, getProperty, setProperty } = options\n const handler: ProxyHandler = {}\n\n if (typeof constructorCall !== 'undefined') {\n handler.construct = function (target, args, newTarget) {\n const next = Reflect.construct.bind(null, target as any, args, newTarget)\n return constructorCall.call(newTarget, args, next)\n }\n }\n\n handler.set = function (target, propertyName, nextValue) {\n const next = () => {\n const propertySource = findPropertySource(target, propertyName) || target\n const ownDescriptors = Reflect.getOwnPropertyDescriptor(\n propertySource,\n propertyName\n )\n\n // Respect any custom setters present for this property.\n if (typeof ownDescriptors?.set !== 'undefined') {\n ownDescriptors.set.apply(target, [nextValue])\n return true\n }\n\n // Otherwise, set the property on the source.\n return Reflect.defineProperty(propertySource, propertyName, {\n writable: true,\n enumerable: true,\n configurable: true,\n value: nextValue,\n })\n }\n\n if (typeof setProperty !== 'undefined') {\n return setProperty.call(target, [propertyName, nextValue], next)\n }\n\n return next()\n }\n\n handler.get = function (target, propertyName, receiver) {\n /**\n * @note Using `Reflect.get()` here causes \"TypeError: Illegal invocation\".\n */\n const next = () => target[propertyName as any]\n\n const value =\n typeof getProperty !== 'undefined'\n ? getProperty.call(target, [propertyName, receiver], next)\n : next()\n\n if (typeof value === 'function') {\n return (...args: Array) => {\n const next = value.bind(target, ...args)\n\n if (typeof methodCall !== 'undefined') {\n return methodCall.call(target, [propertyName as any, args], next)\n }\n\n return next()\n }\n }\n\n return value\n }\n\n return handler\n}\n","export function isDomParserSupportedType(\n type: string\n): type is DOMParserSupportedType {\n const supportedTypes: Array = [\n 'application/xhtml+xml',\n 'application/xml',\n 'image/svg+xml',\n 'text/html',\n 'text/xml',\n ]\n return supportedTypes.some((supportedType) => {\n return type.startsWith(supportedType)\n })\n}\n","/**\n * Parses a given string into JSON.\n * Gracefully handles invalid JSON by returning `null`.\n */\nexport function parseJson(data: string): Record | null {\n try {\n const json = JSON.parse(data)\n return json\n } catch (_) {\n return null\n }\n}\n","import { FetchResponse } from '../../../utils/fetchUtils'\n\n/**\n * Creates a Fetch API `Response` instance from the given\n * `XMLHttpRequest` instance and a response body.\n */\nexport function createResponse(\n request: XMLHttpRequest,\n body: BodyInit | null\n): Response {\n /**\n * Handle XMLHttpRequest responses that must have null as the\n * response body when represented using Fetch API Response.\n * XMLHttpRequest response will always have an empty string\n * as the \"request.response\" in those cases, resulting in an error\n * when constructing a Response instance.\n * @see https://github.com/mswjs/interceptors/issues/379\n */\n const responseBodyOrNull = FetchResponse.isResponseWithBody(request.status)\n ? body\n : null\n\n return new FetchResponse(responseBodyOrNull, {\n url: request.responseURL,\n status: request.status,\n statusText: request.statusText,\n headers: createHeadersFromXMLHttpReqestHeaders(\n request.getAllResponseHeaders()\n ),\n })\n}\n\nfunction createHeadersFromXMLHttpReqestHeaders(headersString: string): Headers {\n const headers = new Headers()\n\n const lines = headersString.split(/[\\r\\n]+/)\n for (const line of lines) {\n if (line.trim() === '') {\n continue\n }\n\n const [name, ...parts] = line.split(': ')\n const value = parts.join(': ')\n\n headers.append(name, value)\n }\n\n return headers\n}\n","/**\n * Return a total byte length of the given request/response body.\n * If the `Content-Length` header is present, it will be used as the byte length.\n */\nexport async function getBodyByteLength(\n input: Request | Response\n): Promise {\n const explicitContentLength = input.headers.get('content-length')\n\n if (explicitContentLength != null && explicitContentLength !== '') {\n return Number(explicitContentLength)\n }\n\n const buffer = await input.arrayBuffer()\n return buffer.byteLength\n}\n","import type { Logger } from '@open-draft/logger'\nimport { XMLHttpRequestEmitter } from '.'\nimport { RequestController } from '../../RequestController'\nimport { XMLHttpRequestController } from './XMLHttpRequestController'\nimport { handleRequest } from '../../utils/handleRequest'\n\nexport interface XMLHttpRequestProxyOptions {\n emitter: XMLHttpRequestEmitter\n logger: Logger\n}\n\n/**\n * Create a proxied `XMLHttpRequest` class.\n * The proxied class establishes spies on certain methods,\n * allowing us to intercept requests and respond to them.\n */\nexport function createXMLHttpRequestProxy({\n emitter,\n logger,\n}: XMLHttpRequestProxyOptions) {\n const XMLHttpRequestProxy = new Proxy(globalThis.XMLHttpRequest, {\n construct(target, args, newTarget) {\n logger.info('constructed new XMLHttpRequest')\n\n const originalRequest = Reflect.construct(\n target,\n args,\n newTarget\n ) as XMLHttpRequest\n\n /**\n * @note Forward prototype descriptors onto the proxied object.\n * XMLHttpRequest is implemented in JSDOM in a way that assigns\n * a bunch of descriptors, like \"set responseType()\" on the prototype.\n * With this propagation, we make sure that those descriptors trigger\n * when the user operates with the proxied request instance.\n */\n const prototypeDescriptors = Object.getOwnPropertyDescriptors(\n target.prototype\n )\n for (const propertyName in prototypeDescriptors) {\n Reflect.defineProperty(\n originalRequest,\n propertyName,\n prototypeDescriptors[propertyName]\n )\n }\n\n const xhrRequestController = new XMLHttpRequestController(\n originalRequest,\n logger\n )\n\n xhrRequestController.onRequest = async function ({ request, requestId }) {\n const controller = new RequestController(request)\n\n this.logger.info('awaiting mocked response...')\n\n this.logger.info(\n 'emitting the \"request\" event for %s listener(s)...',\n emitter.listenerCount('request')\n )\n\n const isRequestHandled = await handleRequest({\n request,\n requestId,\n controller,\n emitter,\n onResponse: async (response) => {\n await this.respondWith(response)\n },\n onRequestError: () => {\n this.errorWith(new TypeError('Network error'))\n },\n onError: (error) => {\n this.logger.info('request errored!', { error })\n\n if (error instanceof Error) {\n this.errorWith(error)\n }\n },\n })\n\n if (!isRequestHandled) {\n this.logger.info(\n 'no mocked response received, performing request as-is...'\n )\n }\n }\n\n xhrRequestController.onResponse = async function ({\n response,\n isMockedResponse,\n request,\n requestId,\n }) {\n this.logger.info(\n 'emitting the \"response\" event for %s listener(s)...',\n emitter.listenerCount('response')\n )\n\n emitter.emit('response', {\n response,\n isMockedResponse,\n request,\n requestId,\n })\n }\n\n // Return the proxied request from the controller\n // so that the controller can react to the consumer's interactions\n // with this request (opening/sending/etc).\n return xhrRequestController.request\n },\n })\n\n return XMLHttpRequestProxy\n}\n"],"mappings":"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","names":["invariant","next","invariant"]} \ No newline at end of file diff --git a/node_modules/@mswjs/interceptors/lib/node/chunk-PFGO5BSM.js b/node_modules/@mswjs/interceptors/lib/node/chunk-PFGO5BSM.js new file mode 100644 index 0000000000000000000000000000000000000000..3206fc0cb780f904a0c0b48ce7194828ae296162 --- /dev/null +++ b/node_modules/@mswjs/interceptors/lib/node/chunk-PFGO5BSM.js @@ -0,0 +1,25 @@ +"use strict";Object.defineProperty(exports, "__esModule", {value: true});// src/utils/hasConfigurableGlobal.ts +function hasConfigurableGlobal(propertyName) { + const descriptor = Object.getOwnPropertyDescriptor(globalThis, propertyName); + if (typeof descriptor === "undefined") { + return false; + } + if (typeof descriptor.get === "function" && typeof descriptor.get() === "undefined") { + return false; + } + if (typeof descriptor.get === "undefined" && descriptor.value == null) { + return false; + } + if (typeof descriptor.set === "undefined" && !descriptor.configurable) { + console.error( + `[MSW] Failed to apply interceptor: the global \`${propertyName}\` property is non-configurable. This is likely an issue with your environment. If you are using a framework, please open an issue about this in their repository.` + ); + return false; + } + return true; +} + + + +exports.hasConfigurableGlobal = hasConfigurableGlobal; +//# sourceMappingURL=chunk-PFGO5BSM.js.map \ No newline at end of file diff --git a/node_modules/@mswjs/interceptors/lib/node/chunk-PFGO5BSM.js.map b/node_modules/@mswjs/interceptors/lib/node/chunk-PFGO5BSM.js.map new file mode 100644 index 0000000000000000000000000000000000000000..4069b5ab7b51ea60c2a3a8490c4b95b71d3797ab --- /dev/null +++ b/node_modules/@mswjs/interceptors/lib/node/chunk-PFGO5BSM.js.map @@ -0,0 +1 @@ +{"version":3,"sources":["../../src/utils/hasConfigurableGlobal.ts"],"names":[],"mappings":";AAIO,SAAS,sBAAsB,cAA+B;AACnE,QAAM,aAAa,OAAO,yBAAyB,YAAY,YAAY;AAG3E,MAAI,OAAO,eAAe,aAAa;AACrC,WAAO;AAAA,EACT;AAGA,MACE,OAAO,WAAW,QAAQ,cAC1B,OAAO,WAAW,IAAI,MAAM,aAC5B;AACA,WAAO;AAAA,EACT;AAGA,MAAI,OAAO,WAAW,QAAQ,eAAe,WAAW,SAAS,MAAM;AACrE,WAAO;AAAA,EACT;AAEA,MAAI,OAAO,WAAW,QAAQ,eAAe,CAAC,WAAW,cAAc;AACrE,YAAQ;AAAA,MACN,mDAAmD;AAAA,IACrD;AACA,WAAO;AAAA,EACT;AAEA,SAAO;AACT","sourcesContent":["/**\n * Returns a boolean indicating whether the given global property\n * is defined and is configurable.\n */\nexport function hasConfigurableGlobal(propertyName: string): boolean {\n const descriptor = Object.getOwnPropertyDescriptor(globalThis, propertyName)\n\n // The property is not set at all.\n if (typeof descriptor === 'undefined') {\n return false\n }\n\n // The property is set to a getter that returns undefined.\n if (\n typeof descriptor.get === 'function' &&\n typeof descriptor.get() === 'undefined'\n ) {\n return false\n }\n\n // The property is set to a value equal to undefined.\n if (typeof descriptor.get === 'undefined' && descriptor.value == null) {\n return false\n }\n\n if (typeof descriptor.set === 'undefined' && !descriptor.configurable) {\n console.error(\n `[MSW] Failed to apply interceptor: the global \\`${propertyName}\\` property is non-configurable. This is likely an issue with your environment. If you are using a framework, please open an issue about this in their repository.`\n )\n return false\n }\n\n return true\n}\n"]} \ No newline at end of file diff --git a/node_modules/@mswjs/interceptors/lib/node/chunk-PJA4E426.mjs b/node_modules/@mswjs/interceptors/lib/node/chunk-PJA4E426.mjs new file mode 100644 index 0000000000000000000000000000000000000000..e3d8725da89810d1882c074193a4ac692a4e6728 --- /dev/null +++ b/node_modules/@mswjs/interceptors/lib/node/chunk-PJA4E426.mjs @@ -0,0 +1,51 @@ +import { + Interceptor +} from "./chunk-I7HQIBT7.mjs"; + +// src/BatchInterceptor.ts +var BatchInterceptor = class extends Interceptor { + constructor(options) { + BatchInterceptor.symbol = Symbol(options.name); + super(BatchInterceptor.symbol); + this.interceptors = options.interceptors; + } + setup() { + const logger = this.logger.extend("setup"); + logger.info("applying all %d interceptors...", this.interceptors.length); + for (const interceptor of this.interceptors) { + logger.info('applying "%s" interceptor...', interceptor.constructor.name); + interceptor.apply(); + logger.info("adding interceptor dispose subscription"); + this.subscriptions.push(() => interceptor.dispose()); + } + } + on(event, listener) { + for (const interceptor of this.interceptors) { + interceptor.on(event, listener); + } + return this; + } + once(event, listener) { + for (const interceptor of this.interceptors) { + interceptor.once(event, listener); + } + return this; + } + off(event, listener) { + for (const interceptor of this.interceptors) { + interceptor.off(event, listener); + } + return this; + } + removeAllListeners(event) { + for (const interceptors of this.interceptors) { + interceptors.removeAllListeners(event); + } + return this; + } +}; + +export { + BatchInterceptor +}; +//# sourceMappingURL=chunk-PJA4E426.mjs.map \ No newline at end of file diff --git a/node_modules/@mswjs/interceptors/lib/node/chunk-PJA4E426.mjs.map b/node_modules/@mswjs/interceptors/lib/node/chunk-PJA4E426.mjs.map new file mode 100644 index 0000000000000000000000000000000000000000..9569e4edae42e44acab6716f4c0a4ba4a8933c3a --- /dev/null +++ b/node_modules/@mswjs/interceptors/lib/node/chunk-PJA4E426.mjs.map @@ -0,0 +1 @@ +{"version":3,"sources":["../../src/BatchInterceptor.ts"],"sourcesContent":["import { EventMap, Listener } from 'strict-event-emitter'\nimport { Interceptor, ExtractEventNames } from './Interceptor'\n\nexport interface BatchInterceptorOptions<\n InterceptorList extends ReadonlyArray>\n> {\n name: string\n interceptors: InterceptorList\n}\n\nexport type ExtractEventMapType<\n InterceptorList extends ReadonlyArray>\n> = InterceptorList extends ReadonlyArray\n ? InterceptorType extends Interceptor\n ? EventMap\n : never\n : never\n\n/**\n * A batch interceptor that exposes a single interface\n * to apply and operate with multiple interceptors at once.\n */\nexport class BatchInterceptor<\n InterceptorList extends ReadonlyArray>,\n Events extends EventMap = ExtractEventMapType\n> extends Interceptor {\n static symbol: symbol\n\n private interceptors: InterceptorList\n\n constructor(options: BatchInterceptorOptions) {\n BatchInterceptor.symbol = Symbol(options.name)\n super(BatchInterceptor.symbol)\n this.interceptors = options.interceptors\n }\n\n protected setup() {\n const logger = this.logger.extend('setup')\n\n logger.info('applying all %d interceptors...', this.interceptors.length)\n\n for (const interceptor of this.interceptors) {\n logger.info('applying \"%s\" interceptor...', interceptor.constructor.name)\n interceptor.apply()\n\n logger.info('adding interceptor dispose subscription')\n this.subscriptions.push(() => interceptor.dispose())\n }\n }\n\n public on>(\n event: EventName,\n listener: Listener\n ): this {\n // Instead of adding a listener to the batch interceptor,\n // propagate the listener to each of the individual interceptors.\n for (const interceptor of this.interceptors) {\n interceptor.on(event, listener)\n }\n\n return this\n }\n\n public once>(\n event: EventName,\n listener: Listener\n ): this {\n for (const interceptor of this.interceptors) {\n interceptor.once(event, listener)\n }\n\n return this\n }\n\n public off>(\n event: EventName,\n listener: Listener\n ): this {\n for (const interceptor of this.interceptors) {\n interceptor.off(event, listener)\n }\n\n return this\n }\n\n public removeAllListeners>(\n event?: EventName | undefined\n ): this {\n for (const interceptors of this.interceptors) {\n interceptors.removeAllListeners(event)\n }\n\n return this\n }\n}\n"],"mappings":";;;;;AAsBO,IAAM,mBAAN,cAGG,YAAoB;AAAA,EAK5B,YAAY,SAAmD;AAC7D,qBAAiB,SAAS,OAAO,QAAQ,IAAI;AAC7C,UAAM,iBAAiB,MAAM;AAC7B,SAAK,eAAe,QAAQ;AAAA,EAC9B;AAAA,EAEU,QAAQ;AAChB,UAAM,SAAS,KAAK,OAAO,OAAO,OAAO;AAEzC,WAAO,KAAK,mCAAmC,KAAK,aAAa,MAAM;AAEvE,eAAW,eAAe,KAAK,cAAc;AAC3C,aAAO,KAAK,gCAAgC,YAAY,YAAY,IAAI;AACxE,kBAAY,MAAM;AAElB,aAAO,KAAK,yCAAyC;AACrD,WAAK,cAAc,KAAK,MAAM,YAAY,QAAQ,CAAC;AAAA,IACrD;AAAA,EACF;AAAA,EAEO,GACL,OACA,UACM;AAGN,eAAW,eAAe,KAAK,cAAc;AAC3C,kBAAY,GAAG,OAAO,QAAQ;AAAA,IAChC;AAEA,WAAO;AAAA,EACT;AAAA,EAEO,KACL,OACA,UACM;AACN,eAAW,eAAe,KAAK,cAAc;AAC3C,kBAAY,KAAK,OAAO,QAAQ;AAAA,IAClC;AAEA,WAAO;AAAA,EACT;AAAA,EAEO,IACL,OACA,UACM;AACN,eAAW,eAAe,KAAK,cAAc;AAC3C,kBAAY,IAAI,OAAO,QAAQ;AAAA,IACjC;AAEA,WAAO;AAAA,EACT;AAAA,EAEO,mBACL,OACM;AACN,eAAW,gBAAgB,KAAK,cAAc;AAC5C,mBAAa,mBAAmB,KAAK;AAAA,IACvC;AAEA,WAAO;AAAA,EACT;AACF;","names":[]} \ No newline at end of file diff --git a/node_modules/@mswjs/interceptors/lib/node/chunk-TX5GBTFY.mjs b/node_modules/@mswjs/interceptors/lib/node/chunk-TX5GBTFY.mjs new file mode 100644 index 0000000000000000000000000000000000000000..f42b2faa86ecb8bf3f85d30e0bbeeb04b5f1b4dc --- /dev/null +++ b/node_modules/@mswjs/interceptors/lib/node/chunk-TX5GBTFY.mjs @@ -0,0 +1,25 @@ +// src/utils/hasConfigurableGlobal.ts +function hasConfigurableGlobal(propertyName) { + const descriptor = Object.getOwnPropertyDescriptor(globalThis, propertyName); + if (typeof descriptor === "undefined") { + return false; + } + if (typeof descriptor.get === "function" && typeof descriptor.get() === "undefined") { + return false; + } + if (typeof descriptor.get === "undefined" && descriptor.value == null) { + return false; + } + if (typeof descriptor.set === "undefined" && !descriptor.configurable) { + console.error( + `[MSW] Failed to apply interceptor: the global \`${propertyName}\` property is non-configurable. This is likely an issue with your environment. If you are using a framework, please open an issue about this in their repository.` + ); + return false; + } + return true; +} + +export { + hasConfigurableGlobal +}; +//# sourceMappingURL=chunk-TX5GBTFY.mjs.map \ No newline at end of file diff --git a/node_modules/@mswjs/interceptors/lib/node/chunk-TX5GBTFY.mjs.map b/node_modules/@mswjs/interceptors/lib/node/chunk-TX5GBTFY.mjs.map new file mode 100644 index 0000000000000000000000000000000000000000..c5a9cb80f9e3490ec747574f677a05f8d48bd34d --- /dev/null +++ b/node_modules/@mswjs/interceptors/lib/node/chunk-TX5GBTFY.mjs.map @@ -0,0 +1 @@ +{"version":3,"sources":["../../src/utils/hasConfigurableGlobal.ts"],"sourcesContent":["/**\n * Returns a boolean indicating whether the given global property\n * is defined and is configurable.\n */\nexport function hasConfigurableGlobal(propertyName: string): boolean {\n const descriptor = Object.getOwnPropertyDescriptor(globalThis, propertyName)\n\n // The property is not set at all.\n if (typeof descriptor === 'undefined') {\n return false\n }\n\n // The property is set to a getter that returns undefined.\n if (\n typeof descriptor.get === 'function' &&\n typeof descriptor.get() === 'undefined'\n ) {\n return false\n }\n\n // The property is set to a value equal to undefined.\n if (typeof descriptor.get === 'undefined' && descriptor.value == null) {\n return false\n }\n\n if (typeof descriptor.set === 'undefined' && !descriptor.configurable) {\n console.error(\n `[MSW] Failed to apply interceptor: the global \\`${propertyName}\\` property is non-configurable. This is likely an issue with your environment. If you are using a framework, please open an issue about this in their repository.`\n )\n return false\n }\n\n return true\n}\n"],"mappings":";AAIO,SAAS,sBAAsB,cAA+B;AACnE,QAAM,aAAa,OAAO,yBAAyB,YAAY,YAAY;AAG3E,MAAI,OAAO,eAAe,aAAa;AACrC,WAAO;AAAA,EACT;AAGA,MACE,OAAO,WAAW,QAAQ,cAC1B,OAAO,WAAW,IAAI,MAAM,aAC5B;AACA,WAAO;AAAA,EACT;AAGA,MAAI,OAAO,WAAW,QAAQ,eAAe,WAAW,SAAS,MAAM;AACrE,WAAO;AAAA,EACT;AAEA,MAAI,OAAO,WAAW,QAAQ,eAAe,CAAC,WAAW,cAAc;AACrE,YAAQ;AAAA,MACN,mDAAmD;AAAA,IACrD;AACA,WAAO;AAAA,EACT;AAEA,SAAO;AACT;","names":[]} \ No newline at end of file diff --git a/node_modules/@mswjs/interceptors/lib/node/chunk-WZTE4PCO.js b/node_modules/@mswjs/interceptors/lib/node/chunk-WZTE4PCO.js new file mode 100644 index 0000000000000000000000000000000000000000..9230ad0c3204cf485f36e0a543fa3f665d51276c --- /dev/null +++ b/node_modules/@mswjs/interceptors/lib/node/chunk-WZTE4PCO.js @@ -0,0 +1,245 @@ +"use strict";Object.defineProperty(exports, "__esModule", {value: true});// src/Interceptor.ts +var _logger = require('@open-draft/logger'); +var _stricteventemitter = require('strict-event-emitter'); +var INTERNAL_REQUEST_ID_HEADER_NAME = "x-interceptors-internal-request-id"; +function getGlobalSymbol(symbol) { + return ( + // @ts-ignore https://github.com/Microsoft/TypeScript/issues/24587 + globalThis[symbol] || void 0 + ); +} +function setGlobalSymbol(symbol, value) { + globalThis[symbol] = value; +} +function deleteGlobalSymbol(symbol) { + delete globalThis[symbol]; +} +var InterceptorReadyState = /* @__PURE__ */ ((InterceptorReadyState2) => { + InterceptorReadyState2["INACTIVE"] = "INACTIVE"; + InterceptorReadyState2["APPLYING"] = "APPLYING"; + InterceptorReadyState2["APPLIED"] = "APPLIED"; + InterceptorReadyState2["DISPOSING"] = "DISPOSING"; + InterceptorReadyState2["DISPOSED"] = "DISPOSED"; + return InterceptorReadyState2; +})(InterceptorReadyState || {}); +var Interceptor = class { + constructor(symbol) { + this.symbol = symbol; + this.readyState = "INACTIVE" /* INACTIVE */; + this.emitter = new (0, _stricteventemitter.Emitter)(); + this.subscriptions = []; + this.logger = new (0, _logger.Logger)(symbol.description); + this.emitter.setMaxListeners(0); + this.logger.info("constructing the interceptor..."); + } + /** + * Determine if this interceptor can be applied + * in the current environment. + */ + checkEnvironment() { + return true; + } + /** + * Apply this interceptor to the current process. + * Returns an already running interceptor instance if it's present. + */ + apply() { + const logger = this.logger.extend("apply"); + logger.info("applying the interceptor..."); + if (this.readyState === "APPLIED" /* APPLIED */) { + logger.info("intercepted already applied!"); + return; + } + const shouldApply = this.checkEnvironment(); + if (!shouldApply) { + logger.info("the interceptor cannot be applied in this environment!"); + return; + } + this.readyState = "APPLYING" /* APPLYING */; + const runningInstance = this.getInstance(); + if (runningInstance) { + logger.info("found a running instance, reusing..."); + this.on = (event, listener) => { + logger.info('proxying the "%s" listener', event); + runningInstance.emitter.addListener(event, listener); + this.subscriptions.push(() => { + runningInstance.emitter.removeListener(event, listener); + logger.info('removed proxied "%s" listener!', event); + }); + return this; + }; + this.readyState = "APPLIED" /* APPLIED */; + return; + } + logger.info("no running instance found, setting up a new instance..."); + this.setup(); + this.setInstance(); + this.readyState = "APPLIED" /* APPLIED */; + } + /** + * Setup the module augments and stubs necessary for this interceptor. + * This method is not run if there's a running interceptor instance + * to prevent instantiating an interceptor multiple times. + */ + setup() { + } + /** + * Listen to the interceptor's public events. + */ + on(event, listener) { + const logger = this.logger.extend("on"); + if (this.readyState === "DISPOSING" /* DISPOSING */ || this.readyState === "DISPOSED" /* DISPOSED */) { + logger.info("cannot listen to events, already disposed!"); + return this; + } + logger.info('adding "%s" event listener:', event, listener); + this.emitter.on(event, listener); + return this; + } + once(event, listener) { + this.emitter.once(event, listener); + return this; + } + off(event, listener) { + this.emitter.off(event, listener); + return this; + } + removeAllListeners(event) { + this.emitter.removeAllListeners(event); + return this; + } + /** + * Disposes of any side-effects this interceptor has introduced. + */ + dispose() { + const logger = this.logger.extend("dispose"); + if (this.readyState === "DISPOSED" /* DISPOSED */) { + logger.info("cannot dispose, already disposed!"); + return; + } + logger.info("disposing the interceptor..."); + this.readyState = "DISPOSING" /* DISPOSING */; + if (!this.getInstance()) { + logger.info("no interceptors running, skipping dispose..."); + return; + } + this.clearInstance(); + logger.info("global symbol deleted:", getGlobalSymbol(this.symbol)); + if (this.subscriptions.length > 0) { + logger.info("disposing of %d subscriptions...", this.subscriptions.length); + for (const dispose of this.subscriptions) { + dispose(); + } + this.subscriptions = []; + logger.info("disposed of all subscriptions!", this.subscriptions.length); + } + this.emitter.removeAllListeners(); + logger.info("destroyed the listener!"); + this.readyState = "DISPOSED" /* DISPOSED */; + } + getInstance() { + var _a; + const instance = getGlobalSymbol(this.symbol); + this.logger.info("retrieved global instance:", (_a = instance == null ? void 0 : instance.constructor) == null ? void 0 : _a.name); + return instance; + } + setInstance() { + setGlobalSymbol(this.symbol, this); + this.logger.info("set global instance!", this.symbol.description); + } + clearInstance() { + deleteGlobalSymbol(this.symbol); + this.logger.info("cleared global instance!", this.symbol.description); + } +}; + +// src/createRequestId.ts +function createRequestId() { + return Math.random().toString(16).slice(2); +} + +// src/utils/fetchUtils.ts +var _FetchResponse = class extends Response { + static isConfigurableStatusCode(status) { + return status >= 200 && status <= 599; + } + static isRedirectResponse(status) { + return _FetchResponse.STATUS_CODES_WITH_REDIRECT.includes(status); + } + /** + * Returns a boolean indicating whether the given response status + * code represents a response that can have a body. + */ + static isResponseWithBody(status) { + return !_FetchResponse.STATUS_CODES_WITHOUT_BODY.includes(status); + } + static setUrl(url, response) { + if (!url) { + return; + } + if (response.url != "") { + return; + } + Object.defineProperty(response, "url", { + value: url, + enumerable: true, + configurable: true, + writable: false + }); + } + /** + * Parses the given raw HTTP headers into a Fetch API `Headers` instance. + */ + static parseRawHeaders(rawHeaders) { + const headers = new Headers(); + for (let line = 0; line < rawHeaders.length; line += 2) { + headers.append(rawHeaders[line], rawHeaders[line + 1]); + } + return headers; + } + constructor(body, init = {}) { + var _a; + const status = (_a = init.status) != null ? _a : 200; + const safeStatus = _FetchResponse.isConfigurableStatusCode(status) ? status : 200; + const finalBody = _FetchResponse.isResponseWithBody(status) ? body : null; + super(finalBody, { + ...init, + status: safeStatus + }); + if (status !== safeStatus) { + const stateSymbol = Object.getOwnPropertySymbols(this).find( + (symbol) => symbol.description === "state" + ); + if (stateSymbol) { + const state = Reflect.get(this, stateSymbol); + Reflect.set(state, "status", status); + } else { + Object.defineProperty(this, "status", { + value: status, + enumerable: true, + configurable: true, + writable: false + }); + } + } + _FetchResponse.setUrl(init.url, this); + } +}; +var FetchResponse = _FetchResponse; +/** + * Response status codes for responses that cannot have body. + * @see https://fetch.spec.whatwg.org/#statuses + */ +FetchResponse.STATUS_CODES_WITHOUT_BODY = [101, 103, 204, 205, 304]; +FetchResponse.STATUS_CODES_WITH_REDIRECT = [301, 302, 303, 307, 308]; + + + + + + + + + +exports.INTERNAL_REQUEST_ID_HEADER_NAME = INTERNAL_REQUEST_ID_HEADER_NAME; exports.getGlobalSymbol = getGlobalSymbol; exports.deleteGlobalSymbol = deleteGlobalSymbol; exports.InterceptorReadyState = InterceptorReadyState; exports.Interceptor = Interceptor; exports.createRequestId = createRequestId; exports.FetchResponse = FetchResponse; +//# sourceMappingURL=chunk-WZTE4PCO.js.map \ No newline at end of file diff --git a/node_modules/@mswjs/interceptors/lib/node/chunk-WZTE4PCO.js.map b/node_modules/@mswjs/interceptors/lib/node/chunk-WZTE4PCO.js.map new file mode 100644 index 0000000000000000000000000000000000000000..f10d0d5c848316000aa2103120d61f6c65fe811f --- /dev/null +++ b/node_modules/@mswjs/interceptors/lib/node/chunk-WZTE4PCO.js.map @@ -0,0 +1 @@ +{"version":3,"sources":["../../src/Interceptor.ts","../../src/createRequestId.ts","../../src/utils/fetchUtils.ts"],"names":["InterceptorReadyState"],"mappings":"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","sourcesContent":["import { Logger } from '@open-draft/logger'\nimport { Emitter, Listener } from 'strict-event-emitter'\n\nexport type InterceptorEventMap = Record\nexport type InterceptorSubscription = () => void\n\n/**\n * Request header name to detect when a single request\n * is being handled by nested interceptors (XHR -> ClientRequest).\n * Obscure by design to prevent collisions with user-defined headers.\n * Ideally, come up with the Interceptor-level mechanism for this.\n * @see https://github.com/mswjs/interceptors/issues/378\n */\nexport const INTERNAL_REQUEST_ID_HEADER_NAME =\n 'x-interceptors-internal-request-id'\n\nexport function getGlobalSymbol(symbol: Symbol): V | undefined {\n return (\n // @ts-ignore https://github.com/Microsoft/TypeScript/issues/24587\n globalThis[symbol] || undefined\n )\n}\n\nfunction setGlobalSymbol(symbol: Symbol, value: any): void {\n // @ts-ignore\n globalThis[symbol] = value\n}\n\nexport function deleteGlobalSymbol(symbol: Symbol): void {\n // @ts-ignore\n delete globalThis[symbol]\n}\n\nexport enum InterceptorReadyState {\n INACTIVE = 'INACTIVE',\n APPLYING = 'APPLYING',\n APPLIED = 'APPLIED',\n DISPOSING = 'DISPOSING',\n DISPOSED = 'DISPOSED',\n}\n\nexport type ExtractEventNames> =\n Events extends Record ? EventName : never\n\nexport class Interceptor {\n protected emitter: Emitter\n protected subscriptions: Array\n protected logger: Logger\n\n public readyState: InterceptorReadyState\n\n constructor(private readonly symbol: symbol) {\n this.readyState = InterceptorReadyState.INACTIVE\n\n this.emitter = new Emitter()\n this.subscriptions = []\n this.logger = new Logger(symbol.description!)\n\n // Do not limit the maximum number of listeners\n // so not to limit the maximum amount of parallel events emitted.\n this.emitter.setMaxListeners(0)\n\n this.logger.info('constructing the interceptor...')\n }\n\n /**\n * Determine if this interceptor can be applied\n * in the current environment.\n */\n protected checkEnvironment(): boolean {\n return true\n }\n\n /**\n * Apply this interceptor to the current process.\n * Returns an already running interceptor instance if it's present.\n */\n public apply(): void {\n const logger = this.logger.extend('apply')\n logger.info('applying the interceptor...')\n\n if (this.readyState === InterceptorReadyState.APPLIED) {\n logger.info('intercepted already applied!')\n return\n }\n\n const shouldApply = this.checkEnvironment()\n\n if (!shouldApply) {\n logger.info('the interceptor cannot be applied in this environment!')\n return\n }\n\n this.readyState = InterceptorReadyState.APPLYING\n\n // Whenever applying a new interceptor, check if it hasn't been applied already.\n // This enables to apply the same interceptor multiple times, for example from a different\n // interceptor, only proxying events but keeping the stubs in a single place.\n const runningInstance = this.getInstance()\n\n if (runningInstance) {\n logger.info('found a running instance, reusing...')\n\n // Proxy any listeners you set on this instance to the running instance.\n this.on = (event, listener) => {\n logger.info('proxying the \"%s\" listener', event)\n\n // Add listeners to the running instance so they appear\n // at the top of the event listeners list and are executed first.\n runningInstance.emitter.addListener(event, listener)\n\n // Ensure that once this interceptor instance is disposed,\n // it removes all listeners it has appended to the running interceptor instance.\n this.subscriptions.push(() => {\n runningInstance.emitter.removeListener(event, listener)\n logger.info('removed proxied \"%s\" listener!', event)\n })\n\n return this\n }\n\n this.readyState = InterceptorReadyState.APPLIED\n\n return\n }\n\n logger.info('no running instance found, setting up a new instance...')\n\n // Setup the interceptor.\n this.setup()\n\n // Store the newly applied interceptor instance globally.\n this.setInstance()\n\n this.readyState = InterceptorReadyState.APPLIED\n }\n\n /**\n * Setup the module augments and stubs necessary for this interceptor.\n * This method is not run if there's a running interceptor instance\n * to prevent instantiating an interceptor multiple times.\n */\n protected setup(): void {}\n\n /**\n * Listen to the interceptor's public events.\n */\n public on>(\n event: EventName,\n listener: Listener\n ): this {\n const logger = this.logger.extend('on')\n\n if (\n this.readyState === InterceptorReadyState.DISPOSING ||\n this.readyState === InterceptorReadyState.DISPOSED\n ) {\n logger.info('cannot listen to events, already disposed!')\n return this\n }\n\n logger.info('adding \"%s\" event listener:', event, listener)\n\n this.emitter.on(event, listener)\n return this\n }\n\n public once>(\n event: EventName,\n listener: Listener\n ): this {\n this.emitter.once(event, listener)\n return this\n }\n\n public off>(\n event: EventName,\n listener: Listener\n ): this {\n this.emitter.off(event, listener)\n return this\n }\n\n public removeAllListeners>(\n event?: EventName\n ): this {\n this.emitter.removeAllListeners(event)\n return this\n }\n\n /**\n * Disposes of any side-effects this interceptor has introduced.\n */\n public dispose(): void {\n const logger = this.logger.extend('dispose')\n\n if (this.readyState === InterceptorReadyState.DISPOSED) {\n logger.info('cannot dispose, already disposed!')\n return\n }\n\n logger.info('disposing the interceptor...')\n this.readyState = InterceptorReadyState.DISPOSING\n\n if (!this.getInstance()) {\n logger.info('no interceptors running, skipping dispose...')\n return\n }\n\n // Delete the global symbol as soon as possible,\n // indicating that the interceptor is no longer running.\n this.clearInstance()\n\n logger.info('global symbol deleted:', getGlobalSymbol(this.symbol))\n\n if (this.subscriptions.length > 0) {\n logger.info('disposing of %d subscriptions...', this.subscriptions.length)\n\n for (const dispose of this.subscriptions) {\n dispose()\n }\n\n this.subscriptions = []\n\n logger.info('disposed of all subscriptions!', this.subscriptions.length)\n }\n\n this.emitter.removeAllListeners()\n logger.info('destroyed the listener!')\n\n this.readyState = InterceptorReadyState.DISPOSED\n }\n\n private getInstance(): this | undefined {\n const instance = getGlobalSymbol(this.symbol)\n this.logger.info('retrieved global instance:', instance?.constructor?.name)\n return instance\n }\n\n private setInstance(): void {\n setGlobalSymbol(this.symbol, this)\n this.logger.info('set global instance!', this.symbol.description)\n }\n\n private clearInstance(): void {\n deleteGlobalSymbol(this.symbol)\n this.logger.info('cleared global instance!', this.symbol.description)\n }\n}\n","/**\n * Generate a random ID string to represent a request.\n * @example\n * createRequestId()\n * // \"f774b6c9c600f\"\n */\nexport function createRequestId(): string {\n return Math.random().toString(16).slice(2)\n}\n","export interface FetchResponseInit extends ResponseInit {\n url?: string\n}\n\nexport class FetchResponse extends Response {\n /**\n * Response status codes for responses that cannot have body.\n * @see https://fetch.spec.whatwg.org/#statuses\n */\n static readonly STATUS_CODES_WITHOUT_BODY = [101, 103, 204, 205, 304]\n\n static readonly STATUS_CODES_WITH_REDIRECT = [301, 302, 303, 307, 308]\n\n static isConfigurableStatusCode(status: number): boolean {\n return status >= 200 && status <= 599\n }\n\n static isRedirectResponse(status: number): boolean {\n return FetchResponse.STATUS_CODES_WITH_REDIRECT.includes(status)\n }\n\n /**\n * Returns a boolean indicating whether the given response status\n * code represents a response that can have a body.\n */\n static isResponseWithBody(status: number): boolean {\n return !FetchResponse.STATUS_CODES_WITHOUT_BODY.includes(status)\n }\n\n static setUrl(url: string | undefined, response: Response): void {\n if (!url) {\n return\n }\n\n if (response.url != '') {\n return\n }\n\n Object.defineProperty(response, 'url', {\n value: url,\n enumerable: true,\n configurable: true,\n writable: false,\n })\n }\n\n /**\n * Parses the given raw HTTP headers into a Fetch API `Headers` instance.\n */\n static parseRawHeaders(rawHeaders: Array): Headers {\n const headers = new Headers()\n for (let line = 0; line < rawHeaders.length; line += 2) {\n headers.append(rawHeaders[line], rawHeaders[line + 1])\n }\n return headers\n }\n\n constructor(body?: BodyInit | null, init: FetchResponseInit = {}) {\n const status = init.status ?? 200\n const safeStatus = FetchResponse.isConfigurableStatusCode(status)\n ? status\n : 200\n const finalBody = FetchResponse.isResponseWithBody(status) ? body : null\n\n super(finalBody, {\n ...init,\n status: safeStatus,\n })\n\n if (status !== safeStatus) {\n /**\n * @note Undici keeps an internal \"Symbol(state)\" that holds\n * the actual value of response status. Update that in Node.js.\n */\n const stateSymbol = Object.getOwnPropertySymbols(this).find(\n (symbol) => symbol.description === 'state'\n )\n if (stateSymbol) {\n const state = Reflect.get(this, stateSymbol) as object\n Reflect.set(state, 'status', status)\n } else {\n Object.defineProperty(this, 'status', {\n value: status,\n enumerable: true,\n configurable: true,\n writable: false,\n })\n }\n }\n\n FetchResponse.setUrl(init.url, this)\n }\n}\n"]} \ No newline at end of file diff --git a/node_modules/@mswjs/interceptors/lib/node/chunk-YBN5MFAP.js b/node_modules/@mswjs/interceptors/lib/node/chunk-YBN5MFAP.js new file mode 100644 index 0000000000000000000000000000000000000000..b44060531b135b926c845df791c3e39197be2973 --- /dev/null +++ b/node_modules/@mswjs/interceptors/lib/node/chunk-YBN5MFAP.js @@ -0,0 +1,51 @@ +"use strict";Object.defineProperty(exports, "__esModule", {value: true}); + +var _chunkWZTE4PCOjs = require('./chunk-WZTE4PCO.js'); + +// src/BatchInterceptor.ts +var BatchInterceptor = class extends _chunkWZTE4PCOjs.Interceptor { + constructor(options) { + BatchInterceptor.symbol = Symbol(options.name); + super(BatchInterceptor.symbol); + this.interceptors = options.interceptors; + } + setup() { + const logger = this.logger.extend("setup"); + logger.info("applying all %d interceptors...", this.interceptors.length); + for (const interceptor of this.interceptors) { + logger.info('applying "%s" interceptor...', interceptor.constructor.name); + interceptor.apply(); + logger.info("adding interceptor dispose subscription"); + this.subscriptions.push(() => interceptor.dispose()); + } + } + on(event, listener) { + for (const interceptor of this.interceptors) { + interceptor.on(event, listener); + } + return this; + } + once(event, listener) { + for (const interceptor of this.interceptors) { + interceptor.once(event, listener); + } + return this; + } + off(event, listener) { + for (const interceptor of this.interceptors) { + interceptor.off(event, listener); + } + return this; + } + removeAllListeners(event) { + for (const interceptors of this.interceptors) { + interceptors.removeAllListeners(event); + } + return this; + } +}; + + + +exports.BatchInterceptor = BatchInterceptor; +//# sourceMappingURL=chunk-YBN5MFAP.js.map \ No newline at end of file diff --git a/node_modules/@mswjs/interceptors/lib/node/chunk-YBN5MFAP.js.map b/node_modules/@mswjs/interceptors/lib/node/chunk-YBN5MFAP.js.map new file mode 100644 index 0000000000000000000000000000000000000000..968f3b814bfe2243dd7081d7252f51194244f9cd --- /dev/null +++ b/node_modules/@mswjs/interceptors/lib/node/chunk-YBN5MFAP.js.map @@ -0,0 +1 @@ +{"version":3,"sources":["../../src/BatchInterceptor.ts"],"names":[],"mappings":";;;;;AAsBO,IAAM,mBAAN,cAGG,YAAoB;AAAA,EAK5B,YAAY,SAAmD;AAC7D,qBAAiB,SAAS,OAAO,QAAQ,IAAI;AAC7C,UAAM,iBAAiB,MAAM;AAC7B,SAAK,eAAe,QAAQ;AAAA,EAC9B;AAAA,EAEU,QAAQ;AAChB,UAAM,SAAS,KAAK,OAAO,OAAO,OAAO;AAEzC,WAAO,KAAK,mCAAmC,KAAK,aAAa,MAAM;AAEvE,eAAW,eAAe,KAAK,cAAc;AAC3C,aAAO,KAAK,gCAAgC,YAAY,YAAY,IAAI;AACxE,kBAAY,MAAM;AAElB,aAAO,KAAK,yCAAyC;AACrD,WAAK,cAAc,KAAK,MAAM,YAAY,QAAQ,CAAC;AAAA,IACrD;AAAA,EACF;AAAA,EAEO,GACL,OACA,UACM;AAGN,eAAW,eAAe,KAAK,cAAc;AAC3C,kBAAY,GAAG,OAAO,QAAQ;AAAA,IAChC;AAEA,WAAO;AAAA,EACT;AAAA,EAEO,KACL,OACA,UACM;AACN,eAAW,eAAe,KAAK,cAAc;AAC3C,kBAAY,KAAK,OAAO,QAAQ;AAAA,IAClC;AAEA,WAAO;AAAA,EACT;AAAA,EAEO,IACL,OACA,UACM;AACN,eAAW,eAAe,KAAK,cAAc;AAC3C,kBAAY,IAAI,OAAO,QAAQ;AAAA,IACjC;AAEA,WAAO;AAAA,EACT;AAAA,EAEO,mBACL,OACM;AACN,eAAW,gBAAgB,KAAK,cAAc;AAC5C,mBAAa,mBAAmB,KAAK;AAAA,IACvC;AAEA,WAAO;AAAA,EACT;AACF","sourcesContent":["import { EventMap, Listener } from 'strict-event-emitter'\nimport { Interceptor, ExtractEventNames } from './Interceptor'\n\nexport interface BatchInterceptorOptions<\n InterceptorList extends ReadonlyArray>\n> {\n name: string\n interceptors: InterceptorList\n}\n\nexport type ExtractEventMapType<\n InterceptorList extends ReadonlyArray>\n> = InterceptorList extends ReadonlyArray\n ? InterceptorType extends Interceptor\n ? EventMap\n : never\n : never\n\n/**\n * A batch interceptor that exposes a single interface\n * to apply and operate with multiple interceptors at once.\n */\nexport class BatchInterceptor<\n InterceptorList extends ReadonlyArray>,\n Events extends EventMap = ExtractEventMapType\n> extends Interceptor {\n static symbol: symbol\n\n private interceptors: InterceptorList\n\n constructor(options: BatchInterceptorOptions) {\n BatchInterceptor.symbol = Symbol(options.name)\n super(BatchInterceptor.symbol)\n this.interceptors = options.interceptors\n }\n\n protected setup() {\n const logger = this.logger.extend('setup')\n\n logger.info('applying all %d interceptors...', this.interceptors.length)\n\n for (const interceptor of this.interceptors) {\n logger.info('applying \"%s\" interceptor...', interceptor.constructor.name)\n interceptor.apply()\n\n logger.info('adding interceptor dispose subscription')\n this.subscriptions.push(() => interceptor.dispose())\n }\n }\n\n public on>(\n event: EventName,\n listener: Listener\n ): this {\n // Instead of adding a listener to the batch interceptor,\n // propagate the listener to each of the individual interceptors.\n for (const interceptor of this.interceptors) {\n interceptor.on(event, listener)\n }\n\n return this\n }\n\n public once>(\n event: EventName,\n listener: Listener\n ): this {\n for (const interceptor of this.interceptors) {\n interceptor.once(event, listener)\n }\n\n return this\n }\n\n public off>(\n event: EventName,\n listener: Listener\n ): this {\n for (const interceptor of this.interceptors) {\n interceptor.off(event, listener)\n }\n\n return this\n }\n\n public removeAllListeners>(\n event?: EventName | undefined\n ): this {\n for (const interceptors of this.interceptors) {\n interceptors.removeAllListeners(event)\n }\n\n return this\n }\n}\n"]} \ No newline at end of file diff --git a/node_modules/@mswjs/interceptors/lib/node/index.d.ts b/node_modules/@mswjs/interceptors/lib/node/index.d.ts new file mode 100644 index 0000000000000000000000000000000000000000..6a78c7d9c2679a79ee4fa44d9b6e487ff529e5a2 --- /dev/null +++ b/node_modules/@mswjs/interceptors/lib/node/index.d.ts @@ -0,0 +1,48 @@ +export { E as ExtractEventNames, H as HttpRequestEventMap, d as INTERNAL_REQUEST_ID_HEADER_NAME, I as IS_PATCHED_MODULE, h as Interceptor, b as InterceptorEventMap, f as InterceptorReadyState, c as InterceptorSubscription, R as RequestController, a as RequestCredentials, e as deleteGlobalSymbol, g as getGlobalSymbol } from './Interceptor-436630be.js'; +export { a as BatchInterceptor, B as BatchInterceptorOptions, E as ExtractEventMapType } from './BatchInterceptor-67bf41ba.js'; +import '@open-draft/deferred-promise'; +import '@open-draft/logger'; +import 'strict-event-emitter'; + +/** + * Generate a random ID string to represent a request. + * @example + * createRequestId() + * // "f774b6c9c600f" + */ +declare function createRequestId(): string; + +/** + * Removes query parameters and hashes from a given URL. + */ +declare function getCleanUrl(url: URL, isAbsolute?: boolean): string; + +declare function encodeBuffer(text: string): Uint8Array; +declare function decodeBuffer(buffer: ArrayBuffer, encoding?: string): string; + +interface FetchResponseInit extends ResponseInit { + url?: string; +} +declare class FetchResponse extends Response { + /** + * Response status codes for responses that cannot have body. + * @see https://fetch.spec.whatwg.org/#statuses + */ + static readonly STATUS_CODES_WITHOUT_BODY: number[]; + static readonly STATUS_CODES_WITH_REDIRECT: number[]; + static isConfigurableStatusCode(status: number): boolean; + static isRedirectResponse(status: number): boolean; + /** + * Returns a boolean indicating whether the given response status + * code represents a response that can have a body. + */ + static isResponseWithBody(status: number): boolean; + static setUrl(url: string | undefined, response: Response): void; + /** + * Parses the given raw HTTP headers into a Fetch API `Headers` instance. + */ + static parseRawHeaders(rawHeaders: Array): Headers; + constructor(body?: BodyInit | null, init?: FetchResponseInit); +} + +export { FetchResponse, createRequestId, decodeBuffer, encodeBuffer, getCleanUrl }; diff --git a/node_modules/@mswjs/interceptors/lib/node/index.js b/node_modules/@mswjs/interceptors/lib/node/index.js new file mode 100644 index 0000000000000000000000000000000000000000..caec122add23068b0d0c850ceb3c19c28f4a2647 --- /dev/null +++ b/node_modules/@mswjs/interceptors/lib/node/index.js @@ -0,0 +1,39 @@ +"use strict";Object.defineProperty(exports, "__esModule", {value: true}); + +var _chunkYBN5MFAPjs = require('./chunk-YBN5MFAP.js'); + + + +var _chunkLK6DILFKjs = require('./chunk-LK6DILFK.js'); + + +var _chunk73NOP3T5js = require('./chunk-73NOP3T5.js'); + + + + + + + + +var _chunkWZTE4PCOjs = require('./chunk-WZTE4PCO.js'); + +// src/utils/getCleanUrl.ts +function getCleanUrl(url, isAbsolute = true) { + return [isAbsolute && url.origin, url.pathname].filter(Boolean).join(""); +} + + + + + + + + + + + + + +exports.BatchInterceptor = _chunkYBN5MFAPjs.BatchInterceptor; exports.FetchResponse = _chunkWZTE4PCOjs.FetchResponse; exports.INTERNAL_REQUEST_ID_HEADER_NAME = _chunkWZTE4PCOjs.INTERNAL_REQUEST_ID_HEADER_NAME; exports.IS_PATCHED_MODULE = _chunk73NOP3T5js.IS_PATCHED_MODULE; exports.Interceptor = _chunkWZTE4PCOjs.Interceptor; exports.InterceptorReadyState = _chunkWZTE4PCOjs.InterceptorReadyState; exports.createRequestId = _chunkWZTE4PCOjs.createRequestId; exports.decodeBuffer = _chunkLK6DILFKjs.decodeBuffer; exports.deleteGlobalSymbol = _chunkWZTE4PCOjs.deleteGlobalSymbol; exports.encodeBuffer = _chunkLK6DILFKjs.encodeBuffer; exports.getCleanUrl = getCleanUrl; exports.getGlobalSymbol = _chunkWZTE4PCOjs.getGlobalSymbol; +//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/node_modules/@mswjs/interceptors/lib/node/index.js.map b/node_modules/@mswjs/interceptors/lib/node/index.js.map new file mode 100644 index 0000000000000000000000000000000000000000..ee90ca4d4e56dbd08ee1f9a7fdc299cdc6c1aa51 --- /dev/null +++ b/node_modules/@mswjs/interceptors/lib/node/index.js.map @@ -0,0 +1 @@ +{"version":3,"sources":["../../src/utils/getCleanUrl.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;AAGO,SAAS,YAAY,KAAU,aAAsB,MAAc;AACxE,SAAO,CAAC,cAAc,IAAI,QAAQ,IAAI,QAAQ,EAAE,OAAO,OAAO,EAAE,KAAK,EAAE;AACzE","sourcesContent":["/**\n * Removes query parameters and hashes from a given URL.\n */\nexport function getCleanUrl(url: URL, isAbsolute: boolean = true): string {\n return [isAbsolute && url.origin, url.pathname].filter(Boolean).join('')\n}\n"]} \ No newline at end of file diff --git a/node_modules/@mswjs/interceptors/lib/node/index.mjs b/node_modules/@mswjs/interceptors/lib/node/index.mjs new file mode 100644 index 0000000000000000000000000000000000000000..705d15097507f0c8134f8161965f10cb4be2a4c4 --- /dev/null +++ b/node_modules/@mswjs/interceptors/lib/node/index.mjs @@ -0,0 +1,39 @@ +import { + BatchInterceptor +} from "./chunk-PJA4E426.mjs"; +import { + decodeBuffer, + encodeBuffer +} from "./chunk-6HYIRFX2.mjs"; +import { + IS_PATCHED_MODULE +} from "./chunk-6YM4PLBI.mjs"; +import { + FetchResponse, + INTERNAL_REQUEST_ID_HEADER_NAME, + Interceptor, + InterceptorReadyState, + createRequestId, + deleteGlobalSymbol, + getGlobalSymbol +} from "./chunk-I7HQIBT7.mjs"; + +// src/utils/getCleanUrl.ts +function getCleanUrl(url, isAbsolute = true) { + return [isAbsolute && url.origin, url.pathname].filter(Boolean).join(""); +} +export { + BatchInterceptor, + FetchResponse, + INTERNAL_REQUEST_ID_HEADER_NAME, + IS_PATCHED_MODULE, + Interceptor, + InterceptorReadyState, + createRequestId, + decodeBuffer, + deleteGlobalSymbol, + encodeBuffer, + getCleanUrl, + getGlobalSymbol +}; +//# sourceMappingURL=index.mjs.map \ No newline at end of file diff --git a/node_modules/@mswjs/interceptors/lib/node/index.mjs.map b/node_modules/@mswjs/interceptors/lib/node/index.mjs.map new file mode 100644 index 0000000000000000000000000000000000000000..0c277e56ed286846b2f219e9f452255167395135 --- /dev/null +++ b/node_modules/@mswjs/interceptors/lib/node/index.mjs.map @@ -0,0 +1 @@ +{"version":3,"sources":["../../src/utils/getCleanUrl.ts"],"sourcesContent":["/**\n * Removes query parameters and hashes from a given URL.\n */\nexport function getCleanUrl(url: URL, isAbsolute: boolean = true): string {\n return [isAbsolute && url.origin, url.pathname].filter(Boolean).join('')\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;AAGO,SAAS,YAAY,KAAU,aAAsB,MAAc;AACxE,SAAO,CAAC,cAAc,IAAI,QAAQ,IAAI,QAAQ,EAAE,OAAO,OAAO,EAAE,KAAK,EAAE;AACzE;","names":[]} \ No newline at end of file diff --git a/node_modules/@mswjs/interceptors/lib/node/interceptors/ClientRequest/index.d.ts b/node_modules/@mswjs/interceptors/lib/node/interceptors/ClientRequest/index.d.ts new file mode 100644 index 0000000000000000000000000000000000000000..595d475b3da7caeada0d3eee4e41c8e7e7226e4e --- /dev/null +++ b/node_modules/@mswjs/interceptors/lib/node/interceptors/ClientRequest/index.d.ts @@ -0,0 +1,93 @@ +import { h as Interceptor, H as HttpRequestEventMap } from '../../Interceptor-436630be.js'; +import net from 'node:net'; +import '@open-draft/deferred-promise'; +import '@open-draft/logger'; +import 'strict-event-emitter'; + +type WriteCallback = (error?: Error | null) => void; + +interface MockSocketOptions { + write: (chunk: Buffer | string, encoding: BufferEncoding | undefined, callback?: WriteCallback) => void; + read: (chunk: Buffer, encoding: BufferEncoding | undefined) => void; +} +declare class MockSocket extends net.Socket { + protected readonly options: MockSocketOptions; + connecting: boolean; + constructor(options: MockSocketOptions); + connect(): this; + write(...args: Array): boolean; + end(...args: Array): this; + push(chunk: any, encoding?: BufferEncoding): boolean; +} + +type HttpConnectionOptions = any; +type MockHttpSocketRequestCallback = (args: { + requestId: string; + request: Request; + socket: MockHttpSocket; +}) => void; +type MockHttpSocketResponseCallback = (args: { + requestId: string; + request: Request; + response: Response; + isMockedResponse: boolean; + socket: MockHttpSocket; +}) => Promise; +interface MockHttpSocketOptions { + connectionOptions: HttpConnectionOptions; + createConnection: () => net.Socket; + onRequest: MockHttpSocketRequestCallback; + onResponse: MockHttpSocketResponseCallback; +} +declare class MockHttpSocket extends MockSocket { + private connectionOptions; + private createConnection; + private baseUrl; + private onRequest; + private onResponse; + private responseListenersPromise?; + private writeBuffer; + private request?; + private requestParser; + private requestStream?; + private shouldKeepAlive?; + private socketState; + private responseParser; + private responseStream?; + private originalSocket?; + constructor(options: MockHttpSocketOptions); + emit(event: string | symbol, ...args: any[]): boolean; + destroy(error?: Error | undefined): this; + /** + * Establish this Socket connection as-is and pipe + * its data/events through this Socket. + */ + passthrough(): void; + /** + * Convert the given Fetch API `Response` instance to an + * HTTP message and push it to the socket. + */ + respondWith(response: Response): Promise; + /** + * Close this socket connection with the given error. + */ + errorWith(error?: Error): void; + private mockConnect; + private flushWriteBuffer; + private onRequestStart; + private onRequestBody; + private onRequestEnd; + private onResponseStart; + private onResponseBody; + private onResponseEnd; +} + +declare class ClientRequestInterceptor extends Interceptor { + static symbol: symbol; + constructor(); + protected setup(): void; + private onRequest; + onResponse: MockHttpSocketResponseCallback; +} + +export { ClientRequestInterceptor }; diff --git a/node_modules/@mswjs/interceptors/lib/node/interceptors/ClientRequest/index.js b/node_modules/@mswjs/interceptors/lib/node/interceptors/ClientRequest/index.js new file mode 100644 index 0000000000000000000000000000000000000000..4f7cf29ad1c4294da7129124ae57dae8a6d57707 --- /dev/null +++ b/node_modules/@mswjs/interceptors/lib/node/interceptors/ClientRequest/index.js @@ -0,0 +1,9 @@ +"use strict";Object.defineProperty(exports, "__esModule", {value: true}); + +var _chunk3HCE66HZjs = require('../../chunk-3HCE66HZ.js'); +require('../../chunk-6L3PFBGT.js'); +require('../../chunk-WZTE4PCO.js'); + + +exports.ClientRequestInterceptor = _chunk3HCE66HZjs.ClientRequestInterceptor; +//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/node_modules/@mswjs/interceptors/lib/node/interceptors/ClientRequest/index.js.map b/node_modules/@mswjs/interceptors/lib/node/interceptors/ClientRequest/index.js.map new file mode 100644 index 0000000000000000000000000000000000000000..a464c6732ec9fa9ef5cf78917d42f90f2200eb58 --- /dev/null +++ b/node_modules/@mswjs/interceptors/lib/node/interceptors/ClientRequest/index.js.map @@ -0,0 +1 @@ +{"version":3,"sources":[],"names":[],"mappings":""} \ No newline at end of file diff --git a/node_modules/@mswjs/interceptors/lib/node/interceptors/ClientRequest/index.mjs b/node_modules/@mswjs/interceptors/lib/node/interceptors/ClientRequest/index.mjs new file mode 100644 index 0000000000000000000000000000000000000000..4160645edf83fd304f47dd2cce33e424c457dc23 --- /dev/null +++ b/node_modules/@mswjs/interceptors/lib/node/interceptors/ClientRequest/index.mjs @@ -0,0 +1,9 @@ +import { + ClientRequestInterceptor +} from "../../chunk-FWJSC2QD.mjs"; +import "../../chunk-5KMS5CTP.mjs"; +import "../../chunk-I7HQIBT7.mjs"; +export { + ClientRequestInterceptor +}; +//# sourceMappingURL=index.mjs.map \ No newline at end of file diff --git a/node_modules/@mswjs/interceptors/lib/node/interceptors/ClientRequest/index.mjs.map b/node_modules/@mswjs/interceptors/lib/node/interceptors/ClientRequest/index.mjs.map new file mode 100644 index 0000000000000000000000000000000000000000..84c51b288c478ac0d18748007ccfb8cddc797f3a --- /dev/null +++ b/node_modules/@mswjs/interceptors/lib/node/interceptors/ClientRequest/index.mjs.map @@ -0,0 +1 @@ +{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]} \ No newline at end of file diff --git a/node_modules/@mswjs/interceptors/lib/node/interceptors/XMLHttpRequest/index.d.ts b/node_modules/@mswjs/interceptors/lib/node/interceptors/XMLHttpRequest/index.d.ts new file mode 100644 index 0000000000000000000000000000000000000000..50659334ff9013f077909e0dff336a650b6457c4 --- /dev/null +++ b/node_modules/@mswjs/interceptors/lib/node/interceptors/XMLHttpRequest/index.d.ts @@ -0,0 +1,14 @@ +import { Emitter } from 'strict-event-emitter'; +import { H as HttpRequestEventMap, h as Interceptor } from '../../Interceptor-436630be.js'; +import '@open-draft/deferred-promise'; +import '@open-draft/logger'; + +type XMLHttpRequestEmitter = Emitter; +declare class XMLHttpRequestInterceptor extends Interceptor { + static interceptorSymbol: symbol; + constructor(); + protected checkEnvironment(): boolean; + protected setup(): void; +} + +export { XMLHttpRequestEmitter, XMLHttpRequestInterceptor }; diff --git a/node_modules/@mswjs/interceptors/lib/node/interceptors/XMLHttpRequest/index.js b/node_modules/@mswjs/interceptors/lib/node/interceptors/XMLHttpRequest/index.js new file mode 100644 index 0000000000000000000000000000000000000000..5a8eb226c0720f897a2d35301e381176b9a7736f --- /dev/null +++ b/node_modules/@mswjs/interceptors/lib/node/interceptors/XMLHttpRequest/index.js @@ -0,0 +1,12 @@ +"use strict";Object.defineProperty(exports, "__esModule", {value: true}); + +var _chunkLCA4FKWYjs = require('../../chunk-LCA4FKWY.js'); +require('../../chunk-LK6DILFK.js'); +require('../../chunk-PFGO5BSM.js'); +require('../../chunk-73NOP3T5.js'); +require('../../chunk-6L3PFBGT.js'); +require('../../chunk-WZTE4PCO.js'); + + +exports.XMLHttpRequestInterceptor = _chunkLCA4FKWYjs.XMLHttpRequestInterceptor; +//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/node_modules/@mswjs/interceptors/lib/node/interceptors/XMLHttpRequest/index.js.map b/node_modules/@mswjs/interceptors/lib/node/interceptors/XMLHttpRequest/index.js.map new file mode 100644 index 0000000000000000000000000000000000000000..a464c6732ec9fa9ef5cf78917d42f90f2200eb58 --- /dev/null +++ b/node_modules/@mswjs/interceptors/lib/node/interceptors/XMLHttpRequest/index.js.map @@ -0,0 +1 @@ +{"version":3,"sources":[],"names":[],"mappings":""} \ No newline at end of file diff --git a/node_modules/@mswjs/interceptors/lib/node/interceptors/XMLHttpRequest/index.mjs b/node_modules/@mswjs/interceptors/lib/node/interceptors/XMLHttpRequest/index.mjs new file mode 100644 index 0000000000000000000000000000000000000000..be610a7f98c99a56f07392063ce09826434a0c20 --- /dev/null +++ b/node_modules/@mswjs/interceptors/lib/node/interceptors/XMLHttpRequest/index.mjs @@ -0,0 +1,12 @@ +import { + XMLHttpRequestInterceptor +} from "../../chunk-OMWE7UVM.mjs"; +import "../../chunk-6HYIRFX2.mjs"; +import "../../chunk-TX5GBTFY.mjs"; +import "../../chunk-6YM4PLBI.mjs"; +import "../../chunk-5KMS5CTP.mjs"; +import "../../chunk-I7HQIBT7.mjs"; +export { + XMLHttpRequestInterceptor +}; +//# sourceMappingURL=index.mjs.map \ No newline at end of file diff --git a/node_modules/@mswjs/interceptors/lib/node/interceptors/XMLHttpRequest/index.mjs.map b/node_modules/@mswjs/interceptors/lib/node/interceptors/XMLHttpRequest/index.mjs.map new file mode 100644 index 0000000000000000000000000000000000000000..84c51b288c478ac0d18748007ccfb8cddc797f3a --- /dev/null +++ b/node_modules/@mswjs/interceptors/lib/node/interceptors/XMLHttpRequest/index.mjs.map @@ -0,0 +1 @@ +{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]} \ No newline at end of file diff --git a/node_modules/@mswjs/interceptors/lib/node/interceptors/fetch/index.d.ts b/node_modules/@mswjs/interceptors/lib/node/interceptors/fetch/index.d.ts new file mode 100644 index 0000000000000000000000000000000000000000..5e40ca5a2b191a956d40feee24402bd480c91660 --- /dev/null +++ b/node_modules/@mswjs/interceptors/lib/node/interceptors/fetch/index.d.ts @@ -0,0 +1,13 @@ +import { h as Interceptor, H as HttpRequestEventMap } from '../../Interceptor-436630be.js'; +import '@open-draft/deferred-promise'; +import '@open-draft/logger'; +import 'strict-event-emitter'; + +declare class FetchInterceptor extends Interceptor { + static symbol: symbol; + constructor(); + protected checkEnvironment(): boolean; + protected setup(): Promise; +} + +export { FetchInterceptor }; diff --git a/node_modules/@mswjs/interceptors/lib/node/interceptors/fetch/index.js b/node_modules/@mswjs/interceptors/lib/node/interceptors/fetch/index.js new file mode 100644 index 0000000000000000000000000000000000000000..bcf23a0dedbc79fa74b6e6bcf2eae3a0fd3d5052 --- /dev/null +++ b/node_modules/@mswjs/interceptors/lib/node/interceptors/fetch/index.js @@ -0,0 +1,11 @@ +"use strict";Object.defineProperty(exports, "__esModule", {value: true}); + +var _chunkLEA3MUU3js = require('../../chunk-LEA3MUU3.js'); +require('../../chunk-PFGO5BSM.js'); +require('../../chunk-73NOP3T5.js'); +require('../../chunk-6L3PFBGT.js'); +require('../../chunk-WZTE4PCO.js'); + + +exports.FetchInterceptor = _chunkLEA3MUU3js.FetchInterceptor; +//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/node_modules/@mswjs/interceptors/lib/node/interceptors/fetch/index.js.map b/node_modules/@mswjs/interceptors/lib/node/interceptors/fetch/index.js.map new file mode 100644 index 0000000000000000000000000000000000000000..a464c6732ec9fa9ef5cf78917d42f90f2200eb58 --- /dev/null +++ b/node_modules/@mswjs/interceptors/lib/node/interceptors/fetch/index.js.map @@ -0,0 +1 @@ +{"version":3,"sources":[],"names":[],"mappings":""} \ No newline at end of file diff --git a/node_modules/@mswjs/interceptors/lib/node/interceptors/fetch/index.mjs b/node_modules/@mswjs/interceptors/lib/node/interceptors/fetch/index.mjs new file mode 100644 index 0000000000000000000000000000000000000000..033ada34b5cbbec1b5040dfaa9c022b856944f68 --- /dev/null +++ b/node_modules/@mswjs/interceptors/lib/node/interceptors/fetch/index.mjs @@ -0,0 +1,11 @@ +import { + FetchInterceptor +} from "../../chunk-CTGTMEFD.mjs"; +import "../../chunk-TX5GBTFY.mjs"; +import "../../chunk-6YM4PLBI.mjs"; +import "../../chunk-5KMS5CTP.mjs"; +import "../../chunk-I7HQIBT7.mjs"; +export { + FetchInterceptor +}; +//# sourceMappingURL=index.mjs.map \ No newline at end of file diff --git a/node_modules/@mswjs/interceptors/lib/node/interceptors/fetch/index.mjs.map b/node_modules/@mswjs/interceptors/lib/node/interceptors/fetch/index.mjs.map new file mode 100644 index 0000000000000000000000000000000000000000..84c51b288c478ac0d18748007ccfb8cddc797f3a --- /dev/null +++ b/node_modules/@mswjs/interceptors/lib/node/interceptors/fetch/index.mjs.map @@ -0,0 +1 @@ +{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]} \ No newline at end of file diff --git a/node_modules/@mswjs/interceptors/lib/node/presets/node.d.ts b/node_modules/@mswjs/interceptors/lib/node/presets/node.d.ts new file mode 100644 index 0000000000000000000000000000000000000000..22cf47470ba064b29e74855c6dd747de55b2aa4b --- /dev/null +++ b/node_modules/@mswjs/interceptors/lib/node/presets/node.d.ts @@ -0,0 +1,16 @@ +import { ClientRequestInterceptor } from '../interceptors/ClientRequest/index.js'; +import { XMLHttpRequestInterceptor } from '../interceptors/XMLHttpRequest/index.js'; +import { FetchInterceptor } from '../interceptors/fetch/index.js'; +import '../Interceptor-436630be.js'; +import '@open-draft/deferred-promise'; +import '@open-draft/logger'; +import 'strict-event-emitter'; +import 'node:net'; + +/** + * The default preset provisions the interception of requests + * regardless of their type (http/https/XMLHttpRequest). + */ +declare const _default: readonly [ClientRequestInterceptor, XMLHttpRequestInterceptor, FetchInterceptor]; + +export { _default as default }; diff --git a/node_modules/@mswjs/interceptors/lib/node/presets/node.js b/node_modules/@mswjs/interceptors/lib/node/presets/node.js new file mode 100644 index 0000000000000000000000000000000000000000..d2fd7d29699d54a9121d498d3a640bb92ac87a96 --- /dev/null +++ b/node_modules/@mswjs/interceptors/lib/node/presets/node.js @@ -0,0 +1,25 @@ +"use strict";Object.defineProperty(exports, "__esModule", {value: true}); + +var _chunk3HCE66HZjs = require('../chunk-3HCE66HZ.js'); + + +var _chunkLCA4FKWYjs = require('../chunk-LCA4FKWY.js'); +require('../chunk-LK6DILFK.js'); + + +var _chunkLEA3MUU3js = require('../chunk-LEA3MUU3.js'); +require('../chunk-PFGO5BSM.js'); +require('../chunk-73NOP3T5.js'); +require('../chunk-6L3PFBGT.js'); +require('../chunk-WZTE4PCO.js'); + +// src/presets/node.ts +var node_default = [ + new (0, _chunk3HCE66HZjs.ClientRequestInterceptor)(), + new (0, _chunkLCA4FKWYjs.XMLHttpRequestInterceptor)(), + new (0, _chunkLEA3MUU3js.FetchInterceptor)() +]; + + +exports.default = node_default; +//# sourceMappingURL=node.js.map \ No newline at end of file diff --git a/node_modules/@mswjs/interceptors/lib/node/presets/node.js.map b/node_modules/@mswjs/interceptors/lib/node/presets/node.js.map new file mode 100644 index 0000000000000000000000000000000000000000..a1b2a5c75661e0c57d0303d97c32d9c3e3841b23 --- /dev/null +++ b/node_modules/@mswjs/interceptors/lib/node/presets/node.js.map @@ -0,0 +1 @@ +{"version":3,"sources":["../../../src/presets/node.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAQA,IAAO,eAAQ;AAAA,EACb,IAAI,yBAAyB;AAAA,EAC7B,IAAI,0BAA0B;AAAA,EAC9B,IAAI,iBAAiB;AACvB","sourcesContent":["import { ClientRequestInterceptor } from '../interceptors/ClientRequest'\nimport { XMLHttpRequestInterceptor } from '../interceptors/XMLHttpRequest'\nimport { FetchInterceptor } from '../interceptors/fetch'\n\n/**\n * The default preset provisions the interception of requests\n * regardless of their type (http/https/XMLHttpRequest).\n */\nexport default [\n new ClientRequestInterceptor(),\n new XMLHttpRequestInterceptor(),\n new FetchInterceptor(),\n] as const\n"]} \ No newline at end of file diff --git a/node_modules/@mswjs/interceptors/lib/node/presets/node.mjs b/node_modules/@mswjs/interceptors/lib/node/presets/node.mjs new file mode 100644 index 0000000000000000000000000000000000000000..60d6a2d7b22baf019b9592be4c2a77461a51e4f3 --- /dev/null +++ b/node_modules/@mswjs/interceptors/lib/node/presets/node.mjs @@ -0,0 +1,25 @@ +import { + ClientRequestInterceptor +} from "../chunk-FWJSC2QD.mjs"; +import { + XMLHttpRequestInterceptor +} from "../chunk-OMWE7UVM.mjs"; +import "../chunk-6HYIRFX2.mjs"; +import { + FetchInterceptor +} from "../chunk-CTGTMEFD.mjs"; +import "../chunk-TX5GBTFY.mjs"; +import "../chunk-6YM4PLBI.mjs"; +import "../chunk-5KMS5CTP.mjs"; +import "../chunk-I7HQIBT7.mjs"; + +// src/presets/node.ts +var node_default = [ + new ClientRequestInterceptor(), + new XMLHttpRequestInterceptor(), + new FetchInterceptor() +]; +export { + node_default as default +}; +//# sourceMappingURL=node.mjs.map \ No newline at end of file diff --git a/node_modules/@mswjs/interceptors/lib/node/presets/node.mjs.map b/node_modules/@mswjs/interceptors/lib/node/presets/node.mjs.map new file mode 100644 index 0000000000000000000000000000000000000000..188c554323f38f352f445707ee4a7403b9619396 --- /dev/null +++ b/node_modules/@mswjs/interceptors/lib/node/presets/node.mjs.map @@ -0,0 +1 @@ +{"version":3,"sources":["../../../src/presets/node.ts"],"sourcesContent":["import { ClientRequestInterceptor } from '../interceptors/ClientRequest'\nimport { XMLHttpRequestInterceptor } from '../interceptors/XMLHttpRequest'\nimport { FetchInterceptor } from '../interceptors/fetch'\n\n/**\n * The default preset provisions the interception of requests\n * regardless of their type (http/https/XMLHttpRequest).\n */\nexport default [\n new ClientRequestInterceptor(),\n new XMLHttpRequestInterceptor(),\n new FetchInterceptor(),\n] as const\n"],"mappings":";;;;;;;;;;;;;;;;AAQA,IAAO,eAAQ;AAAA,EACb,IAAI,yBAAyB;AAAA,EAC7B,IAAI,0BAA0B;AAAA,EAC9B,IAAI,iBAAiB;AACvB;","names":[]} \ No newline at end of file diff --git a/node_modules/@mswjs/interceptors/package.json b/node_modules/@mswjs/interceptors/package.json new file mode 100644 index 0000000000000000000000000000000000000000..196a032ef83a6d6243abef6a6827021bb1a09631 --- /dev/null +++ b/node_modules/@mswjs/interceptors/package.json @@ -0,0 +1,202 @@ +{ + "name": "@mswjs/interceptors", + "description": "Low-level HTTP/HTTPS/XHR/fetch request interception library.", + "version": "0.37.6", + "main": "./lib/node/index.js", + "module": "./lib/node/index.mjs", + "types": "./lib/node/index.d.ts", + "exports": { + ".": { + "types": "./lib/node/index.d.ts", + "browser": { + "types": "./lib/browser/index.d.ts", + "require": "./lib/browser/index.js", + "import": "./lib/browser/index.mjs", + "default": "./lib/browser/index.js" + }, + "require": "./lib/node/index.js", + "import": "./lib/node/index.mjs", + "default": "./lib/node/index.js" + }, + "./ClientRequest": { + "types": "./lib/node/interceptors/ClientRequest/index.d.ts", + "node": { + "require": "./lib/node/interceptors/ClientRequest/index.js", + "import": "./lib/node/interceptors/ClientRequest/index.mjs" + }, + "browser": null, + "require": "./lib/node/interceptors/ClientRequest/index.js", + "import": "./lib/node/interceptors/ClientRequest/index.mjs", + "default": "./lib/node/interceptors/ClientRequest/index.js" + }, + "./XMLHttpRequest": { + "browser": { + "types": "./lib/browser/interceptors/XMLHttpRequest/index.d.ts", + "require": "./lib/browser/interceptors/XMLHttpRequest/index.js", + "import": "./lib/browser/interceptors/XMLHttpRequest/index.mjs", + "default": "./lib/browser/interceptors/XMLHttpRequest/index.js" + }, + "types": "./lib/node/interceptors/XMLHttpRequest/index.d.ts", + "require": "./lib/node/interceptors/XMLHttpRequest/index.js", + "import": "./lib/node/interceptors/XMLHttpRequest/index.mjs", + "default": "./lib/node/interceptors/XMLHttpRequest/index.js" + }, + "./fetch": { + "browser": { + "types": "./lib/browser/interceptors/fetch/index.d.ts", + "require": "./lib/browser/interceptors/fetch/index.js", + "import": "./lib/browser/interceptors/fetch/index.mjs", + "default": "./lib/browser/interceptors/fetch/index.js" + }, + "types": "./lib/node/interceptors/fetch/index.d.ts", + "require": "./lib/node/interceptors/fetch/index.js", + "import": "./lib/node/interceptors/fetch/index.mjs", + "default": "./lib/node/interceptors/fetch/index.js" + }, + "./WebSocket": { + "types": "./lib/browser/interceptors/WebSocket/index.d.ts", + "require": "./lib/browser/interceptors/WebSocket/index.js", + "import": "./lib/browser/interceptors/WebSocket/index.mjs", + "default": "./lib/browser/interceptors/WebSocket/index.js" + }, + "./RemoteHttpInterceptor": { + "types": "./lib/node/RemoteHttpInterceptor.d.ts", + "node": { + "require": "./lib/node/RemoteHttpInterceptor.js", + "import": "./lib/node/RemoteHttpInterceptor.mjs" + }, + "browser": null, + "require": "./lib/node/RemoteHttpInterceptor.js", + "import": "./lib/node/RemoteHttpInterceptor.mjs", + "default": "./lib/node/RemoteHttpInterceptor.js" + }, + "./presets/node": { + "types": "./lib/node/presets/node.d.ts", + "node": { + "require": "./lib/node/presets/node.js", + "import": "./lib/node/presets/node.mjs" + }, + "browser": null, + "require": "./lib/node/presets/node.js", + "import": "./lib/node/presets/node.mjs", + "default": "./lib/node/presets/node.js" + }, + "./presets/browser": { + "browser": { + "types": "./lib/browser/presets/browser.d.ts", + "require": "./lib/browser/presets/browser.js", + "import": "./lib/browser/presets/browser.mjs", + "default": "./lib/browser/presets/browser.js" + } + } + }, + "author": "Artem Zakharchenko", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "files": [ + "lib", + "README.md", + "src", + "ClientRequest", + "fetch", + "RemoteHttpInterceptor", + "XMLHttpRequest", + "WebSocket" + ], + "repository": { + "type": "git", + "url": "https://github.com/mswjs/interceptors" + }, + "devDependencies": { + "@commitlint/cli": "^16.0.2", + "@commitlint/config-conventional": "^16.0.0", + "@open-draft/test-server": "^0.5.1", + "@ossjs/release": "^0.8.1", + "@playwright/test": "^1.37.1", + "@types/cors": "^2.8.12", + "@types/express": "^4.17.13", + "@types/express-fileupload": "^1.5.0", + "@types/express-rate-limit": "^6.0.0", + "@types/follow-redirects": "^1.14.1", + "@types/jest": "^27.0.3", + "@types/node": "^18.19.31", + "@types/node-fetch": "2.5.12", + "@types/superagent": "^8.1.9", + "@types/supertest": "^2.0.11", + "@types/ws": "^8.5.10", + "axios": "^1.6.0", + "body-parser": "^1.19.0", + "commitizen": "^4.2.4", + "cors": "^2.8.5", + "cross-env": "^7.0.3", + "cz-conventional-changelog": "3.3.0", + "engine.io-parser": "^5.2.1", + "express": "^4.17.3", + "express-fileupload": "^1.5.1", + "express-rate-limit": "^6.3.0", + "follow-redirects": "^1.15.1", + "got": "^11.8.3", + "happy-dom": "^12.10.3", + "jest": "^27.4.3", + "node-fetch": "2.6.7", + "rimraf": "^3.0.2", + "simple-git-hooks": "^2.7.0", + "socket.io": "^4.7.4", + "socket.io-client": "^4.7.4", + "socket.io-parser": "^4.2.4", + "superagent": "^10.1.1", + "supertest": "^6.1.6", + "ts-jest": "^27.1.1", + "tsup": "^6.5.0", + "typescript": "^4.9.4", + "undici": "^6.6.2", + "vitest": "^1.2.2", + "vitest-environment-miniflare": "^2.14.1", + "wait-for-expect": "^3.0.2", + "web-encoding": "^1.1.5", + "webpack-http-server": "^0.5.0", + "ws": "^8.16.0" + }, + "dependencies": { + "@open-draft/deferred-promise": "^2.2.0", + "@open-draft/logger": "^0.3.0", + "@open-draft/until": "^2.0.0", + "is-node-process": "^1.2.0", + "outvariant": "^1.4.3", + "strict-event-emitter": "^0.5.1" + }, + "resolutions": { + "memfs": "^3.4.13" + }, + "keywords": [ + "request", + "intercept", + "http", + "https", + "xmlhttprequest", + "xhr", + "fetch", + "low-level", + "mock", + "spy", + "testing" + ], + "config": { + "commitizen": { + "path": "./node_modules/cz-conventional-changelog" + } + }, + "scripts": { + "start": "tsc --build -w", + "test": "pnpm test:unit && pnpm test:integration", + "test:unit": "vitest", + "test:integration": "pnpm test:node && pnpm test:browser", + "test:node": "vitest -c test/vitest.config.js", + "test:browser": "pnpm playwright test -c test/playwright.config.ts", + "clean": "rimraf lib", + "build": "pnpm clean && cross-env NODE_ENV=production tsup --splitting", + "release": "release publish" + } +} \ No newline at end of file diff --git a/node_modules/@mswjs/interceptors/src/BatchInterceptor.test.ts b/node_modules/@mswjs/interceptors/src/BatchInterceptor.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..5891d626718a75d0c3ea2b3a98833f77a2885f0c --- /dev/null +++ b/node_modules/@mswjs/interceptors/src/BatchInterceptor.test.ts @@ -0,0 +1,255 @@ +import { vi, it, expect, afterEach } from 'vitest' +import { Interceptor } from './Interceptor' +import { BatchInterceptor } from './BatchInterceptor' + +afterEach(() => { + vi.resetAllMocks() +}) + +it('applies child interceptors', () => { + class PrimaryInterceptor extends Interceptor { + constructor() { + super(Symbol('primary')) + } + } + + class SecondaryInterceptor extends Interceptor { + constructor() { + super(Symbol('secondary')) + } + } + + const instances = { + primary: new PrimaryInterceptor(), + secondary: new SecondaryInterceptor(), + } + + const interceptor = new BatchInterceptor({ + name: 'batch-apply', + interceptors: [instances.primary, instances.secondary], + }) + + const primaryApplySpy = vi.spyOn(instances.primary, 'apply') + const secondaryApplySpy = vi.spyOn(instances.secondary, 'apply') + + interceptor.apply() + + expect(primaryApplySpy).toHaveBeenCalledTimes(1) + expect(secondaryApplySpy).toHaveBeenCalledTimes(1) +}) + +it('proxies event listeners to the interceptors', () => { + class PrimaryInterceptor extends Interceptor<{ hello: [string] }> { + constructor() { + super(Symbol('primary')) + } + } + + class SecondaryInterceptor extends Interceptor<{ + goodbye: [string] + }> { + constructor() { + super(Symbol('secondary')) + } + } + + const instances = { + primary: new PrimaryInterceptor(), + secondary: new SecondaryInterceptor(), + } + + const interceptor = new BatchInterceptor({ + name: 'batch-proxy', + interceptors: [instances.primary, instances.secondary], + }) + + const helloListener = vi.fn() + interceptor.on('hello', helloListener) + + const goodbyeListener = vi.fn() + interceptor.on('goodbye', goodbyeListener) + + // Emulate the child interceptor emitting events. + instances.primary['emitter'].emit('hello', 'John') + instances.secondary['emitter'].emit('goodbye', 'Kate') + + // Must call the batch interceptor listener. + expect(helloListener).toHaveBeenCalledTimes(1) + expect(helloListener).toHaveBeenCalledWith('John') + expect(goodbyeListener).toHaveBeenCalledTimes(1) + expect(goodbyeListener).toHaveBeenCalledWith('Kate') +}) + +it('disposes of child interceptors', async () => { + class PrimaryInterceptor extends Interceptor { + constructor() { + super(Symbol('primary')) + } + } + + class SecondaryInterceptor extends Interceptor { + constructor() { + super(Symbol('secondary')) + } + } + + const instances = { + primary: new PrimaryInterceptor(), + secondary: new SecondaryInterceptor(), + } + + const interceptor = new BatchInterceptor({ + name: 'batch-dispose', + interceptors: [instances.primary, instances.secondary], + }) + + const primaryDisposeSpy = vi.spyOn(instances.primary, 'dispose') + const secondaryDisposeSpy = vi.spyOn(instances.secondary, 'dispose') + + interceptor.apply() + interceptor.dispose() + + expect(primaryDisposeSpy).toHaveBeenCalledTimes(1) + expect(secondaryDisposeSpy).toHaveBeenCalledTimes(1) +}) + +it('forwards listeners added via "on()"', () => { + class FirstInterceptor extends Interceptor { + constructor() { + super(Symbol('first')) + } + } + class SecondaryInterceptor extends Interceptor { + constructor() { + super(Symbol('second')) + } + } + + const firstInterceptor = new FirstInterceptor() + const secondInterceptor = new SecondaryInterceptor() + + const interceptor = new BatchInterceptor({ + name: 'batch', + interceptors: [firstInterceptor, secondInterceptor], + }) + + const listener = vi.fn() + interceptor.on('foo', listener) + + expect(firstInterceptor['emitter'].listenerCount('foo')).toBe(1) + expect(secondInterceptor['emitter'].listenerCount('foo')).toBe(1) + expect(interceptor['emitter'].listenerCount('foo')).toBe(0) +}) + +it('forwards listeners removal via "off()"', () => { + type Events = { + foo: [] + } + + class FirstInterceptor extends Interceptor { + constructor() { + super(Symbol('first')) + } + } + class SecondaryInterceptor extends Interceptor { + constructor() { + super(Symbol('second')) + } + } + + const firstInterceptor = new FirstInterceptor() + const secondInterceptor = new SecondaryInterceptor() + + const interceptor = new BatchInterceptor({ + name: 'batch', + interceptors: [firstInterceptor, secondInterceptor], + }) + + const listener = vi.fn() + interceptor.on('foo', listener) + interceptor.off('foo', listener) + + expect(firstInterceptor['emitter'].listenerCount('foo')).toBe(0) + expect(secondInterceptor['emitter'].listenerCount('foo')).toBe(0) +}) + +it('forwards removal of all listeners by name via ".removeAllListeners()"', () => { + type Events = { + foo: [] + bar: [] + } + + class FirstInterceptor extends Interceptor { + constructor() { + super(Symbol('first')) + } + } + class SecondaryInterceptor extends Interceptor { + constructor() { + super(Symbol('second')) + } + } + + const firstInterceptor = new FirstInterceptor() + const secondInterceptor = new SecondaryInterceptor() + + const interceptor = new BatchInterceptor({ + name: 'batch', + interceptors: [firstInterceptor, secondInterceptor], + }) + + const listener = vi.fn() + interceptor.on('foo', listener) + interceptor.on('foo', listener) + interceptor.on('bar', listener) + + expect(firstInterceptor['emitter'].listenerCount('foo')).toBe(2) + expect(secondInterceptor['emitter'].listenerCount('foo')).toBe(2) + expect(firstInterceptor['emitter'].listenerCount('bar')).toBe(1) + expect(secondInterceptor['emitter'].listenerCount('bar')).toBe(1) + + interceptor.removeAllListeners('foo') + + expect(firstInterceptor['emitter'].listenerCount('foo')).toBe(0) + expect(secondInterceptor['emitter'].listenerCount('foo')).toBe(0) + expect(firstInterceptor['emitter'].listenerCount('bar')).toBe(1) + expect(secondInterceptor['emitter'].listenerCount('bar')).toBe(1) +}) + +it('forwards removal of all listeners via ".removeAllListeners()"', () => { + class FirstInterceptor extends Interceptor { + constructor() { + super(Symbol('first')) + } + } + class SecondaryInterceptor extends Interceptor { + constructor() { + super(Symbol('second')) + } + } + + const firstInterceptor = new FirstInterceptor() + const secondInterceptor = new SecondaryInterceptor() + + const interceptor = new BatchInterceptor({ + name: 'batch', + interceptors: [firstInterceptor, secondInterceptor], + }) + + const listener = vi.fn() + interceptor.on('foo', listener) + interceptor.on('foo', listener) + interceptor.on('bar', listener) + + expect(firstInterceptor['emitter'].listenerCount('foo')).toBe(2) + expect(secondInterceptor['emitter'].listenerCount('foo')).toBe(2) + expect(firstInterceptor['emitter'].listenerCount('bar')).toBe(1) + expect(secondInterceptor['emitter'].listenerCount('bar')).toBe(1) + + interceptor.removeAllListeners() + + expect(firstInterceptor['emitter'].listenerCount('foo')).toBe(0) + expect(secondInterceptor['emitter'].listenerCount('foo')).toBe(0) + expect(firstInterceptor['emitter'].listenerCount('bar')).toBe(0) + expect(secondInterceptor['emitter'].listenerCount('bar')).toBe(0) +}) diff --git a/node_modules/@mswjs/interceptors/src/BatchInterceptor.ts b/node_modules/@mswjs/interceptors/src/BatchInterceptor.ts new file mode 100644 index 0000000000000000000000000000000000000000..083ce5fb2386109b72119293fa8a5f17d82553f1 --- /dev/null +++ b/node_modules/@mswjs/interceptors/src/BatchInterceptor.ts @@ -0,0 +1,95 @@ +import { EventMap, Listener } from 'strict-event-emitter' +import { Interceptor, ExtractEventNames } from './Interceptor' + +export interface BatchInterceptorOptions< + InterceptorList extends ReadonlyArray> +> { + name: string + interceptors: InterceptorList +} + +export type ExtractEventMapType< + InterceptorList extends ReadonlyArray> +> = InterceptorList extends ReadonlyArray + ? InterceptorType extends Interceptor + ? EventMap + : never + : never + +/** + * A batch interceptor that exposes a single interface + * to apply and operate with multiple interceptors at once. + */ +export class BatchInterceptor< + InterceptorList extends ReadonlyArray>, + Events extends EventMap = ExtractEventMapType +> extends Interceptor { + static symbol: symbol + + private interceptors: InterceptorList + + constructor(options: BatchInterceptorOptions) { + BatchInterceptor.symbol = Symbol(options.name) + super(BatchInterceptor.symbol) + this.interceptors = options.interceptors + } + + protected setup() { + const logger = this.logger.extend('setup') + + logger.info('applying all %d interceptors...', this.interceptors.length) + + for (const interceptor of this.interceptors) { + logger.info('applying "%s" interceptor...', interceptor.constructor.name) + interceptor.apply() + + logger.info('adding interceptor dispose subscription') + this.subscriptions.push(() => interceptor.dispose()) + } + } + + public on>( + event: EventName, + listener: Listener + ): this { + // Instead of adding a listener to the batch interceptor, + // propagate the listener to each of the individual interceptors. + for (const interceptor of this.interceptors) { + interceptor.on(event, listener) + } + + return this + } + + public once>( + event: EventName, + listener: Listener + ): this { + for (const interceptor of this.interceptors) { + interceptor.once(event, listener) + } + + return this + } + + public off>( + event: EventName, + listener: Listener + ): this { + for (const interceptor of this.interceptors) { + interceptor.off(event, listener) + } + + return this + } + + public removeAllListeners>( + event?: EventName | undefined + ): this { + for (const interceptors of this.interceptors) { + interceptors.removeAllListeners(event) + } + + return this + } +} diff --git a/node_modules/@mswjs/interceptors/src/Interceptor.test.ts b/node_modules/@mswjs/interceptors/src/Interceptor.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..6b76606a553d4e783a782af040ede90e2b0ce7fa --- /dev/null +++ b/node_modules/@mswjs/interceptors/src/Interceptor.test.ts @@ -0,0 +1,205 @@ +import { describe, vi, it, expect, afterEach } from 'vitest' +import { + Interceptor, + getGlobalSymbol, + deleteGlobalSymbol, + InterceptorReadyState, +} from './Interceptor' +import { nextTickAsync } from './utils/nextTick' + +const symbol = Symbol('test') + +afterEach(() => { + deleteGlobalSymbol(symbol) +}) + +it('does not set a maximum listeners limit', () => { + const interceptor = new Interceptor(symbol) + expect(interceptor['emitter'].getMaxListeners()).toBe(0) +}) + +describe('on()', () => { + it('adds a new listener using "on()"', () => { + const interceptor = new Interceptor(symbol) + expect(interceptor['emitter'].listenerCount('event')).toBe(0) + + const listener = vi.fn() + interceptor.on('event', listener) + expect(interceptor['emitter'].listenerCount('event')).toBe(1) + }) +}) + +describe('once()', () => { + it('calls the listener only once', () => { + const interceptor = new Interceptor(symbol) + const listener = vi.fn() + + interceptor.once('foo', listener) + expect(listener).not.toHaveBeenCalled() + + interceptor['emitter'].emit('foo', 'bar') + + expect(listener).toHaveBeenCalledTimes(1) + expect(listener).toHaveBeenCalledWith('bar') + + listener.mockReset() + + interceptor['emitter'].emit('foo', 'baz') + interceptor['emitter'].emit('foo', 'xyz') + expect(listener).toHaveBeenCalledTimes(0) + }) +}) + +describe('off()', () => { + it('removes a listener using "off()"', () => { + const interceptor = new Interceptor(symbol) + expect(interceptor['emitter'].listenerCount('event')).toBe(0) + + const listener = vi.fn() + interceptor.on('event', listener) + expect(interceptor['emitter'].listenerCount('event')).toBe(1) + + interceptor.off('event', listener) + expect(interceptor['emitter'].listenerCount('event')).toBe(0) + }) +}) + +describe('persistence', () => { + it('stores global reference to the applied interceptor', () => { + const interceptor = new Interceptor(symbol) + interceptor.apply() + + expect(getGlobalSymbol(symbol)).toEqual(interceptor) + }) + + it('deletes global reference when the interceptor is disposed', () => { + const interceptor = new Interceptor(symbol) + + interceptor.apply() + interceptor.dispose() + + expect(getGlobalSymbol(symbol)).toBeUndefined() + }) +}) + +describe('readyState', () => { + it('sets the state to "INACTIVE" when the interceptor is created', () => { + const interceptor = new Interceptor(symbol) + expect(interceptor.readyState).toBe(InterceptorReadyState.INACTIVE) + }) + + it('leaves state as "INACTIVE" if the interceptor failed the environment check', async () => { + class MyInterceptor extends Interceptor { + protected checkEnvironment(): boolean { + return false + } + } + const interceptor = new MyInterceptor(symbol) + interceptor.apply() + + expect(interceptor.readyState).toBe(InterceptorReadyState.INACTIVE) + }) + + it('perfroms state transition when the interceptor is applying', async () => { + const interceptor = new Interceptor(symbol) + interceptor.apply() + + // The interceptor's state transitions to APPLIED immediately. + // The only exception is if something throws during the setup. + expect(interceptor.readyState).toBe(InterceptorReadyState.APPLIED) + }) + + it('perfroms state transition when disposing of the interceptor', async () => { + const interceptor = new Interceptor(symbol) + interceptor.apply() + interceptor.dispose() + + // The interceptor's state transitions to DISPOSED immediately. + // The only exception is if something throws during the teardown. + expect(interceptor.readyState).toBe(InterceptorReadyState.DISPOSED) + }) +}) + +describe('apply', () => { + it('does not apply the same interceptor multiple times', () => { + const interceptor = new Interceptor(symbol) + const setupSpy = vi.spyOn( + interceptor, + // @ts-expect-error Protected property spy. + 'setup' + ) + + // Intentionally apply the same interceptor multiple times. + interceptor.apply() + interceptor.apply() + interceptor.apply() + + // The "setup" must not be called repeatedly. + expect(setupSpy).toHaveBeenCalledTimes(1) + + expect(getGlobalSymbol(symbol)).toEqual(interceptor) + }) + + it('does not call "apply" if the interceptor fails environment check', () => { + class MyInterceptor extends Interceptor<{}> { + checkEnvironment() { + return false + } + } + + const interceptor = new MyInterceptor(Symbol('test')) + const setupSpy = vi.spyOn( + interceptor, + // @ts-expect-error Protected property spy. + 'setup' + ) + interceptor.apply() + + expect(setupSpy).not.toHaveBeenCalled() + }) + + it('proxies listeners from new interceptor to already running interceptor', () => { + const firstInterceptor = new Interceptor(symbol) + const secondInterceptor = new Interceptor(symbol) + + firstInterceptor.apply() + const firstListener = vi.fn() + firstInterceptor.on('test', firstListener) + + secondInterceptor.apply() + const secondListener = vi.fn() + secondInterceptor.on('test', secondListener) + + // Emitting event in the first interceptor will bubble to the second one. + firstInterceptor['emitter'].emit('test', 'hello world') + + expect(firstListener).toHaveBeenCalledTimes(1) + expect(firstListener).toHaveBeenCalledWith('hello world') + + expect(secondListener).toHaveBeenCalledTimes(1) + expect(secondListener).toHaveBeenCalledWith('hello world') + + expect(secondInterceptor['emitter'].listenerCount('test')).toBe(0) + }) +}) + +describe('dispose', () => { + it('removes all listeners when the interceptor is disposed', async () => { + const interceptor = new Interceptor(symbol) + + interceptor.apply() + const listener = vi.fn() + interceptor.on('test', listener) + interceptor.dispose() + + // Even after emitting an event, the listener must not get called. + interceptor['emitter'].emit('test') + expect(listener).not.toHaveBeenCalled() + + // The listener must not be called on the next tick either. + await nextTickAsync(() => { + interceptor['emitter'].emit('test') + expect(listener).not.toHaveBeenCalled() + }) + }) +}) diff --git a/node_modules/@mswjs/interceptors/src/Interceptor.ts b/node_modules/@mswjs/interceptors/src/Interceptor.ts new file mode 100644 index 0000000000000000000000000000000000000000..b33e74fdfb29d523e63711dae56e056a12dd8864 --- /dev/null +++ b/node_modules/@mswjs/interceptors/src/Interceptor.ts @@ -0,0 +1,249 @@ +import { Logger } from '@open-draft/logger' +import { Emitter, Listener } from 'strict-event-emitter' + +export type InterceptorEventMap = Record +export type InterceptorSubscription = () => void + +/** + * Request header name to detect when a single request + * is being handled by nested interceptors (XHR -> ClientRequest). + * Obscure by design to prevent collisions with user-defined headers. + * Ideally, come up with the Interceptor-level mechanism for this. + * @see https://github.com/mswjs/interceptors/issues/378 + */ +export const INTERNAL_REQUEST_ID_HEADER_NAME = + 'x-interceptors-internal-request-id' + +export function getGlobalSymbol(symbol: Symbol): V | undefined { + return ( + // @ts-ignore https://github.com/Microsoft/TypeScript/issues/24587 + globalThis[symbol] || undefined + ) +} + +function setGlobalSymbol(symbol: Symbol, value: any): void { + // @ts-ignore + globalThis[symbol] = value +} + +export function deleteGlobalSymbol(symbol: Symbol): void { + // @ts-ignore + delete globalThis[symbol] +} + +export enum InterceptorReadyState { + INACTIVE = 'INACTIVE', + APPLYING = 'APPLYING', + APPLIED = 'APPLIED', + DISPOSING = 'DISPOSING', + DISPOSED = 'DISPOSED', +} + +export type ExtractEventNames> = + Events extends Record ? EventName : never + +export class Interceptor { + protected emitter: Emitter + protected subscriptions: Array + protected logger: Logger + + public readyState: InterceptorReadyState + + constructor(private readonly symbol: symbol) { + this.readyState = InterceptorReadyState.INACTIVE + + this.emitter = new Emitter() + this.subscriptions = [] + this.logger = new Logger(symbol.description!) + + // Do not limit the maximum number of listeners + // so not to limit the maximum amount of parallel events emitted. + this.emitter.setMaxListeners(0) + + this.logger.info('constructing the interceptor...') + } + + /** + * Determine if this interceptor can be applied + * in the current environment. + */ + protected checkEnvironment(): boolean { + return true + } + + /** + * Apply this interceptor to the current process. + * Returns an already running interceptor instance if it's present. + */ + public apply(): void { + const logger = this.logger.extend('apply') + logger.info('applying the interceptor...') + + if (this.readyState === InterceptorReadyState.APPLIED) { + logger.info('intercepted already applied!') + return + } + + const shouldApply = this.checkEnvironment() + + if (!shouldApply) { + logger.info('the interceptor cannot be applied in this environment!') + return + } + + this.readyState = InterceptorReadyState.APPLYING + + // Whenever applying a new interceptor, check if it hasn't been applied already. + // This enables to apply the same interceptor multiple times, for example from a different + // interceptor, only proxying events but keeping the stubs in a single place. + const runningInstance = this.getInstance() + + if (runningInstance) { + logger.info('found a running instance, reusing...') + + // Proxy any listeners you set on this instance to the running instance. + this.on = (event, listener) => { + logger.info('proxying the "%s" listener', event) + + // Add listeners to the running instance so they appear + // at the top of the event listeners list and are executed first. + runningInstance.emitter.addListener(event, listener) + + // Ensure that once this interceptor instance is disposed, + // it removes all listeners it has appended to the running interceptor instance. + this.subscriptions.push(() => { + runningInstance.emitter.removeListener(event, listener) + logger.info('removed proxied "%s" listener!', event) + }) + + return this + } + + this.readyState = InterceptorReadyState.APPLIED + + return + } + + logger.info('no running instance found, setting up a new instance...') + + // Setup the interceptor. + this.setup() + + // Store the newly applied interceptor instance globally. + this.setInstance() + + this.readyState = InterceptorReadyState.APPLIED + } + + /** + * Setup the module augments and stubs necessary for this interceptor. + * This method is not run if there's a running interceptor instance + * to prevent instantiating an interceptor multiple times. + */ + protected setup(): void {} + + /** + * Listen to the interceptor's public events. + */ + public on>( + event: EventName, + listener: Listener + ): this { + const logger = this.logger.extend('on') + + if ( + this.readyState === InterceptorReadyState.DISPOSING || + this.readyState === InterceptorReadyState.DISPOSED + ) { + logger.info('cannot listen to events, already disposed!') + return this + } + + logger.info('adding "%s" event listener:', event, listener) + + this.emitter.on(event, listener) + return this + } + + public once>( + event: EventName, + listener: Listener + ): this { + this.emitter.once(event, listener) + return this + } + + public off>( + event: EventName, + listener: Listener + ): this { + this.emitter.off(event, listener) + return this + } + + public removeAllListeners>( + event?: EventName + ): this { + this.emitter.removeAllListeners(event) + return this + } + + /** + * Disposes of any side-effects this interceptor has introduced. + */ + public dispose(): void { + const logger = this.logger.extend('dispose') + + if (this.readyState === InterceptorReadyState.DISPOSED) { + logger.info('cannot dispose, already disposed!') + return + } + + logger.info('disposing the interceptor...') + this.readyState = InterceptorReadyState.DISPOSING + + if (!this.getInstance()) { + logger.info('no interceptors running, skipping dispose...') + return + } + + // Delete the global symbol as soon as possible, + // indicating that the interceptor is no longer running. + this.clearInstance() + + logger.info('global symbol deleted:', getGlobalSymbol(this.symbol)) + + if (this.subscriptions.length > 0) { + logger.info('disposing of %d subscriptions...', this.subscriptions.length) + + for (const dispose of this.subscriptions) { + dispose() + } + + this.subscriptions = [] + + logger.info('disposed of all subscriptions!', this.subscriptions.length) + } + + this.emitter.removeAllListeners() + logger.info('destroyed the listener!') + + this.readyState = InterceptorReadyState.DISPOSED + } + + private getInstance(): this | undefined { + const instance = getGlobalSymbol(this.symbol) + this.logger.info('retrieved global instance:', instance?.constructor?.name) + return instance + } + + private setInstance(): void { + setGlobalSymbol(this.symbol, this) + this.logger.info('set global instance!', this.symbol.description) + } + + private clearInstance(): void { + deleteGlobalSymbol(this.symbol) + this.logger.info('cleared global instance!', this.symbol.description) + } +} diff --git a/node_modules/@mswjs/interceptors/src/InterceptorError.ts b/node_modules/@mswjs/interceptors/src/InterceptorError.ts new file mode 100644 index 0000000000000000000000000000000000000000..882848befd5b77cca56749572437482942d001bb --- /dev/null +++ b/node_modules/@mswjs/interceptors/src/InterceptorError.ts @@ -0,0 +1,7 @@ +export class InterceptorError extends Error { + constructor(message?: string) { + super(message) + this.name = 'InterceptorError' + Object.setPrototypeOf(this, InterceptorError.prototype) + } +} diff --git a/node_modules/@mswjs/interceptors/src/RemoteHttpInterceptor.ts b/node_modules/@mswjs/interceptors/src/RemoteHttpInterceptor.ts new file mode 100644 index 0000000000000000000000000000000000000000..5b7c53dca1df457450b753ee8ec9aec6e3bc98c3 --- /dev/null +++ b/node_modules/@mswjs/interceptors/src/RemoteHttpInterceptor.ts @@ -0,0 +1,244 @@ +import { ChildProcess } from 'child_process' +import { HttpRequestEventMap } from './glossary' +import { Interceptor } from './Interceptor' +import { BatchInterceptor } from './BatchInterceptor' +import { ClientRequestInterceptor } from './interceptors/ClientRequest' +import { XMLHttpRequestInterceptor } from './interceptors/XMLHttpRequest' +import { handleRequest } from './utils/handleRequest' +import { RequestController } from './RequestController' +import { FetchResponse } from './utils/fetchUtils' + +export interface SerializedRequest { + id: string + url: string + method: string + headers: Array<[string, string]> + credentials: RequestCredentials + body: string +} + +interface RevivedRequest extends Omit { + url: URL + headers: Headers +} + +export interface SerializedResponse { + status: number + statusText: string + headers: Array<[string, string]> + body: string +} + +export class RemoteHttpInterceptor extends BatchInterceptor< + [ClientRequestInterceptor, XMLHttpRequestInterceptor] +> { + constructor() { + super({ + name: 'remote-interceptor', + interceptors: [ + new ClientRequestInterceptor(), + new XMLHttpRequestInterceptor(), + ], + }) + } + + protected setup() { + super.setup() + + let handleParentMessage: NodeJS.MessageListener + + this.on('request', async ({ request, requestId, controller }) => { + // Send the stringified intercepted request to + // the parent process where the remote resolver is established. + const serializedRequest = JSON.stringify({ + id: requestId, + method: request.method, + url: request.url, + headers: Array.from(request.headers.entries()), + credentials: request.credentials, + body: ['GET', 'HEAD'].includes(request.method) + ? null + : await request.text(), + } as SerializedRequest) + + this.logger.info( + 'sent serialized request to the child:', + serializedRequest + ) + + process.send?.(`request:${serializedRequest}`) + + const responsePromise = new Promise((resolve) => { + handleParentMessage = (message) => { + if (typeof message !== 'string') { + return resolve() + } + + if (message.startsWith(`response:${requestId}`)) { + const [, serializedResponse] = + message.match(/^response:.+?:(.+)$/) || [] + + if (!serializedResponse) { + return resolve() + } + + const responseInit = JSON.parse( + serializedResponse + ) as SerializedResponse + + const mockedResponse = new FetchResponse(responseInit.body, { + url: request.url, + status: responseInit.status, + statusText: responseInit.statusText, + headers: responseInit.headers, + }) + + /** + * @todo Support "errorWith" as well. + * This response handling from the child is incomplete. + */ + + controller.respondWith(mockedResponse) + return resolve() + } + } + }) + + // Listen for the mocked response message from the parent. + this.logger.info( + 'add "message" listener to the parent process', + handleParentMessage + ) + process.addListener('message', handleParentMessage) + + return responsePromise + }) + + this.subscriptions.push(() => { + process.removeListener('message', handleParentMessage) + }) + } +} + +export function requestReviver(key: string, value: any) { + switch (key) { + case 'url': + return new URL(value) + + case 'headers': + return new Headers(value) + + default: + return value + } +} + +export interface RemoveResolverOptions { + process: ChildProcess +} + +export class RemoteHttpResolver extends Interceptor { + static symbol = Symbol('remote-resolver') + private process: ChildProcess + + constructor(options: RemoveResolverOptions) { + super(RemoteHttpResolver.symbol) + this.process = options.process + } + + protected setup() { + const logger = this.logger.extend('setup') + + const handleChildMessage: NodeJS.MessageListener = async (message) => { + logger.info('received message from child!', message) + + if (typeof message !== 'string' || !message.startsWith('request:')) { + logger.info('unknown message, ignoring...') + return + } + + const [, serializedRequest] = message.match(/^request:(.+)$/) || [] + if (!serializedRequest) { + return + } + + const requestJson = JSON.parse( + serializedRequest, + requestReviver + ) as RevivedRequest + + logger.info('parsed intercepted request', requestJson) + + const request = new Request(requestJson.url, { + method: requestJson.method, + headers: new Headers(requestJson.headers), + credentials: requestJson.credentials, + body: requestJson.body, + }) + + const controller = new RequestController(request) + await handleRequest({ + request, + requestId: requestJson.id, + controller, + emitter: this.emitter, + onResponse: async (response) => { + this.logger.info('received mocked response!', { response }) + + const responseClone = response.clone() + const responseText = await responseClone.text() + + // // Send the mocked response to the child process. + const serializedResponse = JSON.stringify({ + status: response.status, + statusText: response.statusText, + headers: Array.from(response.headers.entries()), + body: responseText, + } as SerializedResponse) + + this.process.send( + `response:${requestJson.id}:${serializedResponse}`, + (error) => { + if (error) { + return + } + + // Emit an optimistic "response" event at this point, + // not to rely on the back-and-forth signaling for the sake of the event. + this.emitter.emit('response', { + request, + requestId: requestJson.id, + response: responseClone, + isMockedResponse: true, + }) + } + ) + + logger.info( + 'sent serialized mocked response to the parent:', + serializedResponse + ) + }, + onRequestError: (response) => { + this.logger.info('received a network error!', { response }) + throw new Error('Not implemented') + }, + onError: (error) => { + this.logger.info('request has errored!', { error }) + throw new Error('Not implemented') + }, + }) + } + + this.subscriptions.push(() => { + this.process.removeListener('message', handleChildMessage) + logger.info('removed the "message" listener from the child process!') + }) + + logger.info('adding a "message" listener to the child process') + this.process.addListener('message', handleChildMessage) + + this.process.once('error', () => this.dispose()) + this.process.once('exit', () => this.dispose()) + } +} diff --git a/node_modules/@mswjs/interceptors/src/RequestController.test.ts b/node_modules/@mswjs/interceptors/src/RequestController.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..f3adeab2a39117264b11710b6fa620e7900eedd9 --- /dev/null +++ b/node_modules/@mswjs/interceptors/src/RequestController.test.ts @@ -0,0 +1,49 @@ +import { it, expect } from 'vitest' +import { kResponsePromise, RequestController } from './RequestController' + +it('creates a pending response promise on construction', () => { + const controller = new RequestController(new Request('http://localhost')) + expect(controller[kResponsePromise]).toBeInstanceOf(Promise) + expect(controller[kResponsePromise].state).toBe('pending') +}) + +it('resolves the response promise with the response provided to "respondWith"', async () => { + const controller = new RequestController(new Request('http://localhost')) + controller.respondWith(new Response('hello world')) + + const response = (await controller[kResponsePromise]) as Response + + expect(response).toBeInstanceOf(Response) + expect(response.status).toBe(200) + expect(await response.text()).toBe('hello world') +}) + +it('resolves the response promise with the error provided to "errorWith"', async () => { + const controller = new RequestController(new Request('http://localhost')) + const error = new Error('Oops!') + controller.errorWith(error) + + await expect(controller[kResponsePromise]).resolves.toEqual(error) +}) + +it('throws when calling "respondWith" multiple times', () => { + const controller = new RequestController(new Request('http://localhost')) + controller.respondWith(new Response('hello world')) + + expect(() => { + controller.respondWith(new Response('second response')) + }).toThrow( + 'Failed to respond to the "GET http://localhost/" request: the "request" event has already been handled.' + ) +}) + +it('throws when calling "errorWith" multiple times', () => { + const controller = new RequestController(new Request('http://localhost')) + controller.errorWith(new Error('Oops!')) + + expect(() => { + controller.errorWith(new Error('second error')) + }).toThrow( + 'Failed to error the "GET http://localhost/" request: the "request" event has already been handled.' + ) +}) diff --git a/node_modules/@mswjs/interceptors/src/RequestController.ts b/node_modules/@mswjs/interceptors/src/RequestController.ts new file mode 100644 index 0000000000000000000000000000000000000000..8ff48cfcddb91464e0677d80f5bc82ec9683a392 --- /dev/null +++ b/node_modules/@mswjs/interceptors/src/RequestController.ts @@ -0,0 +1,81 @@ +import { invariant } from 'outvariant' +import { DeferredPromise } from '@open-draft/deferred-promise' +import { InterceptorError } from './InterceptorError' + +const kRequestHandled = Symbol('kRequestHandled') +export const kResponsePromise = Symbol('kResponsePromise') + +export class RequestController { + /** + * Internal response promise. + * Available only for the library internals to grab the + * response instance provided by the developer. + * @note This promise cannot be rejected. It's either infinitely + * pending or resolved with whichever Response was passed to `respondWith()`. + */ + [kResponsePromise]: DeferredPromise; + + /** + * Internal flag indicating if this request has been handled. + * @note The response promise becomes "fulfilled" on the next tick. + */ + [kRequestHandled]: boolean + + constructor(private request: Request) { + this[kRequestHandled] = false + this[kResponsePromise] = new DeferredPromise() + } + + /** + * Respond to this request with the given `Response` instance. + * @example + * controller.respondWith(new Response()) + * controller.respondWith(Response.json({ id })) + * controller.respondWith(Response.error()) + */ + public respondWith(response: Response): void { + invariant.as( + InterceptorError, + !this[kRequestHandled], + 'Failed to respond to the "%s %s" request: the "request" event has already been handled.', + this.request.method, + this.request.url + ) + + this[kRequestHandled] = true + this[kResponsePromise].resolve(response) + + /** + * @note The request conrtoller doesn't do anything + * apart from letting the interceptor await the response + * provided by the developer through the response promise. + * Each interceptor implements the actual respondWith/errorWith + * logic based on that interceptor's needs. + */ + } + + /** + * Error this request with the given error. + * @example + * controller.errorWith() + * controller.errorWith(new Error('Oops!')) + */ + public errorWith(error?: Error): void { + invariant.as( + InterceptorError, + !this[kRequestHandled], + 'Failed to error the "%s %s" request: the "request" event has already been handled.', + this.request.method, + this.request.url + ) + + this[kRequestHandled] = true + + /** + * @note Resolve the response promise, not reject. + * This helps us differentiate between unhandled exceptions + * and intended errors ("errorWith") while waiting for the response. + */ + this[kResponsePromise].resolve(error) + } +} diff --git a/node_modules/@mswjs/interceptors/src/createRequestId.test.ts b/node_modules/@mswjs/interceptors/src/createRequestId.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..a59b2c049f3b3dfe0bea0524c3ec27ed10e205b1 --- /dev/null +++ b/node_modules/@mswjs/interceptors/src/createRequestId.test.ts @@ -0,0 +1,7 @@ +import { it, expect } from 'vitest' +import { createRequestId } from './createRequestId' +import { REQUEST_ID_REGEXP } from '../test/helpers' + +it('returns a request ID', () => { + expect(createRequestId()).toMatch(REQUEST_ID_REGEXP) +}) diff --git a/node_modules/@mswjs/interceptors/src/createRequestId.ts b/node_modules/@mswjs/interceptors/src/createRequestId.ts new file mode 100644 index 0000000000000000000000000000000000000000..318d2eb954d8d4620e6b047d38a6feac8744121a --- /dev/null +++ b/node_modules/@mswjs/interceptors/src/createRequestId.ts @@ -0,0 +1,9 @@ +/** + * Generate a random ID string to represent a request. + * @example + * createRequestId() + * // "f774b6c9c600f" + */ +export function createRequestId(): string { + return Math.random().toString(16).slice(2) +} diff --git a/node_modules/@mswjs/interceptors/src/glossary.ts b/node_modules/@mswjs/interceptors/src/glossary.ts new file mode 100644 index 0000000000000000000000000000000000000000..2015852701d6c08c48ea8d4959790d2ee3c03c4a --- /dev/null +++ b/node_modules/@mswjs/interceptors/src/glossary.ts @@ -0,0 +1,37 @@ +import type { RequestController } from './RequestController' + +export const IS_PATCHED_MODULE: unique symbol = Symbol('isPatchedModule') + +/** + * @note Export `RequestController` as a type only. + * It's never meant to be created in the userland. + */ +export type { RequestController } + +export type RequestCredentials = 'omit' | 'include' | 'same-origin' + +export type HttpRequestEventMap = { + request: [ + args: { + request: Request + requestId: string + controller: RequestController + } + ] + response: [ + args: { + response: Response + isMockedResponse: boolean + request: Request + requestId: string + } + ] + unhandledException: [ + args: { + error: unknown + request: Request + requestId: string + controller: RequestController + } + ] +} diff --git a/node_modules/@mswjs/interceptors/src/index.ts b/node_modules/@mswjs/interceptors/src/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..21aa732be8a62a31a0ca9239893e74b0559b5e27 --- /dev/null +++ b/node_modules/@mswjs/interceptors/src/index.ts @@ -0,0 +1,9 @@ +export * from './glossary' +export * from './Interceptor' +export * from './BatchInterceptor' + +/* Utils */ +export { createRequestId } from './createRequestId' +export { getCleanUrl } from './utils/getCleanUrl' +export { encodeBuffer, decodeBuffer } from './utils/bufferUtils' +export { FetchResponse } from './utils/fetchUtils' diff --git a/node_modules/@mswjs/interceptors/src/interceptors/ClientRequest/MockHttpSocket.ts b/node_modules/@mswjs/interceptors/src/interceptors/ClientRequest/MockHttpSocket.ts new file mode 100644 index 0000000000000000000000000000000000000000..45cf6b5dd2c3fa683fa88d7c0d44af5ea32a5d17 --- /dev/null +++ b/node_modules/@mswjs/interceptors/src/interceptors/ClientRequest/MockHttpSocket.ts @@ -0,0 +1,628 @@ +import net from 'node:net' +import { + HTTPParser, + type RequestHeadersCompleteCallback, + type ResponseHeadersCompleteCallback, +} from '_http_common' +import { STATUS_CODES, IncomingMessage, ServerResponse } from 'node:http' +import { Readable } from 'node:stream' +import { invariant } from 'outvariant' +import { INTERNAL_REQUEST_ID_HEADER_NAME } from '../../Interceptor' +import { MockSocket } from '../Socket/MockSocket' +import type { NormalizedSocketWriteArgs } from '../Socket/utils/normalizeSocketWriteArgs' +import { isPropertyAccessible } from '../../utils/isPropertyAccessible' +import { baseUrlFromConnectionOptions } from '../Socket/utils/baseUrlFromConnectionOptions' +import { createServerErrorResponse } from '../../utils/responseUtils' +import { createRequestId } from '../../createRequestId' +import { getRawFetchHeaders } from './utils/recordRawHeaders' +import { FetchResponse } from '../../utils/fetchUtils' + +type HttpConnectionOptions = any + +export type MockHttpSocketRequestCallback = (args: { + requestId: string + request: Request + socket: MockHttpSocket +}) => void + +export type MockHttpSocketResponseCallback = (args: { + requestId: string + request: Request + response: Response + isMockedResponse: boolean + socket: MockHttpSocket +}) => Promise + +interface MockHttpSocketOptions { + connectionOptions: HttpConnectionOptions + createConnection: () => net.Socket + onRequest: MockHttpSocketRequestCallback + onResponse: MockHttpSocketResponseCallback +} + +export const kRequestId = Symbol('kRequestId') + +export class MockHttpSocket extends MockSocket { + private connectionOptions: HttpConnectionOptions + private createConnection: () => net.Socket + private baseUrl: URL + + private onRequest: MockHttpSocketRequestCallback + private onResponse: MockHttpSocketResponseCallback + private responseListenersPromise?: Promise + + private writeBuffer: Array = [] + private request?: Request + private requestParser: HTTPParser<0> + private requestStream?: Readable + private shouldKeepAlive?: boolean + + private socketState: 'unknown' | 'mock' | 'passthrough' = 'unknown' + private responseParser: HTTPParser<1> + private responseStream?: Readable + private originalSocket?: net.Socket + + constructor(options: MockHttpSocketOptions) { + super({ + write: (chunk, encoding, callback) => { + // Buffer the writes so they can be flushed in case of the original connection + // and when reading the request body in the interceptor. If the connection has + // been established, no need to buffer the chunks anymore, they will be forwarded. + if (this.socketState !== 'passthrough') { + this.writeBuffer.push([chunk, encoding, callback]) + } + + if (chunk) { + /** + * Forward any writes to the mock socket to the underlying original socket. + * This ensures functional duplex connections, like WebSocket. + * @see https://github.com/mswjs/interceptors/issues/682 + */ + if (this.socketState === 'passthrough') { + this.originalSocket?.write(chunk, encoding, callback) + } + + this.requestParser.execute( + Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk, encoding) + ) + } + }, + read: (chunk) => { + if (chunk !== null) { + /** + * @todo We need to free the parser if the connection has been + * upgraded to a non-HTTP protocol. It won't be able to parse data + * from that point onward anyway. No need to keep it in memory. + */ + this.responseParser.execute( + Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk) + ) + } + }, + }) + + this.connectionOptions = options.connectionOptions + this.createConnection = options.createConnection + this.onRequest = options.onRequest + this.onResponse = options.onResponse + + this.baseUrl = baseUrlFromConnectionOptions(this.connectionOptions) + + // Request parser. + this.requestParser = new HTTPParser() + this.requestParser.initialize(HTTPParser.REQUEST, {}) + this.requestParser[HTTPParser.kOnHeadersComplete] = + this.onRequestStart.bind(this) + this.requestParser[HTTPParser.kOnBody] = this.onRequestBody.bind(this) + this.requestParser[HTTPParser.kOnMessageComplete] = + this.onRequestEnd.bind(this) + + // Response parser. + this.responseParser = new HTTPParser() + this.responseParser.initialize(HTTPParser.RESPONSE, {}) + this.responseParser[HTTPParser.kOnHeadersComplete] = + this.onResponseStart.bind(this) + this.responseParser[HTTPParser.kOnBody] = this.onResponseBody.bind(this) + this.responseParser[HTTPParser.kOnMessageComplete] = + this.onResponseEnd.bind(this) + + // Once the socket is finished, nothing can write to it + // anymore. It has also flushed any buffered chunks. + this.once('finish', () => this.requestParser.free()) + + if (this.baseUrl.protocol === 'https:') { + Reflect.set(this, 'encrypted', true) + // The server certificate is not the same as a CA + // passed to the TLS socket connection options. + Reflect.set(this, 'authorized', false) + Reflect.set(this, 'getProtocol', () => 'TLSv1.3') + Reflect.set(this, 'getSession', () => undefined) + Reflect.set(this, 'isSessionReused', () => false) + } + } + + public emit(event: string | symbol, ...args: any[]): boolean { + const emitEvent = super.emit.bind(this, event as any, ...args) + + if (this.responseListenersPromise) { + this.responseListenersPromise.finally(emitEvent) + return this.listenerCount(event) > 0 + } + + return emitEvent() + } + + public destroy(error?: Error | undefined): this { + // Destroy the response parser when the socket gets destroyed. + // Normally, we shoud listen to the "close" event but it + // can be suppressed by using the "emitClose: false" option. + this.responseParser.free() + + if (error) { + this.emit('error', error) + } + + return super.destroy(error) + } + + /** + * Establish this Socket connection as-is and pipe + * its data/events through this Socket. + */ + public passthrough(): void { + this.socketState = 'passthrough' + + if (this.destroyed) { + return + } + + const socket = this.createConnection() + this.originalSocket = socket + + // If the developer destroys the socket, destroy the original connection. + this.once('error', (error) => { + socket.destroy(error) + }) + + this.address = socket.address.bind(socket) + + // Flush the buffered "socket.write()" calls onto + // the original socket instance (i.e. write request body). + // Exhaust the "requestBuffer" in case this Socket + // gets reused for different requests. + let writeArgs: NormalizedSocketWriteArgs | undefined + let headersWritten = false + + while ((writeArgs = this.writeBuffer.shift())) { + if (writeArgs !== undefined) { + if (!headersWritten) { + const [chunk, encoding, callback] = writeArgs + const chunkString = chunk.toString() + const chunkBeforeRequestHeaders = chunkString.slice( + 0, + chunkString.indexOf('\r\n') + 2 + ) + const chunkAfterRequestHeaders = chunkString.slice( + chunk.indexOf('\r\n\r\n') + ) + const rawRequestHeaders = getRawFetchHeaders(this.request!.headers) + const requestHeadersString = rawRequestHeaders + // Skip the internal request ID deduplication header. + .filter(([name]) => { + return name.toLowerCase() !== INTERNAL_REQUEST_ID_HEADER_NAME + }) + .map(([name, value]) => `${name}: ${value}`) + .join('\r\n') + + // Modify the HTTP request message headers + // to reflect any changes to the request headers + // from the "request" event listener. + const headersChunk = `${chunkBeforeRequestHeaders}${requestHeadersString}${chunkAfterRequestHeaders}` + socket.write(headersChunk, encoding, callback) + headersWritten = true + continue + } + + socket.write(...writeArgs) + } + } + + // Forward TLS Socket properties onto this Socket instance + // in the case of a TLS/SSL connection. + if (Reflect.get(socket, 'encrypted')) { + const tlsProperties = [ + 'encrypted', + 'authorized', + 'getProtocol', + 'getSession', + 'isSessionReused', + ] + + tlsProperties.forEach((propertyName) => { + Object.defineProperty(this, propertyName, { + enumerable: true, + get: () => { + const value = Reflect.get(socket, propertyName) + return typeof value === 'function' ? value.bind(socket) : value + }, + }) + }) + } + + socket + .on('lookup', (...args) => this.emit('lookup', ...args)) + .on('connect', () => { + this.connecting = socket.connecting + this.emit('connect') + }) + .on('secureConnect', () => this.emit('secureConnect')) + .on('secure', () => this.emit('secure')) + .on('session', (session) => this.emit('session', session)) + .on('ready', () => this.emit('ready')) + .on('drain', () => this.emit('drain')) + .on('data', (chunk) => { + // Push the original response to this socket + // so it triggers the HTTP response parser. This unifies + // the handling pipeline for original and mocked response. + this.push(chunk) + }) + .on('error', (error) => { + Reflect.set(this, '_hadError', Reflect.get(socket, '_hadError')) + this.emit('error', error) + }) + .on('resume', () => this.emit('resume')) + .on('timeout', () => this.emit('timeout')) + .on('prefinish', () => this.emit('prefinish')) + .on('finish', () => this.emit('finish')) + .on('close', (hadError) => this.emit('close', hadError)) + .on('end', () => this.emit('end')) + } + + /** + * Convert the given Fetch API `Response` instance to an + * HTTP message and push it to the socket. + */ + public async respondWith(response: Response): Promise { + // Ignore the mocked response if the socket has been destroyed + // (e.g. aborted or timed out), + if (this.destroyed) { + return + } + + // Handle "type: error" responses. + if (isPropertyAccessible(response, 'type') && response.type === 'error') { + this.errorWith(new TypeError('Network error')) + return + } + + // First, emit all the connection events + // to emulate a successful connection. + this.mockConnect() + this.socketState = 'mock' + + // Flush the write buffer to trigger write callbacks + // if it hasn't been flushed already (e.g. someone started reading request stream). + this.flushWriteBuffer() + + // Create a `ServerResponse` instance to delegate HTTP message parsing, + // Transfer-Encoding, and other things to Node.js internals. + const serverResponse = new ServerResponse(new IncomingMessage(this)) + + /** + * Assign a mock socket instance to the server response to + * spy on the response chunk writes. Push the transformed response chunks + * to this `MockHttpSocket` instance to trigger the "data" event. + * @note Providing the same `MockSocket` instance when creating `ServerResponse` + * does not have the same effect. + * @see https://github.com/nodejs/node/blob/10099bb3f7fd97bb9dd9667188426866b3098e07/test/parallel/test-http-server-response-standalone.js#L32 + */ + serverResponse.assignSocket( + new MockSocket({ + write: (chunk, encoding, callback) => { + this.push(chunk, encoding) + callback?.() + }, + read() {}, + }) + ) + + /** + * @note Remove the `Connection` and `Date` response headers + * injected by `ServerResponse` by default. Those are required + * from the server but the interceptor is NOT technically a server. + * It's confusing to add response headers that the developer didn't + * specify themselves. They can always add these if they wish. + * @see https://www.rfc-editor.org/rfc/rfc9110#field.date + * @see https://www.rfc-editor.org/rfc/rfc9110#field.connection + */ + serverResponse.removeHeader('connection') + serverResponse.removeHeader('date') + + const rawResponseHeaders = getRawFetchHeaders(response.headers) + + /** + * @note Call `.writeHead` in order to set the raw response headers + * in the same case as they were provided by the developer. Using + * `.setHeader()`/`.appendHeader()` normalizes header names. + */ + serverResponse.writeHead( + response.status, + response.statusText || STATUS_CODES[response.status], + rawResponseHeaders + ) + + // If the developer destroy the socket, gracefully destroy the response. + this.once('error', () => { + serverResponse.destroy() + }) + + if (response.body) { + try { + const reader = response.body.getReader() + + while (true) { + const { done, value } = await reader.read() + + if (done) { + serverResponse.end() + break + } + + serverResponse.write(value) + } + } catch (error) { + // Coerce response stream errors to 500 responses. + this.respondWith(createServerErrorResponse(error)) + return + } + } else { + serverResponse.end() + } + + // Close the socket if the connection wasn't marked as keep-alive. + if (!this.shouldKeepAlive) { + this.emit('readable') + + /** + * @todo @fixme This is likely a hack. + * Since we push null to the socket, it never propagates to the + * parser, and the parser never calls "onResponseEnd" to close + * the response stream. We are closing the stream here manually + * but that shouldn't be the case. + */ + this.responseStream?.push(null) + this.push(null) + } + } + + /** + * Close this socket connection with the given error. + */ + public errorWith(error?: Error): void { + this.destroy(error) + } + + private mockConnect(): void { + // Calling this method immediately puts the socket + // into the connected state. + this.connecting = false + + const isIPv6 = + net.isIPv6(this.connectionOptions.hostname) || + this.connectionOptions.family === 6 + const addressInfo = { + address: isIPv6 ? '::1' : '127.0.0.1', + family: isIPv6 ? 'IPv6' : 'IPv4', + port: this.connectionOptions.port, + } + // Return fake address information for the socket. + this.address = () => addressInfo + this.emit( + 'lookup', + null, + addressInfo.address, + addressInfo.family === 'IPv6' ? 6 : 4, + this.connectionOptions.host + ) + this.emit('connect') + this.emit('ready') + + if (this.baseUrl.protocol === 'https:') { + this.emit('secure') + this.emit('secureConnect') + + // A single TLS connection is represented by two "session" events. + this.emit( + 'session', + this.connectionOptions.session || + Buffer.from('mock-session-renegotiate') + ) + this.emit('session', Buffer.from('mock-session-resume')) + } + } + + private flushWriteBuffer(): void { + for (const writeCall of this.writeBuffer) { + if (typeof writeCall[2] === 'function') { + writeCall[2]() + /** + * @note Remove the callback from the write call + * so it doesn't get called twice on passthrough + * if `request.end()` was called within `request.write()`. + * @see https://github.com/mswjs/interceptors/issues/684 + */ + writeCall[2] = undefined + } + } + } + + private onRequestStart: RequestHeadersCompleteCallback = ( + versionMajor, + versionMinor, + rawHeaders, + _, + path, + __, + ___, + ____, + shouldKeepAlive + ) => { + this.shouldKeepAlive = shouldKeepAlive + + const url = new URL(path, this.baseUrl) + const method = this.connectionOptions.method?.toUpperCase() || 'GET' + const headers = FetchResponse.parseRawHeaders(rawHeaders) + const canHaveBody = method !== 'GET' && method !== 'HEAD' + + // Translate the basic authorization in the URL to the request header. + // Constructing a Request instance with a URL containing auth is no-op. + if (url.username || url.password) { + if (!headers.has('authorization')) { + headers.set('authorization', `Basic ${url.username}:${url.password}`) + } + url.username = '' + url.password = '' + } + + // Create a new stream for each request. + // If this Socket is reused for multiple requests, + // this ensures that each request gets its own stream. + // One Socket instance can only handle one request at a time. + if (canHaveBody) { + this.requestStream = new Readable({ + /** + * @note Provide the `read()` method so a `Readable` could be + * used as the actual request body (the stream calls "read()"). + * We control the queue in the onRequestBody/End functions. + */ + read: () => { + // If the user attempts to read the request body, + // flush the write buffer to trigger the callbacks. + // This way, if the request stream ends in the write callback, + // it will indeed end correctly. + this.flushWriteBuffer() + }, + }) + } + + const requestId = createRequestId() + this.request = new Request(url, { + method, + headers, + credentials: 'same-origin', + // @ts-expect-error Undocumented Fetch property. + duplex: canHaveBody ? 'half' : undefined, + body: canHaveBody ? (Readable.toWeb(this.requestStream!) as any) : null, + }) + + Reflect.set(this.request, kRequestId, requestId) + + // Skip handling the request that's already being handled + // by another (parent) interceptor. For example, XMLHttpRequest + // is often implemented via ClientRequest in Node.js (e.g. JSDOM). + // In that case, XHR interceptor will bubble down to the ClientRequest + // interceptor. No need to try to handle that request again. + /** + * @fixme Stop relying on the "X-Request-Id" request header + * to figure out if one interceptor has been invoked within another. + * @see https://github.com/mswjs/interceptors/issues/378 + */ + if (this.request.headers.has(INTERNAL_REQUEST_ID_HEADER_NAME)) { + this.passthrough() + return + } + + this.onRequest({ + requestId, + request: this.request, + socket: this, + }) + } + + private onRequestBody(chunk: Buffer): void { + invariant( + this.requestStream, + 'Failed to write to a request stream: stream does not exist' + ) + + this.requestStream.push(chunk) + } + + private onRequestEnd(): void { + // Request end can be called for requests without body. + if (this.requestStream) { + this.requestStream.push(null) + } + } + + private onResponseStart: ResponseHeadersCompleteCallback = ( + versionMajor, + versionMinor, + rawHeaders, + method, + url, + status, + statusText + ) => { + const headers = FetchResponse.parseRawHeaders(rawHeaders) + + const response = new FetchResponse( + /** + * @note The Fetch API response instance exposed to the consumer + * is created over the response stream of the HTTP parser. It is NOT + * related to the Socket instance. This way, you can read response body + * in response listener while the Socket instance delays the emission + * of "end" and other events until those response listeners are finished. + */ + FetchResponse.isResponseWithBody(status) + ? (Readable.toWeb( + (this.responseStream = new Readable({ read() {} })) + ) as any) + : null, + { + url, + status, + statusText, + headers, + } + ) + + invariant( + this.request, + 'Failed to handle a response: request does not exist' + ) + + /** + * @fixme Stop relying on the "X-Request-Id" request header + * to figure out if one interceptor has been invoked within another. + * @see https://github.com/mswjs/interceptors/issues/378 + */ + if (this.request.headers.has(INTERNAL_REQUEST_ID_HEADER_NAME)) { + return + } + + this.responseListenersPromise = this.onResponse({ + response, + isMockedResponse: this.socketState === 'mock', + requestId: Reflect.get(this.request, kRequestId), + request: this.request, + socket: this, + }) + } + + private onResponseBody(chunk: Buffer) { + invariant( + this.responseStream, + 'Failed to write to a response stream: stream does not exist' + ) + + this.responseStream.push(chunk) + } + + private onResponseEnd(): void { + // Response end can be called for responses without body. + if (this.responseStream) { + this.responseStream.push(null) + } + } +} diff --git a/node_modules/@mswjs/interceptors/src/interceptors/ClientRequest/agents.ts b/node_modules/@mswjs/interceptors/src/interceptors/ClientRequest/agents.ts new file mode 100644 index 0000000000000000000000000000000000000000..917ca1706cd0bc5300c9a2292019ac5a6dc9be4c --- /dev/null +++ b/node_modules/@mswjs/interceptors/src/interceptors/ClientRequest/agents.ts @@ -0,0 +1,103 @@ +import net from 'node:net' +import http from 'node:http' +import https from 'node:https' +import { + MockHttpSocket, + type MockHttpSocketRequestCallback, + type MockHttpSocketResponseCallback, +} from './MockHttpSocket' + +declare module 'node:http' { + interface Agent { + options?: http.AgentOptions + createConnection(options: any, callback: any): net.Socket + } +} + +interface MockAgentOptions { + customAgent?: http.RequestOptions['agent'] + onRequest: MockHttpSocketRequestCallback + onResponse: MockHttpSocketResponseCallback +} + +export class MockAgent extends http.Agent { + private customAgent?: http.RequestOptions['agent'] + private onRequest: MockHttpSocketRequestCallback + private onResponse: MockHttpSocketResponseCallback + + constructor(options: MockAgentOptions) { + super() + this.customAgent = options.customAgent + this.onRequest = options.onRequest + this.onResponse = options.onResponse + } + + public createConnection(options: any, callback: any): net.Socket { + const createConnection = + this.customAgent instanceof http.Agent + ? this.customAgent.createConnection + : super.createConnection + + const createConnectionOptions = + this.customAgent instanceof http.Agent + ? { + ...options, + ...this.customAgent.options, + } + : options + + const socket = new MockHttpSocket({ + connectionOptions: options, + createConnection: createConnection.bind( + this.customAgent || this, + createConnectionOptions, + callback + ), + onRequest: this.onRequest.bind(this), + onResponse: this.onResponse.bind(this), + }) + + return socket + } +} + +export class MockHttpsAgent extends https.Agent { + private customAgent?: https.RequestOptions['agent'] + private onRequest: MockHttpSocketRequestCallback + private onResponse: MockHttpSocketResponseCallback + + constructor(options: MockAgentOptions) { + super() + this.customAgent = options.customAgent + this.onRequest = options.onRequest + this.onResponse = options.onResponse + } + + public createConnection(options: any, callback: any): net.Socket { + const createConnection = + this.customAgent instanceof https.Agent + ? this.customAgent.createConnection + : super.createConnection + + const createConnectionOptions = + this.customAgent instanceof https.Agent + ? { + ...options, + ...this.customAgent.options, + } + : options + + const socket = new MockHttpSocket({ + connectionOptions: options, + createConnection: createConnection.bind( + this.customAgent || this, + createConnectionOptions, + callback + ), + onRequest: this.onRequest.bind(this), + onResponse: this.onResponse.bind(this), + }) + + return socket + } +} diff --git a/node_modules/@mswjs/interceptors/src/interceptors/ClientRequest/index.test.ts b/node_modules/@mswjs/interceptors/src/interceptors/ClientRequest/index.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..98539017d01f8e706e501401f16cb8e45dfb1dcc --- /dev/null +++ b/node_modules/@mswjs/interceptors/src/interceptors/ClientRequest/index.test.ts @@ -0,0 +1,75 @@ +import { it, expect, beforeAll, afterEach, afterAll } from 'vitest' +import http from 'node:http' +import { HttpServer } from '@open-draft/test-server/http' +import { DeferredPromise } from '@open-draft/deferred-promise' +import { ClientRequestInterceptor } from '.' +import { sleep, waitForClientRequest } from '../../../test/helpers' + +const httpServer = new HttpServer((app) => { + app.get('/', (_req, res) => { + res.status(200).send('/') + }) + app.get('/get', (_req, res) => { + res.status(200).send('/get') + }) +}) + +const interceptor = new ClientRequestInterceptor() + +beforeAll(async () => { + interceptor.apply() + await httpServer.listen() +}) + +afterEach(() => { + interceptor.removeAllListeners() +}) + +afterAll(async () => { + interceptor.dispose() + await httpServer.close() +}) + +it('abort the request if the abort signal is emitted', async () => { + const requestUrl = httpServer.http.url('/') + + interceptor.on('request', async function delayedResponse({ controller }) { + await sleep(1_000) + controller.respondWith(new Response()) + }) + + const abortController = new AbortController() + const request = http.get(requestUrl, { signal: abortController.signal }) + + abortController.abort() + + const abortErrorPromise = new DeferredPromise() + request.on('error', function (error) { + abortErrorPromise.resolve(error) + }) + + const abortError = await abortErrorPromise + expect(abortError.name).toEqual('AbortError') + + expect(request.destroyed).toBe(true) +}) + +it('patch the Headers object correctly after dispose and reapply', async () => { + interceptor.dispose() + interceptor.apply() + + interceptor.on('request', ({ controller }) => { + const headers = new Headers({ + 'X-CustoM-HeadeR': 'Yes', + }) + controller.respondWith(new Response(null, { headers })) + }) + + const request = http.get(httpServer.http.url('/')) + const { res } = await waitForClientRequest(request) + + expect(res.rawHeaders).toEqual( + expect.arrayContaining(['X-CustoM-HeadeR', 'Yes']) + ) + expect(res.headers['x-custom-header']).toEqual('Yes') +}) diff --git a/node_modules/@mswjs/interceptors/src/interceptors/ClientRequest/index.ts b/node_modules/@mswjs/interceptors/src/interceptors/ClientRequest/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..c5dac7a33e373f1e758bcf2b2c8e4a20ef33c771 --- /dev/null +++ b/node_modules/@mswjs/interceptors/src/interceptors/ClientRequest/index.ts @@ -0,0 +1,170 @@ +import http from 'node:http' +import https from 'node:https' +import { Interceptor } from '../../Interceptor' +import type { HttpRequestEventMap } from '../../glossary' +import { + kRequestId, + MockHttpSocketRequestCallback, + MockHttpSocketResponseCallback, +} from './MockHttpSocket' +import { MockAgent, MockHttpsAgent } from './agents' +import { RequestController } from '../../RequestController' +import { emitAsync } from '../../utils/emitAsync' +import { normalizeClientRequestArgs } from './utils/normalizeClientRequestArgs' +import { handleRequest } from '../../utils/handleRequest' +import { + recordRawFetchHeaders, + restoreHeadersPrototype, +} from './utils/recordRawHeaders' + +export class ClientRequestInterceptor extends Interceptor { + static symbol = Symbol('client-request-interceptor') + + constructor() { + super(ClientRequestInterceptor.symbol) + } + + protected setup(): void { + const { get: originalGet, request: originalRequest } = http + const { get: originalHttpsGet, request: originalHttpsRequest } = https + + const onRequest = this.onRequest.bind(this) + const onResponse = this.onResponse.bind(this) + + http.request = new Proxy(http.request, { + apply: (target, thisArg, args: Parameters) => { + const [url, options, callback] = normalizeClientRequestArgs( + 'http:', + args + ) + const mockAgent = new MockAgent({ + customAgent: options.agent, + onRequest, + onResponse, + }) + options.agent = mockAgent + + return Reflect.apply(target, thisArg, [url, options, callback]) + }, + }) + + http.get = new Proxy(http.get, { + apply: (target, thisArg, args: Parameters) => { + const [url, options, callback] = normalizeClientRequestArgs( + 'http:', + args + ) + + const mockAgent = new MockAgent({ + customAgent: options.agent, + onRequest, + onResponse, + }) + options.agent = mockAgent + + return Reflect.apply(target, thisArg, [url, options, callback]) + }, + }) + + // + // HTTPS. + // + + https.request = new Proxy(https.request, { + apply: (target, thisArg, args: Parameters) => { + const [url, options, callback] = normalizeClientRequestArgs( + 'https:', + args + ) + + const mockAgent = new MockHttpsAgent({ + customAgent: options.agent, + onRequest, + onResponse, + }) + options.agent = mockAgent + + return Reflect.apply(target, thisArg, [url, options, callback]) + }, + }) + + https.get = new Proxy(https.get, { + apply: (target, thisArg, args: Parameters) => { + const [url, options, callback] = normalizeClientRequestArgs( + 'https:', + args + ) + + const mockAgent = new MockHttpsAgent({ + customAgent: options.agent, + onRequest, + onResponse, + }) + options.agent = mockAgent + + return Reflect.apply(target, thisArg, [url, options, callback]) + }, + }) + + // Spy on `Header.prototype.set` and `Header.prototype.append` calls + // and record the raw header names provided. This is to support + // `IncomingMessage.prototype.rawHeaders`. + recordRawFetchHeaders() + + this.subscriptions.push(() => { + http.get = originalGet + http.request = originalRequest + + https.get = originalHttpsGet + https.request = originalHttpsRequest + + restoreHeadersPrototype() + }) + } + + private onRequest: MockHttpSocketRequestCallback = async ({ + request, + socket, + }) => { + const requestId = Reflect.get(request, kRequestId) + const controller = new RequestController(request) + + const isRequestHandled = await handleRequest({ + request, + requestId, + controller, + emitter: this.emitter, + onResponse: (response) => { + socket.respondWith(response) + }, + onRequestError: (response) => { + socket.respondWith(response) + }, + onError: (error) => { + if (error instanceof Error) { + socket.errorWith(error) + } + }, + }) + + if (!isRequestHandled) { + return socket.passthrough() + } + } + + public onResponse: MockHttpSocketResponseCallback = async ({ + requestId, + request, + response, + isMockedResponse, + }) => { + // Return the promise to when all the response event listeners + // are finished. + return emitAsync(this.emitter, 'response', { + requestId, + request, + response, + isMockedResponse, + }) + } +} diff --git a/node_modules/@mswjs/interceptors/src/interceptors/ClientRequest/utils/getIncomingMessageBody.test.ts b/node_modules/@mswjs/interceptors/src/interceptors/ClientRequest/utils/getIncomingMessageBody.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..314120c3261c418fcce24a8ac5a43c00704479a8 --- /dev/null +++ b/node_modules/@mswjs/interceptors/src/interceptors/ClientRequest/utils/getIncomingMessageBody.test.ts @@ -0,0 +1,54 @@ +import { it, expect } from 'vitest' +import { IncomingMessage } from 'http' +import { Socket } from 'net' +import * as zlib from 'zlib' +import { getIncomingMessageBody } from './getIncomingMessageBody' + +it('returns utf8 string given a utf8 response body', async () => { + const utfBuffer = Buffer.from('one') + const message = new IncomingMessage(new Socket()) + + const pendingResponseBody = getIncomingMessageBody(message) + message.emit('data', utfBuffer) + message.emit('end') + + expect(await pendingResponseBody).toEqual('one') +}) + +it('returns utf8 string given a gzipped response body', async () => { + const utfBuffer = zlib.gzipSync(Buffer.from('two')) + const message = new IncomingMessage(new Socket()) + message.headers = { + 'content-encoding': 'gzip', + } + + const pendingResponseBody = getIncomingMessageBody(message) + message.emit('data', utfBuffer) + message.emit('end') + + expect(await pendingResponseBody).toEqual('two') +}) + +it('returns utf8 string given a gzipped response body with incorrect "content-lenght"', async () => { + const utfBuffer = zlib.gzipSync(Buffer.from('three')) + const message = new IncomingMessage(new Socket()) + message.headers = { + 'content-encoding': 'gzip', + 'content-length': '500', + } + + const pendingResponseBody = getIncomingMessageBody(message) + message.emit('data', utfBuffer) + message.emit('end') + + expect(await pendingResponseBody).toEqual('three') +}) + +it('returns empty string given an empty body', async () => { + const message = new IncomingMessage(new Socket()) + + const pendingResponseBody = getIncomingMessageBody(message) + message.emit('end') + + expect(await pendingResponseBody).toEqual('') +}) diff --git a/node_modules/@mswjs/interceptors/src/interceptors/ClientRequest/utils/getIncomingMessageBody.ts b/node_modules/@mswjs/interceptors/src/interceptors/ClientRequest/utils/getIncomingMessageBody.ts new file mode 100644 index 0000000000000000000000000000000000000000..563e55259706b93213f1232e8e1165256cb58ca3 --- /dev/null +++ b/node_modules/@mswjs/interceptors/src/interceptors/ClientRequest/utils/getIncomingMessageBody.ts @@ -0,0 +1,45 @@ +import { IncomingMessage } from 'http' +import { PassThrough } from 'stream' +import * as zlib from 'zlib' +import { Logger } from '@open-draft/logger' + +const logger = new Logger('http getIncomingMessageBody') + +export function getIncomingMessageBody( + response: IncomingMessage +): Promise { + return new Promise((resolve, reject) => { + logger.info('cloning the original response...') + + // Pipe the original response to support non-clone + // "response" input. No need to clone the response, + // as we always have access to the full "response" input, + // either a clone or an original one (in tests). + const responseClone = response.pipe(new PassThrough()) + const stream = + response.headers['content-encoding'] === 'gzip' + ? responseClone.pipe(zlib.createGunzip()) + : responseClone + + const encoding = response.readableEncoding || 'utf8' + stream.setEncoding(encoding) + logger.info('using encoding:', encoding) + + let body = '' + + stream.on('data', (responseBody) => { + logger.info('response body read:', responseBody) + body += responseBody + }) + + stream.once('end', () => { + logger.info('response body end') + resolve(body) + }) + + stream.once('error', (error) => { + logger.info('error while reading response body:', error) + reject(error) + }) + }) +} diff --git a/node_modules/@mswjs/interceptors/src/interceptors/ClientRequest/utils/normalizeClientRequestArgs.test.ts b/node_modules/@mswjs/interceptors/src/interceptors/ClientRequest/utils/normalizeClientRequestArgs.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..71e1e9ce81807a768b4c5083383ba10bca7441a7 --- /dev/null +++ b/node_modules/@mswjs/interceptors/src/interceptors/ClientRequest/utils/normalizeClientRequestArgs.test.ts @@ -0,0 +1,491 @@ +import { it, expect } from 'vitest' +import { parse } from 'url' +import { globalAgent as httpGlobalAgent, RequestOptions } from 'http' +import { Agent as HttpsAgent, globalAgent as httpsGlobalAgent } from 'https' +import { getUrlByRequestOptions } from '../../../utils/getUrlByRequestOptions' +import { normalizeClientRequestArgs } from './normalizeClientRequestArgs' + +it('handles [string, callback] input', () => { + const [url, options, callback] = normalizeClientRequestArgs('https:', [ + 'https://mswjs.io/resource', + function cb() {}, + ]) + + // URL string must be converted to a URL instance. + expect(url.href).toEqual('https://mswjs.io/resource') + + // Request options must be derived from the URL instance. + expect(options).toHaveProperty('method', 'GET') + expect(options).toHaveProperty('protocol', 'https:') + expect(options).toHaveProperty('hostname', 'mswjs.io') + expect(options).toHaveProperty('path', '/resource') + + // Callback must be preserved. + expect(callback?.name).toEqual('cb') +}) + +it('handles [string, RequestOptions, callback] input', () => { + const initialOptions = { + headers: { + 'Content-Type': 'text/plain', + }, + } + const [url, options, callback] = normalizeClientRequestArgs('https:', [ + 'https://mswjs.io/resource', + initialOptions, + function cb() {}, + ]) + + // URL must be created from the string. + expect(url.href).toEqual('https://mswjs.io/resource') + + // Request options must be preserved. + expect(options).toHaveProperty('headers', initialOptions.headers) + + // Callback must be preserved. + expect(callback?.name).toEqual('cb') +}) + +it('handles [URL, callback] input', () => { + const [url, options, callback] = normalizeClientRequestArgs('https:', [ + new URL('https://mswjs.io/resource'), + function cb() {}, + ]) + + // URL must be preserved. + expect(url.href).toEqual('https://mswjs.io/resource') + + // Request options must be derived from the URL instance. + expect(options.method).toEqual('GET') + expect(options.protocol).toEqual('https:') + expect(options.hostname).toEqual('mswjs.io') + expect(options.path).toEqual('/resource') + + // Callback must be preserved. + expect(callback?.name).toEqual('cb') +}) + +it('handles [Absolute Legacy URL, callback] input', () => { + const [url, options, callback] = normalizeClientRequestArgs('https:', [ + parse('https://cherry:durian@mswjs.io:12345/resource?apple=banana'), + function cb() {}, + ]) + + // URL must be preserved. + expect(url.toJSON()).toEqual( + new URL( + 'https://cherry:durian@mswjs.io:12345/resource?apple=banana' + ).toJSON() + ) + + // Request options must be derived from the URL instance. + expect(options.method).toEqual('GET') + expect(options.protocol).toEqual('https:') + expect(options.hostname).toEqual('mswjs.io') + expect(options.path).toEqual('/resource?apple=banana') + expect(options.port).toEqual(12345) + expect(options.auth).toEqual('cherry:durian') + + // Callback must be preserved. + expect(callback?.name).toEqual('cb') +}) + +it('handles [Relative Legacy URL, RequestOptions without path set, callback] input', () => { + const [url, options, callback] = normalizeClientRequestArgs('http:', [ + parse('/resource?apple=banana'), + { host: 'mswjs.io' }, + function cb() {}, + ]) + + // Correct WHATWG URL generated. + expect(url.toJSON()).toEqual( + new URL('http://mswjs.io/resource?apple=banana').toJSON() + ) + + // No path in request options, so legacy url path is copied-in. + expect(options.protocol).toEqual('http:') + expect(options.host).toEqual('mswjs.io') + expect(options.path).toEqual('/resource?apple=banana') + + // Callback must be preserved. + expect(callback?.name).toEqual('cb') +}) + +it('handles [Relative Legacy URL, RequestOptions with path set, callback] input', () => { + const [url, options, callback] = normalizeClientRequestArgs('http:', [ + parse('/resource?apple=banana'), + { host: 'mswjs.io', path: '/other?cherry=durian' }, + function cb() {}, + ]) + + // Correct WHATWG URL generated. + expect(url.toJSON()).toEqual( + new URL('http://mswjs.io/other?cherry=durian').toJSON() + ) + + // Path in request options, so that path is preferred. + expect(options.protocol).toEqual('http:') + expect(options.host).toEqual('mswjs.io') + expect(options.path).toEqual('/other?cherry=durian') + + // Callback must be preserved. + expect(callback?.name).toEqual('cb') +}) + +it('handles [Relative Legacy URL, callback] input', () => { + const [url, options, callback] = normalizeClientRequestArgs('http:', [ + parse('/resource?apple=banana'), + function cb() {}, + ]) + + // Correct WHATWG URL generated. + expect(url.toJSON()).toMatch( + getUrlByRequestOptions({ path: '/resource?apple=banana' }).toJSON() + ) + + // Check path is in options. + expect(options.protocol).toEqual('http:') + expect(options.path).toEqual('/resource?apple=banana') + + // Callback must be preserved. + expect(callback).toBeTypeOf('function') + expect(callback?.name).toEqual('cb') +}) + +it('handles [Relative Legacy URL] input', () => { + const [url, options, callback] = normalizeClientRequestArgs('http:', [ + parse('/resource?apple=banana'), + ]) + + // Correct WHATWG URL generated. + expect(url.toJSON()).toMatch( + getUrlByRequestOptions({ path: '/resource?apple=banana' }).toJSON() + ) + + // Check path is in options. + expect(options.protocol).toEqual('http:') + expect(options.path).toEqual('/resource?apple=banana') + + // Callback must be preserved. + expect(callback).toBeUndefined() +}) + +it('handles [URL, RequestOptions, callback] input', () => { + const [url, options, callback] = normalizeClientRequestArgs('https:', [ + new URL('https://mswjs.io/resource'), + { + agent: false, + headers: { + 'Content-Type': 'text/plain', + }, + }, + function cb() {}, + ]) + + // URL must be preserved. + expect(url.href).toEqual('https://mswjs.io/resource') + + // Options must be preserved. + // `urlToHttpOptions` from `node:url` generates additional + // ClientRequest options, some of which are not legally allowed. + expect(options).toMatchObject({ + agent: false, + _defaultAgent: httpsGlobalAgent, + protocol: url.protocol, + method: 'GET', + headers: { + 'Content-Type': 'text/plain', + }, + hostname: url.hostname, + path: url.pathname, + }) + + // Callback must be preserved. + expect(callback).toBeTypeOf('function') + expect(callback?.name).toEqual('cb') +}) + +it('handles [URL, RequestOptions] where options have custom "hostname"', () => { + const [url, options] = normalizeClientRequestArgs('http:', [ + new URL('http://example.com/path-from-url'), + { + hostname: 'host-from-options.com', + }, + ]) + expect(url.href).toBe('http://host-from-options.com/path-from-url') + expect(options).toMatchObject({ + hostname: 'host-from-options.com', + path: '/path-from-url', + }) +}) + +it('handles [URL, RequestOptions] where options contain "host" and "path" and "port"', () => { + const [url, options] = normalizeClientRequestArgs('http:', [ + new URL('http://example.com/path-from-url?a=b&c=d'), + { + hostname: 'host-from-options.com', + path: '/path-from-options', + port: 1234, + }, + ]) + // Must remove the query string since it's not specified in "options.path" + expect(url.href).toBe('http://host-from-options.com:1234/path-from-options') + expect(options).toMatchObject({ + hostname: 'host-from-options.com', + path: '/path-from-options', + port: 1234, + }) +}) + +it('handles [URL, RequestOptions] where options contain "path" with query string', () => { + const [url, options] = normalizeClientRequestArgs('http:', [ + new URL('http://example.com/path-from-url?a=b&c=d'), + { + path: '/path-from-options?foo=bar&baz=xyz', + }, + ]) + expect(url.href).toBe('http://example.com/path-from-options?foo=bar&baz=xyz') + expect(options).toMatchObject({ + hostname: 'example.com', + path: '/path-from-options?foo=bar&baz=xyz', + }) +}) + +it('handles [RequestOptions, callback] input', () => { + const initialOptions = { + method: 'POST', + protocol: 'https:', + host: 'mswjs.io', + /** + * @see https://github.com/mswjs/msw/issues/705 + */ + origin: 'https://mswjs.io', + path: '/resource', + headers: { + 'Content-Type': 'text/plain', + }, + } + const [url, options, callback] = normalizeClientRequestArgs('https:', [ + initialOptions, + function cb() {}, + ]) + + // URL must be derived from request options. + expect(url.href).toEqual('https://mswjs.io/resource') + + // Request options must be preserved. + expect(options).toMatchObject(initialOptions) + + // Callback must be preserved. + expect(callback).toBeTypeOf('function') + expect(callback?.name).toEqual('cb') +}) + +it('handles [Empty RequestOptions, callback] input', () => { + const [_, options, callback] = normalizeClientRequestArgs('https:', [ + {}, + function cb() {}, + ]) + + expect(options.protocol).toEqual('https:') + + // Callback must be preserved + expect(callback?.name).toEqual('cb') +}) + +/** + * @see https://github.com/mswjs/interceptors/issues/19 + */ +it('handles [PartialRequestOptions, callback] input', () => { + const initialOptions = { + method: 'GET', + port: '50176', + path: '/resource', + host: '127.0.0.1', + ca: undefined, + key: undefined, + pfx: undefined, + cert: undefined, + passphrase: undefined, + agent: false, + } + const [url, options, callback] = normalizeClientRequestArgs('https:', [ + initialOptions, + function cb() {}, + ]) + + // URL must be derived from request options. + expect(url.toJSON()).toEqual( + new URL('https://127.0.0.1:50176/resource').toJSON() + ) + + // Request options must be preserved. + expect(options).toMatchObject(initialOptions) + + // Options protocol must be inferred from the request issuing module. + expect(options.protocol).toEqual('https:') + + // Callback must be preserved. + expect(callback).toBeTypeOf('function') + expect(callback?.name).toEqual('cb') +}) + +it('sets fallback Agent based on the URL protocol', () => { + const [url, options] = normalizeClientRequestArgs('https:', [ + 'https://github.com', + ]) + const agent = options.agent as HttpsAgent + + expect(agent).toBeInstanceOf(HttpsAgent) + expect(agent).toHaveProperty('defaultPort', 443) + expect(agent).toHaveProperty('protocol', url.protocol) +}) + +it('preserves `requestUnauthorized` option set to undefined', () => { + const [, options] = normalizeClientRequestArgs('https:', [ + 'https://github.com', + { rejectUnauthorized: undefined }, + ]) + + expect(options.rejectUnauthorized).toBe(undefined) + expect((options.agent as HttpsAgent).options.rejectUnauthorized).toBe( + undefined + ) +}) + +it('preserves `requestUnauthorized` option set to true', () => { + const [, options] = normalizeClientRequestArgs('https:', [ + 'https://github.com', + { rejectUnauthorized: true }, + ]) + + expect(options.rejectUnauthorized).toBe(true) + expect((options.agent as HttpsAgent).options.rejectUnauthorized).toBe(true) +}) + +it('preserves `requestUnauthorized` option set to false', () => { + const [, options] = normalizeClientRequestArgs('https:', [ + 'https://github.com', + { rejectUnauthorized: false }, + ]) + + expect(options.rejectUnauthorized).toBe(false) + expect((options.agent as HttpsAgent).options.rejectUnauthorized).toBe(false) +}) + +it('does not add `rejectUnauthorized` value if not set', () => { + const agent = new HttpsAgent() + const [, options] = normalizeClientRequestArgs('https:', [ + 'https://github.com', + ]) + + expect(options).not.toHaveProperty('rejectUnauthorized') + expect((options.agent as HttpsAgent).options).not.toHaveProperty( + 'rejectUnauthorized' + ) +}) + +it('does not set any fallback Agent given "agent: false" option', () => { + const [, options] = normalizeClientRequestArgs('https:', [ + 'https://github.com', + { agent: false }, + ]) + + expect(options.agent).toEqual(false) +}) + +it('sets the default Agent for HTTP request', () => { + const [, options] = normalizeClientRequestArgs('http:', [ + 'http://github.com', + {}, + ]) + + expect(options._defaultAgent).toEqual(httpGlobalAgent) +}) + +it('sets the default Agent for HTTPS request', () => { + const [, options] = normalizeClientRequestArgs('https:', [ + 'https://github.com', + {}, + ]) + + expect(options._defaultAgent).toEqual(httpsGlobalAgent) +}) + +it('preserves a custom default Agent when set', () => { + const [, options] = normalizeClientRequestArgs('https:', [ + 'https://github.com', + { + /** + * @note Intentionally incorrect Agent for HTTPS request. + */ + _defaultAgent: httpGlobalAgent, + }, + ]) + + expect(options._defaultAgent).toEqual(httpGlobalAgent) +}) + +it('merges URL-based RequestOptions with the custom RequestOptions', () => { + const [url, options] = normalizeClientRequestArgs('https:', [ + 'https://github.com/graphql', + { + method: 'GET', + pfx: 'PFX_KEY', + }, + ]) + + expect(url.href).toEqual('https://github.com/graphql') + + // Original request options must be preserved. + expect(options.method).toEqual('GET') + expect(options.pfx).toEqual('PFX_KEY') + + // Other options must be inferred from the URL. + expect(options.protocol).toEqual(url.protocol) + expect(options.hostname).toEqual(url.hostname) + expect(options.path).toEqual(url.pathname) +}) + +it('respects custom "options.path" over URL path', () => { + const [url, options] = normalizeClientRequestArgs('http:', [ + new URL('http://example.com/path-from-url'), + { + path: '/path-from-options', + }, + ]) + + expect(url.href).toBe('http://example.com/path-from-options') + expect(options.protocol).toBe('http:') + expect(options.hostname).toBe('example.com') + expect(options.path).toBe('/path-from-options') +}) + +it('respects custom "options.path" over URL path with query string', () => { + const [url, options] = normalizeClientRequestArgs('http:', [ + new URL('http://example.com/path-from-url?a=b&c=d'), + { + path: '/path-from-options', + }, + ]) + + // Must replace both the path and the query string. + expect(url.href).toBe('http://example.com/path-from-options') + expect(options.protocol).toBe('http:') + expect(options.hostname).toBe('example.com') + expect(options.path).toBe('/path-from-options') +}) + +it('preserves URL query string', () => { + const [url, options] = normalizeClientRequestArgs('http:', [ + new URL('http://example.com:8080/resource?a=b&c=d'), + ]) + + expect(url.href).toBe('http://example.com:8080/resource?a=b&c=d') + expect(options.protocol).toBe('http:') + // expect(options.host).toBe('example.com:8080') + expect(options.hostname).toBe('example.com') + // Query string is a part of the options path. + expect(options.path).toBe('/resource?a=b&c=d') + expect(options.port).toBe(8080) +}) diff --git a/node_modules/@mswjs/interceptors/src/interceptors/ClientRequest/utils/normalizeClientRequestArgs.ts b/node_modules/@mswjs/interceptors/src/interceptors/ClientRequest/utils/normalizeClientRequestArgs.ts new file mode 100644 index 0000000000000000000000000000000000000000..2d13f1879538f7f8229127c9f83951358061cd22 --- /dev/null +++ b/node_modules/@mswjs/interceptors/src/interceptors/ClientRequest/utils/normalizeClientRequestArgs.ts @@ -0,0 +1,291 @@ +import { urlToHttpOptions } from 'node:url' +import { + Agent as HttpAgent, + globalAgent as httpGlobalAgent, + IncomingMessage, +} from 'node:http' +import { + RequestOptions, + Agent as HttpsAgent, + globalAgent as httpsGlobalAgent, +} from 'node:https' +import { + /** + * @note Use the Node.js URL instead of the global URL + * because environments like JSDOM may override the global, + * breaking the compatibility with Node.js. + * @see https://github.com/node-fetch/node-fetch/issues/1376#issuecomment-966435555 + */ + URL, + Url as LegacyURL, + parse as parseUrl, +} from 'node:url' +import { Logger } from '@open-draft/logger' +import { + ResolvedRequestOptions, + getUrlByRequestOptions, +} from '../../../utils/getUrlByRequestOptions' +import { cloneObject } from '../../../utils/cloneObject' +import { isObject } from '../../../utils/isObject' + +const logger = new Logger('http normalizeClientRequestArgs') + +export type HttpRequestCallback = (response: IncomingMessage) => void + +export type ClientRequestArgs = + // Request without any arguments is also possible. + | [] + | [string | URL | LegacyURL, HttpRequestCallback?] + | [string | URL | LegacyURL, RequestOptions, HttpRequestCallback?] + | [RequestOptions, HttpRequestCallback?] + +function resolveRequestOptions( + args: ClientRequestArgs, + url: URL +): RequestOptions { + // Calling `fetch` provides only URL to `ClientRequest` + // without any `RequestOptions` or callback. + if (typeof args[1] === 'undefined' || typeof args[1] === 'function') { + logger.info('request options not provided, deriving from the url', url) + return urlToHttpOptions(url) + } + + if (args[1]) { + logger.info('has custom RequestOptions!', args[1]) + const requestOptionsFromUrl = urlToHttpOptions(url) + + logger.info('derived RequestOptions from the URL:', requestOptionsFromUrl) + + /** + * Clone the request options to lock their state + * at the moment they are provided to `ClientRequest`. + * @see https://github.com/mswjs/interceptors/issues/86 + */ + logger.info('cloning RequestOptions...') + const clonedRequestOptions = cloneObject(args[1]) + logger.info('successfully cloned RequestOptions!', clonedRequestOptions) + + return { + ...requestOptionsFromUrl, + ...clonedRequestOptions, + } + } + + logger.info('using an empty object as request options') + return {} as RequestOptions +} + +/** + * Overrides the given `URL` instance with the explicit properties provided + * on the `RequestOptions` object. The options object takes precedence, + * and will replace URL properties like "host", "path", and "port", if specified. + */ +function overrideUrlByRequestOptions(url: URL, options: RequestOptions): URL { + url.host = options.host || url.host + url.hostname = options.hostname || url.hostname + url.port = options.port ? options.port.toString() : url.port + + if (options.path) { + const parsedOptionsPath = parseUrl(options.path, false) + url.pathname = parsedOptionsPath.pathname || '' + url.search = parsedOptionsPath.search || '' + } + + return url +} + +function resolveCallback( + args: ClientRequestArgs +): HttpRequestCallback | undefined { + return typeof args[1] === 'function' ? args[1] : args[2] +} + +export type NormalizedClientRequestArgs = [ + url: URL, + options: ResolvedRequestOptions, + callback?: HttpRequestCallback +] + +/** + * Normalizes parameters given to a `http.request` call + * so it always has a `URL` and `RequestOptions`. + */ +export function normalizeClientRequestArgs( + defaultProtocol: string, + args: ClientRequestArgs +): NormalizedClientRequestArgs { + let url: URL + let options: ResolvedRequestOptions + let callback: HttpRequestCallback | undefined + + logger.info('arguments', args) + logger.info('using default protocol:', defaultProtocol) + + // Support "http.request()" calls without any arguments. + // That call results in a "GET http://localhost" request. + if (args.length === 0) { + const url = new URL('http://localhost') + const options = resolveRequestOptions(args, url) + return [url, options] + } + + // Convert a url string into a URL instance + // and derive request options from it. + if (typeof args[0] === 'string') { + logger.info('first argument is a location string:', args[0]) + + url = new URL(args[0]) + logger.info('created a url:', url) + + const requestOptionsFromUrl = urlToHttpOptions(url) + logger.info('request options from url:', requestOptionsFromUrl) + + options = resolveRequestOptions(args, url) + logger.info('resolved request options:', options) + + callback = resolveCallback(args) + } + // Handle a given URL instance as-is + // and derive request options from it. + else if (args[0] instanceof URL) { + url = args[0] + logger.info('first argument is a URL:', url) + + // Check if the second provided argument is RequestOptions. + // If it is, check if "options.path" was set and rewrite it + // on the input URL. + // Do this before resolving options from the URL below + // to prevent query string from being duplicated in the path. + if (typeof args[1] !== 'undefined' && isObject(args[1])) { + url = overrideUrlByRequestOptions(url, args[1]) + } + + options = resolveRequestOptions(args, url) + logger.info('derived request options:', options) + + callback = resolveCallback(args) + } + // Handle a legacy URL instance and re-normalize from either a RequestOptions object + // or a WHATWG URL. + else if ('hash' in args[0] && !('method' in args[0])) { + const [legacyUrl] = args + logger.info('first argument is a legacy URL:', legacyUrl) + + if (legacyUrl.hostname === null) { + /** + * We are dealing with a relative url, so use the path as an "option" and + * merge in any existing options, giving priority to exising options -- i.e. a path in any + * existing options will take precedence over the one contained in the url. This is consistent + * with the behaviour in ClientRequest. + * @see https://github.com/nodejs/node/blob/d84f1312915fe45fe0febe888db692c74894c382/lib/_http_client.js#L122 + */ + logger.info('given legacy URL is relative (no hostname)') + + return isObject(args[1]) + ? normalizeClientRequestArgs(defaultProtocol, [ + { path: legacyUrl.path, ...args[1] }, + args[2], + ]) + : normalizeClientRequestArgs(defaultProtocol, [ + { path: legacyUrl.path }, + args[1] as HttpRequestCallback, + ]) + } + + logger.info('given legacy url is absolute') + + // We are dealing with an absolute URL, so convert to WHATWG and try again. + const resolvedUrl = new URL(legacyUrl.href) + + return args[1] === undefined + ? normalizeClientRequestArgs(defaultProtocol, [resolvedUrl]) + : typeof args[1] === 'function' + ? normalizeClientRequestArgs(defaultProtocol, [resolvedUrl, args[1]]) + : normalizeClientRequestArgs(defaultProtocol, [ + resolvedUrl, + args[1], + args[2], + ]) + } + // Handle a given "RequestOptions" object as-is + // and derive the URL instance from it. + else if (isObject(args[0])) { + options = { ...(args[0] as any) } + logger.info('first argument is RequestOptions:', options) + + // When handling a "RequestOptions" object without an explicit "protocol", + // infer the protocol from the request issuing module (http/https). + options.protocol = options.protocol || defaultProtocol + logger.info('normalized request options:', options) + + url = getUrlByRequestOptions(options) + logger.info('created a URL from RequestOptions:', url.href) + + callback = resolveCallback(args) + } else { + throw new Error( + `Failed to construct ClientRequest with these parameters: ${args}` + ) + } + + options.protocol = options.protocol || url.protocol + options.method = options.method || 'GET' + + /** + * Infer a fallback agent from the URL protocol. + * The interception is done on the "ClientRequest" level ("NodeClientRequest") + * and it may miss the correct agent. Always align the agent + * with the URL protocol, if not provided. + * + * @note Respect the "agent: false" value. + */ + if (typeof options.agent === 'undefined') { + const agent = + options.protocol === 'https:' + ? new HttpsAgent({ + // Any other value other than false is considered as true, so we don't add this property if undefined. + ...('rejectUnauthorized' in options && { + rejectUnauthorized: options.rejectUnauthorized, + }), + }) + : new HttpAgent() + + options.agent = agent + logger.info('resolved fallback agent:', agent) + } + + /** + * Ensure that the default Agent is always set. + * This prevents the protocol mismatch for requests with { agent: false }, + * where the global Agent is inferred. + * @see https://github.com/mswjs/msw/issues/1150 + * @see https://github.com/nodejs/node/blob/418ff70b810f0e7112d48baaa72932a56cfa213b/lib/_http_client.js#L130 + * @see https://github.com/nodejs/node/blob/418ff70b810f0e7112d48baaa72932a56cfa213b/lib/_http_client.js#L157-L159 + */ + if (!options._defaultAgent) { + logger.info( + 'has no default agent, setting the default agent for "%s"', + options.protocol + ) + + options._defaultAgent = + options.protocol === 'https:' ? httpsGlobalAgent : httpGlobalAgent + } + + logger.info('successfully resolved url:', url.href) + logger.info('successfully resolved options:', options) + logger.info('successfully resolved callback:', callback) + + /** + * @note If the user-provided URL is not a valid URL in Node.js, + * (e.g. the one provided by the JSDOM polyfills), case it to + * string. Otherwise, this throws on Node.js incompatibility + * (`ERR_INVALID_ARG_TYPE` on the connection listener) + * @see https://github.com/node-fetch/node-fetch/issues/1376#issuecomment-966435555 + */ + if (!(url instanceof URL)) { + url = (url as any).toString() + } + + return [url, options, callback] +} diff --git a/node_modules/@mswjs/interceptors/src/interceptors/ClientRequest/utils/recordRawHeaders.test.ts b/node_modules/@mswjs/interceptors/src/interceptors/ClientRequest/utils/recordRawHeaders.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..75071260869aba82018b813573d59ec0cb34a998 --- /dev/null +++ b/node_modules/@mswjs/interceptors/src/interceptors/ClientRequest/utils/recordRawHeaders.test.ts @@ -0,0 +1,258 @@ +// @vitest-environment node +import { it, expect, afterEach } from 'vitest' +import { + recordRawFetchHeaders, + restoreHeadersPrototype, + getRawFetchHeaders, +} from './recordRawHeaders' + +const url = 'http://localhost' + +afterEach(() => { + restoreHeadersPrototype() +}) + +it('returns an empty list if no headers were set', () => { + expect(getRawFetchHeaders(new Headers())).toEqual([]) + expect(getRawFetchHeaders(new Headers(undefined))).toEqual([]) + expect(getRawFetchHeaders(new Headers({}))).toEqual([]) + expect(getRawFetchHeaders(new Headers([]))).toEqual([]) + expect(getRawFetchHeaders(new Request(url).headers)).toEqual([]) + expect(getRawFetchHeaders(new Response().headers)).toEqual([]) +}) + +it('records raw headers (Headers / object as init)', () => { + recordRawFetchHeaders() + const headers = new Headers({ + 'Content-Type': 'application/json', + 'X-My-Header': '1', + }) + + expect(getRawFetchHeaders(headers)).toEqual([ + ['Content-Type', 'application/json'], + ['X-My-Header', '1'], + ]) + expect(Object.fromEntries(headers)).toEqual({ + 'content-type': 'application/json', + 'x-my-header': '1', + }) +}) + +it('records raw headers (Headers / array as init)', () => { + recordRawFetchHeaders() + const headers = new Headers([['X-My-Header', '1']]) + + expect(getRawFetchHeaders(headers)).toEqual([['X-My-Header', '1']]) + expect(Object.fromEntries(headers)).toEqual({ + 'x-my-header': '1', + }) +}) + +it('records raw headers (Headers / Headers as init', () => { + recordRawFetchHeaders() + const headers = new Headers([['X-My-Header', '1']]) + + expect(getRawFetchHeaders(new Headers(headers))).toEqual([ + ['X-My-Header', '1'], + ]) +}) + +it('records raw headers added via ".set()"', () => { + recordRawFetchHeaders() + const headers = new Headers([['X-My-Header', '1']]) + headers.set('X-Another-Header', '2') + + expect(getRawFetchHeaders(headers)).toEqual([ + ['X-My-Header', '1'], + ['X-Another-Header', '2'], + ]) +}) + +it('records raw headers added via ".append()"', () => { + recordRawFetchHeaders() + const headers = new Headers([['X-My-Header', '1']]) + headers.append('X-My-Header', '2') + + expect(getRawFetchHeaders(headers)).toEqual([ + ['X-My-Header', '1'], + ['X-My-Header', '2'], + ]) +}) + +it('deletes the header when called ".delete()"', () => { + const headers = new Headers([['X-My-Header', '1']]) + headers.delete('X-My-Header') + + expect(getRawFetchHeaders(headers)).toEqual([]) +}) + +it('records raw headers (Request / object as init)', () => { + recordRawFetchHeaders() + const request = new Request(url, { + headers: { + 'Content-Type': 'application/json', + 'X-My-Header': '1', + }, + }) + + expect(getRawFetchHeaders(request.headers)).toEqual([ + ['Content-Type', 'application/json'], + ['X-My-Header', '1'], + ]) +}) + +it('records raw headers (Request / array as init)', () => { + recordRawFetchHeaders() + const request = new Request(url, { + headers: [['X-My-Header', '1']], + }) + + expect(getRawFetchHeaders(request.headers)).toEqual([['X-My-Header', '1']]) +}) + +it('records raw headers (Request / Headers as init)', () => { + recordRawFetchHeaders() + const headers = new Headers([['X-My-Header', '1']]) + const request = new Request(url, { headers }) + + expect(getRawFetchHeaders(request.headers)).toEqual([['X-My-Header', '1']]) +}) + +it('records raw headers (Reqest / Request as init)', () => { + recordRawFetchHeaders() + const init = new Request(url, { headers: [['X-My-Header', '1']] }) + const request = new Request(init) + + expect(getRawFetchHeaders(request.headers)).toEqual([['X-My-Header', '1']]) +}) + +it('preserves headers instanceof (Request / Request as init)', () => { + recordRawFetchHeaders() + const init = new Request(url, { headers: [['X-My-Header', '1']] }) + new Request(init) + expect(init.headers).toBeInstanceOf(Headers) +}) + +it('preserves headers instanceof (Request / Request with Headers as init)', () => { + recordRawFetchHeaders() + const headers = new Headers([['X-My-Header', '1']]) + const init = new Request(url, { headers }) + new Request(init) + expect(init.headers).toBeInstanceOf(Headers) +}) + +it('preserves headers instanceof (Response / Response with Headers as init)', () => { + recordRawFetchHeaders() + const init = { headers: new Headers([['X-My-Header', '1']]) } + new Response(url, init) + expect(init.headers).toBeInstanceOf(Headers) +}) + +it('records raw headers (Request / Request+Headers as init)', () => { + recordRawFetchHeaders() + const init = new Request(url, { headers: [['X-My-Header', '1']] }) + expect(getRawFetchHeaders(init.headers)).toEqual([['X-My-Header', '1']]) + + const request = new Request(init, { + headers: new Headers([['X-Another-Header', '2']]), + }) + + // Must merge the raw headers from the request init + // and the request instance itself. + expect(getRawFetchHeaders(request.headers)).toEqual([ + ['X-My-Header', '1'], + ['X-Another-Header', '2'], + ]) +}) + +it('records raw headers (Response / object as init)', () => { + recordRawFetchHeaders() + const response = new Response(null, { + headers: { + 'Content-Type': 'application/json', + 'X-My-Header': '1', + }, + }) + + expect(getRawFetchHeaders(response.headers)).toEqual([ + ['Content-Type', 'application/json'], + ['X-My-Header', '1'], + ]) +}) + +it('records raw headers (Response / array as init)', () => { + recordRawFetchHeaders() + const response = new Response(null, { + headers: [['X-My-Header', '1']], + }) + + expect(getRawFetchHeaders(response.headers)).toEqual([['X-My-Header', '1']]) +}) + +it('records raw headers (Response / Headers as init)', () => { + recordRawFetchHeaders() + const headers = new Headers([['X-My-Header', '1']]) + const response = new Response(null, { headers }) + + expect(getRawFetchHeaders(response.headers)).toEqual([['X-My-Header', '1']]) +}) + +it('stops recording once the patches are restored', () => { + restoreHeadersPrototype() + + const headers = new Headers({ 'X-My-Header': '1' }) + // Must return the normalized headers (no access to raw headers). + expect(getRawFetchHeaders(headers)).toEqual([['x-my-header', '1']]) +}) + +it('overrides an existing header when calling ".set()"', () => { + recordRawFetchHeaders() + const headers = new Headers([['a', '1']]) + expect(headers.get('a')).toBe('1') + + headers.set('a', '2') + expect(headers.get('a')).toBe('2') + + const headersClone = new Headers(headers) + expect(headersClone.get('a')).toBe('2') +}) + +it('overrides an existing multi-value header when calling ".set()"', () => { + recordRawFetchHeaders() + const headers = new Headers([ + ['a', '1'], + ['a', '2'], + ]) + expect(headers.get('a')).toBe('1, 2') + + headers.set('a', '3') + expect(headers.get('a')).toBe('3') +}) + +it('does not throw on using Headers before recording', () => { + // If the consumer constructs a Headers instance before + // the interceptor is enabled, it will have no internal symbol set. + const headers = new Headers() + recordRawFetchHeaders() + const request = new Request(url, { headers }) + + expect(getRawFetchHeaders(request.headers)).toEqual([]) + + request.headers.set('X-My-Header', '1') + expect(getRawFetchHeaders(request.headers)).toEqual([['X-My-Header', '1']]) +}) + +/** + * @see https://github.com/mswjs/interceptors/issues/681 + */ +it('isolates headers between different headers instances', async () => { + recordRawFetchHeaders() + const original = new Headers() + const firstClone = new Headers(original) + firstClone.set('Content-Type', 'application/json') + const secondClone = new Headers(original) + + expect(original.get('Content-Type')).toBeNull() + expect(firstClone.get('Content-Type')).toBe('application/json') + expect(secondClone.get('Content-Type')).toBeNull() +}) diff --git a/node_modules/@mswjs/interceptors/src/interceptors/ClientRequest/utils/recordRawHeaders.ts b/node_modules/@mswjs/interceptors/src/interceptors/ClientRequest/utils/recordRawHeaders.ts new file mode 100644 index 0000000000000000000000000000000000000000..80902d5036765414aaf076b57678a683b0686775 --- /dev/null +++ b/node_modules/@mswjs/interceptors/src/interceptors/ClientRequest/utils/recordRawHeaders.ts @@ -0,0 +1,262 @@ +type HeaderTuple = [string, string] +type RawHeaders = Array +type SetHeaderBehavior = 'set' | 'append' + +const kRawHeaders = Symbol('kRawHeaders') +const kRestorePatches = Symbol('kRestorePatches') + +function recordRawHeader( + headers: Headers, + args: HeaderTuple, + behavior: SetHeaderBehavior +) { + ensureRawHeadersSymbol(headers, []) + const rawHeaders = Reflect.get(headers, kRawHeaders) as RawHeaders + + if (behavior === 'set') { + // When recording a set header, ensure we remove any matching existing headers. + for (let index = rawHeaders.length - 1; index >= 0; index--) { + if (rawHeaders[index][0].toLowerCase() === args[0].toLowerCase()) { + rawHeaders.splice(index, 1) + } + } + } + + rawHeaders.push(args) +} + +/** + * Define the raw headers symbol on the given `Headers` instance. + * If the symbol already exists, this function does nothing. + */ +function ensureRawHeadersSymbol( + headers: Headers, + rawHeaders: RawHeaders +): void { + if (Reflect.has(headers, kRawHeaders)) { + return + } + + defineRawHeadersSymbol(headers, rawHeaders) +} + +/** + * Define the raw headers symbol on the given `Headers` instance. + * If the symbol already exists, it gets overridden. + */ +function defineRawHeadersSymbol(headers: Headers, rawHeaders: RawHeaders) { + Object.defineProperty(headers, kRawHeaders, { + value: rawHeaders, + enumerable: false, + // Mark the symbol as configurable so its value can be overridden. + // Overrides happen when merging raw headers from multiple sources. + // E.g. new Request(new Request(url, { headers }), { headers }) + configurable: true, + }) +} + +/** + * Patch the global `Headers` class to store raw headers. + * This is for compatibility with `IncomingMessage.prototype.rawHeaders`. + * + * @note Node.js has their own raw headers symbol but it + * only records the first header name in case of multi-value headers. + * Any other headers are normalized before comparing. This makes it + * incompatible with the `rawHeaders` format. + * + * let h = new Headers() + * h.append('X-Custom', 'one') + * h.append('x-custom', 'two') + * h[Symbol('headers map')] // Map { 'X-Custom' => 'one, two' } + */ +export function recordRawFetchHeaders() { + // Prevent patching the Headers prototype multiple times. + if (Reflect.get(Headers, kRestorePatches)) { + return Reflect.get(Headers, kRestorePatches) + } + + const { + Headers: OriginalHeaders, + Request: OriginalRequest, + Response: OriginalResponse, + } = globalThis + const { set, append, delete: headersDeleteMethod } = Headers.prototype + + Object.defineProperty(Headers, kRestorePatches, { + value: () => { + Headers.prototype.set = set + Headers.prototype.append = append + Headers.prototype.delete = headersDeleteMethod + globalThis.Headers = OriginalHeaders + + globalThis.Request = OriginalRequest + globalThis.Response = OriginalResponse + + Reflect.deleteProperty(Headers, kRestorePatches) + }, + enumerable: false, + /** + * @note Mark this property as configurable + * so we can delete it using `Reflect.delete` during cleanup. + */ + configurable: true, + }) + + Object.defineProperty(globalThis, 'Headers', { + enumerable: true, + writable: true, + value: new Proxy(Headers, { + construct(target, args, newTarget) { + const headersInit = args[0] || [] + + if ( + headersInit instanceof Headers && + Reflect.has(headersInit, kRawHeaders) + ) { + const headers = Reflect.construct( + target, + [Reflect.get(headersInit, kRawHeaders)], + newTarget + ) + ensureRawHeadersSymbol(headers, [ + /** + * @note Spread the retrieved headers to clone them. + * This prevents multiple Headers instances from pointing + * at the same internal "rawHeaders" array. + */ + ...Reflect.get(headersInit, kRawHeaders), + ]) + return headers + } + + const headers = Reflect.construct(target, args, newTarget) + + // Request/Response constructors will set the symbol + // upon creating a new instance, using the raw developer + // input as the raw headers. Skip the symbol altogether + // in those cases because the input to Headers will be normalized. + if (!Reflect.has(headers, kRawHeaders)) { + const rawHeadersInit = Array.isArray(headersInit) + ? headersInit + : Object.entries(headersInit) + ensureRawHeadersSymbol(headers, rawHeadersInit) + } + + return headers + }, + }), + }) + + Headers.prototype.set = new Proxy(Headers.prototype.set, { + apply(target, thisArg, args: HeaderTuple) { + recordRawHeader(thisArg, args, 'set') + return Reflect.apply(target, thisArg, args) + }, + }) + + Headers.prototype.append = new Proxy(Headers.prototype.append, { + apply(target, thisArg, args: HeaderTuple) { + recordRawHeader(thisArg, args, 'append') + return Reflect.apply(target, thisArg, args) + }, + }) + + Headers.prototype.delete = new Proxy(Headers.prototype.delete, { + apply(target, thisArg, args: [string]) { + const rawHeaders = Reflect.get(thisArg, kRawHeaders) as RawHeaders + + if (rawHeaders) { + for (let index = rawHeaders.length - 1; index >= 0; index--) { + if (rawHeaders[index][0].toLowerCase() === args[0].toLowerCase()) { + rawHeaders.splice(index, 1) + } + } + } + + return Reflect.apply(target, thisArg, args) + }, + }) + + Object.defineProperty(globalThis, 'Request', { + enumerable: true, + writable: true, + value: new Proxy(Request, { + construct(target, args, newTarget) { + const request = Reflect.construct(target, args, newTarget) + const inferredRawHeaders: RawHeaders = [] + + // Infer raw headers from a `Request` instance used as init. + if (typeof args[0] === 'object' && args[0].headers != null) { + inferredRawHeaders.push(...inferRawHeaders(args[0].headers)) + } + + // Infer raw headers from the "headers" init argument. + if (typeof args[1] === 'object' && args[1].headers != null) { + inferredRawHeaders.push(...inferRawHeaders(args[1].headers)) + } + + if (inferredRawHeaders.length > 0) { + ensureRawHeadersSymbol(request.headers, inferredRawHeaders) + } + + return request + }, + }), + }) + + Object.defineProperty(globalThis, 'Response', { + enumerable: true, + writable: true, + value: new Proxy(Response, { + construct(target, args, newTarget) { + const response = Reflect.construct(target, args, newTarget) + + if (typeof args[1] === 'object' && args[1].headers != null) { + ensureRawHeadersSymbol( + response.headers, + inferRawHeaders(args[1].headers) + ) + } + + return response + }, + }), + }) +} + +export function restoreHeadersPrototype() { + if (!Reflect.get(Headers, kRestorePatches)) { + return + } + + Reflect.get(Headers, kRestorePatches)() +} + +export function getRawFetchHeaders(headers: Headers): RawHeaders { + // If the raw headers recording failed for some reason, + // use the normalized header entries instead. + if (!Reflect.has(headers, kRawHeaders)) { + return Array.from(headers.entries()) + } + + const rawHeaders = Reflect.get(headers, kRawHeaders) as RawHeaders + return rawHeaders.length > 0 ? rawHeaders : Array.from(headers.entries()) +} + +/** + * Infers the raw headers from the given `HeadersInit` provided + * to the Request/Response constructor. + * + * If the `init.headers` is a Headers instance, use it directly. + * That means the headers were created standalone and already have + * the raw headers stored. + * If the `init.headers` is a HeadersInit, create a new Headers + * instace out of it. + */ +function inferRawHeaders(headers: HeadersInit): RawHeaders { + if (headers instanceof Headers) { + return Reflect.get(headers, kRawHeaders) || [] + } + + return Reflect.get(new Headers(headers), kRawHeaders) +} diff --git a/node_modules/@mswjs/interceptors/src/interceptors/Socket/MockSocket.test.ts b/node_modules/@mswjs/interceptors/src/interceptors/Socket/MockSocket.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..61235cf3633f6c31b4be8e44ff758d9acf882c12 --- /dev/null +++ b/node_modules/@mswjs/interceptors/src/interceptors/Socket/MockSocket.test.ts @@ -0,0 +1,264 @@ +/** + * @vitest-environment node + */ +import { Socket } from 'node:net' +import { vi, it, expect } from 'vitest' +import { MockSocket } from './MockSocket' + +it(`keeps the socket connecting until it's destroyed`, () => { + const socket = new MockSocket({ + write: vi.fn(), + read: vi.fn(), + }) + + expect(socket.connecting).toBe(true) + + socket.destroy() + expect(socket.connecting).toBe(false) +}) + +it('calls the "write" on "socket.write()"', () => { + const writeCallback = vi.fn() + const socket = new MockSocket({ + write: writeCallback, + read: vi.fn(), + }) + + socket.write() + expect(writeCallback).toHaveBeenCalledWith(undefined, undefined, undefined) +}) + +it('calls the "write" on "socket.write(chunk)"', () => { + const writeCallback = vi.fn() + const socket = new MockSocket({ + write: writeCallback, + read: vi.fn(), + }) + + socket.write('hello') + expect(writeCallback).toHaveBeenCalledWith('hello', undefined, undefined) +}) + +it('calls the "write" on "socket.write(chunk, encoding)"', () => { + const writeCallback = vi.fn() + const socket = new MockSocket({ + write: writeCallback, + read: vi.fn(), + }) + + socket.write('hello', 'utf8') + expect(writeCallback).toHaveBeenCalledWith('hello', 'utf8', undefined) +}) + +it('calls the "write" on "socket.write(chunk, encoding, callback)"', () => { + const writeCallback = vi.fn() + const socket = new MockSocket({ + write: writeCallback, + read: vi.fn(), + }) + + const callback = vi.fn() + socket.write('hello', 'utf8', callback) + expect(writeCallback).toHaveBeenCalledWith('hello', 'utf8', callback) +}) + +it('calls the "write" on "socket.end()"', () => { + const writeCallback = vi.fn() + const socket = new MockSocket({ + write: writeCallback, + read: vi.fn(), + }) + + socket.end() + expect(writeCallback).toHaveBeenCalledWith(undefined, undefined, undefined) +}) + +it('calls the "write" on "socket.end(chunk)"', () => { + const writeCallback = vi.fn() + const socket = new MockSocket({ + write: writeCallback, + read: vi.fn(), + }) + + socket.end('final') + expect(writeCallback).toHaveBeenCalledWith('final', undefined, undefined) +}) + +it('calls the "write" on "socket.end(chunk, encoding)"', () => { + const writeCallback = vi.fn() + const socket = new MockSocket({ + write: writeCallback, + read: vi.fn(), + }) + + socket.end('final', 'utf8') + expect(writeCallback).toHaveBeenCalledWith('final', 'utf8', undefined) +}) + +it('calls the "write" on "socket.end(chunk, encoding, callback)"', () => { + const writeCallback = vi.fn() + const socket = new MockSocket({ + write: writeCallback, + read: vi.fn(), + }) + + const callback = vi.fn() + socket.end('final', 'utf8', callback) + expect(writeCallback).toHaveBeenCalledWith('final', 'utf8', callback) +}) + +it('calls the "write" on "socket.end()" without any arguments', () => { + const writeCallback = vi.fn() + const socket = new MockSocket({ + write: writeCallback, + read: vi.fn(), + }) + + socket.end() + expect(writeCallback).toHaveBeenCalledWith(undefined, undefined, undefined) +}) + +it('emits "finished" on .end() without any arguments', async () => { + const finishListener = vi.fn() + const socket = new MockSocket({ + write: vi.fn(), + read: vi.fn(), + }) + socket.on('finish', finishListener) + socket.end() + + await vi.waitFor(() => { + expect(finishListener).toHaveBeenCalledTimes(1) + }) +}) + +it('calls the "read" on "socket.read(chunk)"', () => { + const readCallback = vi.fn() + const socket = new MockSocket({ + write: vi.fn(), + read: readCallback, + }) + + socket.push('hello') + expect(readCallback).toHaveBeenCalledWith('hello', undefined) +}) + +it('calls the "read" on "socket.read(chunk, encoding)"', () => { + const readCallback = vi.fn() + const socket = new MockSocket({ + write: vi.fn(), + read: readCallback, + }) + + socket.push('world', 'utf8') + expect(readCallback).toHaveBeenCalledWith('world', 'utf8') +}) + +it('calls the "read" on "socket.read(null)"', () => { + const readCallback = vi.fn() + const socket = new MockSocket({ + write: vi.fn(), + read: readCallback, + }) + + socket.push(null) + expect(readCallback).toHaveBeenCalledWith(null, undefined) +}) + +it('updates the writable state on "socket.end()"', async () => { + const finishListener = vi.fn() + const endListener = vi.fn() + const socket = new MockSocket({ + write: vi.fn(), + read: vi.fn(), + }) + socket.on('finish', finishListener) + socket.on('end', endListener) + + expect(socket.writable).toBe(true) + expect(socket.writableEnded).toBe(false) + expect(socket.writableFinished).toBe(false) + + socket.write('hello') + // Finish the writable stream. + socket.end() + + expect(socket.writable).toBe(false) + expect(socket.writableEnded).toBe(true) + + // The "finish" event is emitted when writable is done. + // I.e. "socket.end()" is called. + await vi.waitFor(() => { + expect(finishListener).toHaveBeenCalledTimes(1) + }) + expect(socket.writableFinished).toBe(true) +}) + +it('updates the readable state on "socket.push(null)"', async () => { + const endListener = vi.fn() + const socket = new MockSocket({ + write: vi.fn(), + read: vi.fn(), + }) + socket.on('end', endListener) + + expect(socket.readable).toBe(true) + expect(socket.readableEnded).toBe(false) + + socket.push('hello') + socket.push(null) + + expect(socket.readable).toBe(true) + expect(socket.readableEnded).toBe(false) + + // Read the data to free the buffer and + // make Socket emit "end". + socket.read() + + await vi.waitFor(() => { + expect(endListener).toHaveBeenCalledTimes(1) + }) + expect(socket.readable).toBe(false) + expect(socket.readableEnded).toBe(true) +}) + +it('updates the readable/writable state on "socket.destroy()"', async () => { + const finishListener = vi.fn() + const endListener = vi.fn() + const closeListener = vi.fn() + const socket = new MockSocket({ + write: vi.fn(), + read: vi.fn(), + }) + socket.on('finish', finishListener) + socket.on('end', endListener) + socket.on('close', closeListener) + + expect(socket.writable).toBe(true) + expect(socket.writableEnded).toBe(false) + expect(socket.writableFinished).toBe(false) + expect(socket.readable).toBe(true) + + socket.destroy() + + expect(socket.writable).toBe(false) + // The ".end()" wasn't called. + expect(socket.writableEnded).toBe(false) + expect(socket.writableFinished).toBe(false) + expect(socket.readable).toBe(false) + + await vi.waitFor(() => { + expect(closeListener).toHaveBeenCalledTimes(1) + }) + + // Neither "finish" nor "end" events are emitted + // when you destroy the stream. If you want those, + // call ".end()", then destroy the stream. + expect(finishListener).not.toHaveBeenCalled() + expect(endListener).not.toHaveBeenCalled() + expect(socket.writableFinished).toBe(false) + + // The "end" event was never emitted so "readableEnded" + // remains false. + expect(socket.readableEnded).toBe(false) +}) diff --git a/node_modules/@mswjs/interceptors/src/interceptors/Socket/MockSocket.ts b/node_modules/@mswjs/interceptors/src/interceptors/Socket/MockSocket.ts new file mode 100644 index 0000000000000000000000000000000000000000..5bcc42eead874acf99ab72c32755494e378fcc59 --- /dev/null +++ b/node_modules/@mswjs/interceptors/src/interceptors/Socket/MockSocket.ts @@ -0,0 +1,58 @@ +import net from 'node:net' +import { + normalizeSocketWriteArgs, + type WriteArgs, + type WriteCallback, +} from './utils/normalizeSocketWriteArgs' + +export interface MockSocketOptions { + write: ( + chunk: Buffer | string, + encoding: BufferEncoding | undefined, + callback?: WriteCallback + ) => void + + read: (chunk: Buffer, encoding: BufferEncoding | undefined) => void +} + +export class MockSocket extends net.Socket { + public connecting: boolean + + constructor(protected readonly options: MockSocketOptions) { + super() + this.connecting = false + this.connect() + + this._final = (callback) => { + callback(null) + } + } + + public connect() { + // The connection will remain pending until + // the consumer decides to handle it. + this.connecting = true + return this + } + + public write(...args: Array): boolean { + const [chunk, encoding, callback] = normalizeSocketWriteArgs( + args as WriteArgs + ) + this.options.write(chunk, encoding, callback) + return true + } + + public end(...args: Array) { + const [chunk, encoding, callback] = normalizeSocketWriteArgs( + args as WriteArgs + ) + this.options.write(chunk, encoding, callback) + return super.end.apply(this, args as any) + } + + public push(chunk: any, encoding?: BufferEncoding): boolean { + this.options.read(chunk, encoding) + return super.push(chunk, encoding) + } +} diff --git a/node_modules/@mswjs/interceptors/src/interceptors/Socket/utils/baseUrlFromConnectionOptions.ts b/node_modules/@mswjs/interceptors/src/interceptors/Socket/utils/baseUrlFromConnectionOptions.ts new file mode 100644 index 0000000000000000000000000000000000000000..6a4f33adbaf45647ebb2123fd9b40a7585e63007 --- /dev/null +++ b/node_modules/@mswjs/interceptors/src/interceptors/Socket/utils/baseUrlFromConnectionOptions.ts @@ -0,0 +1,26 @@ +export function baseUrlFromConnectionOptions(options: any): URL { + if ('href' in options) { + return new URL(options.href) + } + + const protocol = options.port === 443 ? 'https:' : 'http:' + const host = options.host + + const url = new URL(`${protocol}//${host}`) + + if (options.port) { + url.port = options.port.toString() + } + + if (options.path) { + url.pathname = options.path + } + + if (options.auth) { + const [username, password] = options.auth.split(':') + url.username = username + url.password = password + } + + return url +} diff --git a/node_modules/@mswjs/interceptors/src/interceptors/Socket/utils/normalizeSocketWriteArgs.test.ts b/node_modules/@mswjs/interceptors/src/interceptors/Socket/utils/normalizeSocketWriteArgs.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..32f2e1d5a87bc30bca4d257d23b15e144e26ac1b --- /dev/null +++ b/node_modules/@mswjs/interceptors/src/interceptors/Socket/utils/normalizeSocketWriteArgs.test.ts @@ -0,0 +1,52 @@ +/** + * @vitest-environment node + */ +import { it, expect } from 'vitest' +import { normalizeSocketWriteArgs } from './normalizeSocketWriteArgs' + +it('normalizes .write()', () => { + expect(normalizeSocketWriteArgs([undefined])).toEqual([ + undefined, + undefined, + undefined, + ]) + expect(normalizeSocketWriteArgs([null])).toEqual([null, undefined, undefined]) +}) + +it('normalizes .write(chunk)', () => { + expect(normalizeSocketWriteArgs([Buffer.from('hello')])).toEqual([ + Buffer.from('hello'), + undefined, + undefined, + ]) + expect(normalizeSocketWriteArgs(['hello'])).toEqual([ + 'hello', + undefined, + undefined, + ]) + expect(normalizeSocketWriteArgs([null])).toEqual([null, undefined, undefined]) +}) + +it('normalizes .write(chunk, encoding)', () => { + expect(normalizeSocketWriteArgs([Buffer.from('hello'), 'utf8'])).toEqual([ + Buffer.from('hello'), + 'utf8', + undefined, + ]) +}) + +it('normalizes .write(chunk, callback)', () => { + const callback = () => {} + expect(normalizeSocketWriteArgs([Buffer.from('hello'), callback])).toEqual([ + Buffer.from('hello'), + undefined, + callback, + ]) +}) + +it('normalizes .write(chunk, encoding, callback)', () => { + const callback = () => {} + expect( + normalizeSocketWriteArgs([Buffer.from('hello'), 'utf8', callback]) + ).toEqual([Buffer.from('hello'), 'utf8', callback]) +}) diff --git a/node_modules/@mswjs/interceptors/src/interceptors/Socket/utils/normalizeSocketWriteArgs.ts b/node_modules/@mswjs/interceptors/src/interceptors/Socket/utils/normalizeSocketWriteArgs.ts new file mode 100644 index 0000000000000000000000000000000000000000..03a3e9c05473819ecb46c6eeffb0143c24d01ded --- /dev/null +++ b/node_modules/@mswjs/interceptors/src/interceptors/Socket/utils/normalizeSocketWriteArgs.ts @@ -0,0 +1,33 @@ +export type WriteCallback = (error?: Error | null) => void + +export type WriteArgs = + | [chunk: unknown, callback?: WriteCallback] + | [chunk: unknown, encoding: BufferEncoding, callback?: WriteCallback] + +export type NormalizedSocketWriteArgs = [ + chunk: any, + encoding?: BufferEncoding, + callback?: WriteCallback, +] + +/** + * Normalizes the arguments provided to the `Writable.prototype.write()` + * and `Writable.prototype.end()`. + */ +export function normalizeSocketWriteArgs( + args: WriteArgs +): NormalizedSocketWriteArgs { + const normalized: NormalizedSocketWriteArgs = [args[0], undefined, undefined] + + if (typeof args[1] === 'string') { + normalized[1] = args[1] + } else if (typeof args[1] === 'function') { + normalized[2] = args[1] + } + + if (typeof args[2] === 'function') { + normalized[2] = args[2] + } + + return normalized +} diff --git a/node_modules/@mswjs/interceptors/src/interceptors/WebSocket/WebSocketClassTransport.ts b/node_modules/@mswjs/interceptors/src/interceptors/WebSocket/WebSocketClassTransport.ts new file mode 100644 index 0000000000000000000000000000000000000000..70f2166584409bcd9ea78d50af5665c796e4872c --- /dev/null +++ b/node_modules/@mswjs/interceptors/src/interceptors/WebSocket/WebSocketClassTransport.ts @@ -0,0 +1,116 @@ +import { bindEvent } from './utils/bindEvent' +import { + StrictEventListenerOrEventListenerObject, + WebSocketData, + WebSocketTransport, + WebSocketTransportEventMap, +} from './WebSocketTransport' +import { kOnSend, kClose, WebSocketOverride } from './WebSocketOverride' +import { CancelableMessageEvent, CloseEvent } from './utils/events' + +/** + * Abstraction over the given mock `WebSocket` instance that allows + * for controlling that instance (e.g. sending and receiving messages). + */ +export class WebSocketClassTransport + extends EventTarget + implements WebSocketTransport +{ + constructor(protected readonly socket: WebSocketOverride) { + super() + + // Emit the "close" event on the transport if the close + // originates from the WebSocket client. E.g. the application + // calls "ws.close()", not the interceptor. + this.socket.addEventListener('close', (event) => { + this.dispatchEvent(bindEvent(this.socket, new CloseEvent('close', event))) + }) + + /** + * Emit the "outgoing" event on the transport + * whenever the WebSocket client sends data ("ws.send()"). + */ + this.socket[kOnSend] = (data) => { + this.dispatchEvent( + bindEvent( + this.socket, + // Dispatch this as cancelable because "client" connection + // re-creates this message event (cannot dispatch the same event). + new CancelableMessageEvent('outgoing', { + data, + origin: this.socket.url, + cancelable: true, + }) + ) + ) + } + } + + public addEventListener( + type: EventType, + callback: StrictEventListenerOrEventListenerObject< + WebSocketTransportEventMap[EventType] + > | null, + options?: boolean | AddEventListenerOptions + ): void { + return super.addEventListener(type, callback as EventListener, options) + } + + public dispatchEvent( + event: WebSocketTransportEventMap[EventType] + ): boolean { + return super.dispatchEvent(event) + } + + public send(data: WebSocketData): void { + queueMicrotask(() => { + if ( + this.socket.readyState === this.socket.CLOSING || + this.socket.readyState === this.socket.CLOSED + ) { + return + } + + const dispatchEvent = () => { + this.socket.dispatchEvent( + bindEvent( + /** + * @note Setting this event's "target" to the + * WebSocket override instance is important. + * This way it can tell apart original incoming events + * (must be forwarded to the transport) from the + * mocked message events like the one below + * (must be dispatched on the client instance). + */ + this.socket, + new MessageEvent('message', { + data, + origin: this.socket.url, + }) + ) + ) + } + + if (this.socket.readyState === this.socket.CONNECTING) { + this.socket.addEventListener( + 'open', + () => { + dispatchEvent() + }, + { once: true } + ) + } else { + dispatchEvent() + } + }) + } + + public close(code: number, reason?: string): void { + /** + * @note Call the internal close method directly + * to allow closing the connection with the status codes + * that are non-configurable by the user (> 1000 <= 1015). + */ + this.socket[kClose](code, reason) + } +} diff --git a/node_modules/@mswjs/interceptors/src/interceptors/WebSocket/WebSocketClientConnection.ts b/node_modules/@mswjs/interceptors/src/interceptors/WebSocket/WebSocketClientConnection.ts new file mode 100644 index 0000000000000000000000000000000000000000..0e1749cf7fe58cd486f6b6243cc650cee6b6463b --- /dev/null +++ b/node_modules/@mswjs/interceptors/src/interceptors/WebSocket/WebSocketClientConnection.ts @@ -0,0 +1,138 @@ +import type { WebSocketData, WebSocketTransport } from './WebSocketTransport' +import type { WebSocketEventListener } from './WebSocketOverride' +import { bindEvent } from './utils/bindEvent' +import { CancelableMessageEvent, CloseEvent } from './utils/events' +import { createRequestId } from '../../createRequestId' + +const kEmitter = Symbol('kEmitter') +const kBoundListener = Symbol('kBoundListener') + +interface WebSocketClientEventMap { + message: MessageEvent + close: CloseEvent +} + +export interface WebSocketClientConnectionProtocol { + id: string + url: URL + send(data: WebSocketData): void + close(code?: number, reason?: string): void +} + +/** + * The WebSocket client instance represents an incoming + * client connection. The user can control the connection, + * send and receive events. + */ +export class WebSocketClientConnection + implements WebSocketClientConnectionProtocol +{ + public readonly id: string + public readonly url: URL + + private [kEmitter]: EventTarget + + constructor( + public readonly socket: WebSocket, + private readonly transport: WebSocketTransport + ) { + this.id = createRequestId() + this.url = new URL(socket.url) + this[kEmitter] = new EventTarget() + + // Emit outgoing client data ("ws.send()") as "message" + // events on the "client" connection. + this.transport.addEventListener('outgoing', (event) => { + const message = bindEvent( + this.socket, + new CancelableMessageEvent('message', { + data: event.data, + origin: event.origin, + cancelable: true, + }) + ) + + this[kEmitter].dispatchEvent(message) + + // This is a bit silly but forward the cancellation state + // of the "client" message event to the "outgoing" transport event. + // This way, other agens (like "server" connection) can know + // whether the client listener has pervented the default. + if (message.defaultPrevented) { + event.preventDefault() + } + }) + + /** + * Emit the "close" event on the "client" connection + * whenever the underlying transport is closed. + * @note "client.close()" does NOT dispatch the "close" + * event on the WebSocket because it uses non-configurable + * close status code. Thus, we listen to the transport + * instead of the WebSocket's "close" event. + */ + this.transport.addEventListener('close', (event) => { + this[kEmitter].dispatchEvent( + bindEvent(this.socket, new CloseEvent('close', event)) + ) + }) + } + + /** + * Listen for the outgoing events from the connected WebSocket client. + */ + public addEventListener( + type: EventType, + listener: WebSocketEventListener, + options?: AddEventListenerOptions | boolean + ): void { + if (!Reflect.has(listener, kBoundListener)) { + const boundListener = listener.bind(this.socket) + + // Store the bound listener on the original listener + // so the exact bound function can be accessed in "removeEventListener()". + Object.defineProperty(listener, kBoundListener, { + value: boundListener, + enumerable: false, + configurable: false, + }) + } + + this[kEmitter].addEventListener( + type, + Reflect.get(listener, kBoundListener) as EventListener, + options + ) + } + + /** + * Removes the listener for the given event. + */ + public removeEventListener( + event: EventType, + listener: WebSocketEventListener, + options?: EventListenerOptions | boolean + ): void { + this[kEmitter].removeEventListener( + event, + Reflect.get(listener, kBoundListener) as EventListener, + options + ) + } + + /** + * Send data to the connected client. + */ + public send(data: WebSocketData): void { + this.transport.send(data) + } + + /** + * Close the WebSocket connection. + * @param {number} code A status code (see https://www.rfc-editor.org/rfc/rfc6455#section-7.4.1). + * @param {string} reason A custom connection close reason. + */ + public close(code?: number, reason?: string): void { + this.transport.close(code, reason) + } +} diff --git a/node_modules/@mswjs/interceptors/src/interceptors/WebSocket/WebSocketOverride.ts b/node_modules/@mswjs/interceptors/src/interceptors/WebSocket/WebSocketOverride.ts new file mode 100644 index 0000000000000000000000000000000000000000..8edb17289d631c090ff162cc37aaac6e2e872dcd --- /dev/null +++ b/node_modules/@mswjs/interceptors/src/interceptors/WebSocket/WebSocketOverride.ts @@ -0,0 +1,251 @@ +import { invariant } from 'outvariant' +import type { WebSocketData } from './WebSocketTransport' +import { bindEvent } from './utils/bindEvent' +import { CloseEvent } from './utils/events' +import { DeferredPromise } from '@open-draft/deferred-promise' + +export type WebSocketEventListener< + EventType extends WebSocketEventMap[keyof WebSocketEventMap] = Event +> = (this: WebSocket, event: EventType) => void + +const WEBSOCKET_CLOSE_CODE_RANGE_ERROR = + 'InvalidAccessError: close code out of user configurable range' + +export const kPassthroughPromise = Symbol('kPassthroughPromise') +export const kOnSend = Symbol('kOnSend') +export const kClose = Symbol('kClose') + +export class WebSocketOverride extends EventTarget implements WebSocket { + static readonly CONNECTING = 0 + static readonly OPEN = 1 + static readonly CLOSING = 2 + static readonly CLOSED = 3 + readonly CONNECTING = 0 + readonly OPEN = 1 + readonly CLOSING = 2 + readonly CLOSED = 3 + + public url: string + public protocol: string + public extensions: string + public binaryType: BinaryType + public readyState: number + public bufferedAmount: number + + private _onopen: WebSocketEventListener | null = null + private _onmessage: WebSocketEventListener< + MessageEvent + > | null = null + private _onerror: WebSocketEventListener | null = null + private _onclose: WebSocketEventListener | null = null + + private [kPassthroughPromise]: DeferredPromise + private [kOnSend]?: (data: WebSocketData) => void + + constructor(url: string | URL, protocols?: string | Array) { + super() + this.url = url.toString() + this.protocol = '' + this.extensions = '' + this.binaryType = 'blob' + this.readyState = this.CONNECTING + this.bufferedAmount = 0 + + this[kPassthroughPromise] = new DeferredPromise() + + queueMicrotask(async () => { + if (await this[kPassthroughPromise]) { + return + } + + this.protocol = + typeof protocols === 'string' + ? protocols + : Array.isArray(protocols) && protocols.length > 0 + ? protocols[0] + : '' + + /** + * @note Check that nothing has prevented this connection + * (e.g. called `client.close()` in the connection listener). + * If the connection has been prevented, never dispatch the open event,. + */ + if (this.readyState === this.CONNECTING) { + this.readyState = this.OPEN + this.dispatchEvent(bindEvent(this, new Event('open'))) + } + }) + } + + set onopen(listener: WebSocketEventListener | null) { + this.removeEventListener('open', this._onopen) + this._onopen = listener + if (listener !== null) { + this.addEventListener('open', listener) + } + } + get onopen(): WebSocketEventListener | null { + return this._onopen + } + + set onmessage( + listener: WebSocketEventListener> | null + ) { + this.removeEventListener( + 'message', + this._onmessage as WebSocketEventListener + ) + this._onmessage = listener + if (listener !== null) { + this.addEventListener('message', listener) + } + } + get onmessage(): WebSocketEventListener> | null { + return this._onmessage + } + + set onerror(listener: WebSocketEventListener | null) { + this.removeEventListener('error', this._onerror) + this._onerror = listener + if (listener !== null) { + this.addEventListener('error', listener) + } + } + get onerror(): WebSocketEventListener | null { + return this._onerror + } + + set onclose(listener: WebSocketEventListener | null) { + this.removeEventListener('close', this._onclose as WebSocketEventListener) + this._onclose = listener + if (listener !== null) { + this.addEventListener('close', listener) + } + } + get onclose(): WebSocketEventListener | null { + return this._onclose + } + + /** + * @see https://websockets.spec.whatwg.org/#ref-for-dom-websocket-send%E2%91%A0 + */ + public send(data: WebSocketData): void { + if (this.readyState === this.CONNECTING) { + this.close() + throw new DOMException('InvalidStateError') + } + + // Sending when the socket is about to close + // discards the sent data. + if (this.readyState === this.CLOSING || this.readyState === this.CLOSED) { + return + } + + // Buffer the data to send in this even loop + // but send it in the next. + this.bufferedAmount += getDataSize(data) + + queueMicrotask(() => { + // This is a bit optimistic but since no actual data transfer + // is involved, all the data will be "sent" on the next tick. + this.bufferedAmount = 0 + + /** + * @note Notify the parent about outgoing data. + * This notifies the transport and the connection + * listens to the outgoing data to emit the "message" event. + */ + this[kOnSend]?.(data) + }) + } + + public close(code: number = 1000, reason?: string): void { + invariant(code, WEBSOCKET_CLOSE_CODE_RANGE_ERROR) + invariant( + code === 1000 || (code >= 3000 && code <= 4999), + WEBSOCKET_CLOSE_CODE_RANGE_ERROR + ) + + this[kClose](code, reason) + } + + private [kClose]( + code: number = 1000, + reason?: string, + wasClean = true + ): void { + /** + * @note Move this check here so that even internall closures, + * like those triggered by the `server` connection, are not + * performed twice. + */ + if (this.readyState === this.CLOSING || this.readyState === this.CLOSED) { + return + } + + this.readyState = this.CLOSING + + queueMicrotask(() => { + this.readyState = this.CLOSED + + this.dispatchEvent( + bindEvent( + this, + new CloseEvent('close', { + code, + reason, + wasClean, + }) + ) + ) + + // Remove all event listeners once the socket is closed. + this._onopen = null + this._onmessage = null + this._onerror = null + this._onclose = null + }) + } + + public addEventListener( + type: K, + listener: (this: WebSocket, event: WebSocketEventMap[K]) => void, + options?: boolean | AddEventListenerOptions + ): void + public addEventListener( + type: string, + listener: EventListenerOrEventListenerObject, + options?: boolean | AddEventListenerOptions + ): void + public addEventListener( + type: unknown, + listener: unknown, + options?: unknown + ): void { + return super.addEventListener( + type as string, + listener as EventListener, + options as AddEventListenerOptions + ) + } + + removeEventListener( + type: K, + callback: EventListenerOrEventListenerObject | null, + options?: boolean | EventListenerOptions + ): void { + return super.removeEventListener(type, callback, options) + } +} + +function getDataSize(data: WebSocketData): number { + if (typeof data === 'string') { + return data.length + } + + if (data instanceof Blob) { + return data.size + } + + return data.byteLength +} diff --git a/node_modules/@mswjs/interceptors/src/interceptors/WebSocket/WebSocketServerConnection.ts b/node_modules/@mswjs/interceptors/src/interceptors/WebSocket/WebSocketServerConnection.ts new file mode 100644 index 0000000000000000000000000000000000000000..dbf310cebba14ef0f106e58a1aaa50b685e21efc --- /dev/null +++ b/node_modules/@mswjs/interceptors/src/interceptors/WebSocket/WebSocketServerConnection.ts @@ -0,0 +1,398 @@ +import { invariant } from 'outvariant' +import { + kClose, + WebSocketEventListener, + WebSocketOverride, +} from './WebSocketOverride' +import type { WebSocketData } from './WebSocketTransport' +import type { WebSocketClassTransport } from './WebSocketClassTransport' +import { bindEvent } from './utils/bindEvent' +import { + CancelableMessageEvent, + CancelableCloseEvent, + CloseEvent, +} from './utils/events' + +const kEmitter = Symbol('kEmitter') +const kBoundListener = Symbol('kBoundListener') +const kSend = Symbol('kSend') + +interface WebSocketServerEventMap { + open: Event + message: MessageEvent + error: Event + close: CloseEvent +} + +/** + * The WebSocket server instance represents the actual production + * WebSocket server connection. It's idle by default but you can + * establish it by calling `server.connect()`. + */ +export class WebSocketServerConnection { + /** + * A WebSocket instance connected to the original server. + */ + private realWebSocket?: WebSocket + private mockCloseController: AbortController + private realCloseController: AbortController + private [kEmitter]: EventTarget + + constructor( + private readonly client: WebSocketOverride, + private readonly transport: WebSocketClassTransport, + private readonly createConnection: () => WebSocket + ) { + this[kEmitter] = new EventTarget() + this.mockCloseController = new AbortController() + this.realCloseController = new AbortController() + + // Automatically forward outgoing client events + // to the actual server unless the outgoing message event + // has been prevented. The "outgoing" transport event it + // dispatched by the "client" connection. + this.transport.addEventListener('outgoing', (event) => { + // Ignore client messages if the server connection + // hasn't been established yet. Nowhere to forward. + if (typeof this.realWebSocket === 'undefined') { + return + } + + // Every outgoing client message can prevent this forwarding + // by preventing the default of the outgoing message event. + // This listener will be added before user-defined listeners, + // so execute the logic on the next tick. + queueMicrotask(() => { + if (!event.defaultPrevented) { + /** + * @note Use the internal send mechanism so consumers can tell + * apart direct user calls to `server.send()` and internal calls. + * E.g. MSW has to ignore this internal call to log out messages correctly. + */ + this[kSend](event.data) + } + }) + }) + + this.transport.addEventListener( + 'incoming', + this.handleIncomingMessage.bind(this) + ) + } + + /** + * The `WebSocket` instance connected to the original server. + * Accessing this before calling `server.connect()` will throw. + */ + public get socket(): WebSocket { + invariant( + this.realWebSocket, + 'Cannot access "socket" on the original WebSocket server object: the connection is not open. Did you forget to call `server.connect()`?' + ) + + return this.realWebSocket + } + + /** + * Open connection to the original WebSocket server. + */ + public connect(): void { + invariant( + !this.realWebSocket || this.realWebSocket.readyState !== WebSocket.OPEN, + 'Failed to call "connect()" on the original WebSocket instance: the connection already open' + ) + + const realWebSocket = this.createConnection() + + // Inherit the binary type from the mock WebSocket client. + realWebSocket.binaryType = this.client.binaryType + + // Allow the interceptor to listen to when the server connection + // has been established. This isn't necessary to operate with the connection + // but may be beneficial in some cases (like conditionally adding logging). + realWebSocket.addEventListener( + 'open', + (event) => { + this[kEmitter].dispatchEvent( + bindEvent(this.realWebSocket!, new Event('open', event)) + ) + }, + { once: true } + ) + + realWebSocket.addEventListener('message', (event) => { + // Dispatch the "incoming" transport event instead of + // invoking the internal handler directly. This way, + // anyone can listen to the "incoming" event but this + // class is the one resulting in it. + this.transport.dispatchEvent( + bindEvent( + this.realWebSocket!, + new MessageEvent('incoming', { + data: event.data, + origin: event.origin, + }) + ) + ) + }) + + // Close the original connection when the mock client closes. + // E.g. "client.close()" was called. This is never forwarded anywhere. + this.client.addEventListener( + 'close', + (event) => { + this.handleMockClose(event) + }, + { + signal: this.mockCloseController.signal, + } + ) + + // Forward the "close" event to let the interceptor handle + // closures initiated by the original server. + realWebSocket.addEventListener( + 'close', + (event) => { + this.handleRealClose(event) + }, + { + signal: this.realCloseController.signal, + } + ) + + realWebSocket.addEventListener('error', () => { + const errorEvent = bindEvent( + realWebSocket, + new Event('error', { cancelable: true }) + ) + + // Emit the "error" event on the `server` connection + // to let the interceptor react to original server errors. + this[kEmitter].dispatchEvent(errorEvent) + + // If the error event from the original server hasn't been prevented, + // forward it to the underlying client. + if (!errorEvent.defaultPrevented) { + this.client.dispatchEvent(bindEvent(this.client, new Event('error'))) + } + }) + + this.realWebSocket = realWebSocket + } + + /** + * Listen for the incoming events from the original WebSocket server. + */ + public addEventListener( + event: EventType, + listener: WebSocketEventListener, + options?: AddEventListenerOptions | boolean + ): void { + if (!Reflect.has(listener, kBoundListener)) { + const boundListener = listener.bind(this.client) + + // Store the bound listener on the original listener + // so the exact bound function can be accessed in "removeEventListener()". + Object.defineProperty(listener, kBoundListener, { + value: boundListener, + enumerable: false, + }) + } + + this[kEmitter].addEventListener( + event, + Reflect.get(listener, kBoundListener) as EventListener, + options + ) + } + + /** + * Remove the listener for the given event. + */ + public removeEventListener( + event: EventType, + listener: WebSocketEventListener, + options?: EventListenerOptions | boolean + ): void { + this[kEmitter].removeEventListener( + event, + Reflect.get(listener, kBoundListener) as EventListener, + options + ) + } + + /** + * Send data to the original WebSocket server. + * @example + * server.send('hello') + * server.send(new Blob(['hello'])) + * server.send(new TextEncoder().encode('hello')) + */ + public send(data: WebSocketData): void { + this[kSend](data) + } + + private [kSend](data: WebSocketData): void { + const { realWebSocket } = this + + invariant( + realWebSocket, + 'Failed to call "server.send()" for "%s": the connection is not open. Did you forget to call "server.connect()"?', + this.client.url + ) + + // Silently ignore writes on the closed original WebSocket. + if ( + realWebSocket.readyState === WebSocket.CLOSING || + realWebSocket.readyState === WebSocket.CLOSED + ) { + return + } + + // Delegate the send to when the original connection is open. + // Unlike the mock, connecting to the original server may take time + // so we cannot call this on the next tick. + if (realWebSocket.readyState === WebSocket.CONNECTING) { + realWebSocket.addEventListener( + 'open', + () => { + realWebSocket.send(data) + }, + { once: true } + ) + return + } + + // Send the data to the original WebSocket server. + realWebSocket.send(data) + } + + /** + * Close the actual server connection. + */ + public close(): void { + const { realWebSocket } = this + + invariant( + realWebSocket, + 'Failed to close server connection for "%s": the connection is not open. Did you forget to call "server.connect()"?', + this.client.url + ) + + // Remove the "close" event listener from the server + // so it doesn't close the underlying WebSocket client + // when you call "server.close()". This also prevents the + // `close` event on the `server` connection from being dispatched twice. + this.realCloseController.abort() + + if ( + realWebSocket.readyState === WebSocket.CLOSING || + realWebSocket.readyState === WebSocket.CLOSED + ) { + return + } + + // Close the actual client connection. + realWebSocket.close() + + // Dispatch the "close" event on the `server` connection. + queueMicrotask(() => { + this[kEmitter].dispatchEvent( + bindEvent( + this.realWebSocket, + new CancelableCloseEvent('close', { + /** + * @note `server.close()` in the interceptor + * always results in clean closures. + */ + code: 1000, + cancelable: true, + }) + ) + ) + }) + } + + private handleIncomingMessage(event: MessageEvent): void { + // Clone the event to dispatch it on this class + // once again and prevent the "already being dispatched" + // exception. Clone it here so we can observe this event + // being prevented in the "server.on()" listeners. + const messageEvent = bindEvent( + event.target, + new CancelableMessageEvent('message', { + data: event.data, + origin: event.origin, + cancelable: true, + }) + ) + + /** + * @note Emit "message" event on the server connection + * instance to let the interceptor know about these + * incoming events from the original server. In that listener, + * the interceptor can modify or skip the event forwarding + * to the mock WebSocket instance. + */ + this[kEmitter].dispatchEvent(messageEvent) + + /** + * @note Forward the incoming server events to the client. + * Preventing the default on the message event stops this. + */ + if (!messageEvent.defaultPrevented) { + this.client.dispatchEvent( + bindEvent( + /** + * @note Bind the forwarded original server events + * to the mock WebSocket instance so it would + * dispatch them straight away. + */ + this.client, + // Clone the message event again to prevent + // the "already being dispatched" exception. + new MessageEvent('message', { + data: event.data, + origin: event.origin, + }) + ) + ) + } + } + + private handleMockClose(_event: Event): void { + // Close the original connection if the mock client closes. + if (this.realWebSocket) { + this.realWebSocket.close() + } + } + + private handleRealClose(event: CloseEvent): void { + // For closures originating from the original server, + // remove the "close" listener from the mock client. + // original close -> (?) client[kClose]() --X--> "close" (again). + this.mockCloseController.abort() + + const closeEvent = bindEvent( + this.realWebSocket, + new CancelableCloseEvent('close', { + code: event.code, + reason: event.reason, + wasClean: event.wasClean, + cancelable: true, + }) + ) + + this[kEmitter].dispatchEvent(closeEvent) + + // If the close event from the server hasn't been prevented, + // forward the closure to the mock client. + if (!closeEvent.defaultPrevented) { + // Close the intercepted client forcefully to + // allow non-configurable status codes from the server. + // If the socket has been closed by now, no harm calling + // this again—it will have no effect. + this.client[kClose](event.code, event.reason) + } + } +} diff --git a/node_modules/@mswjs/interceptors/src/interceptors/WebSocket/WebSocketTransport.ts b/node_modules/@mswjs/interceptors/src/interceptors/WebSocket/WebSocketTransport.ts new file mode 100644 index 0000000000000000000000000000000000000000..973f511ed983d3dc81ad895a317d66d24460ffe1 --- /dev/null +++ b/node_modules/@mswjs/interceptors/src/interceptors/WebSocket/WebSocketTransport.ts @@ -0,0 +1,39 @@ +import { CloseEvent } from './utils/events' + +export type WebSocketData = string | ArrayBufferLike | Blob | ArrayBufferView + +export type WebSocketTransportEventMap = { + incoming: MessageEvent + outgoing: MessageEvent + close: CloseEvent +} + +export type StrictEventListenerOrEventListenerObject = + | ((this: WebSocket, event: EventType) => void) + | { + handleEvent(this: WebSocket, event: EventType): void + } + +export interface WebSocketTransport { + addEventListener( + event: EventType, + listener: StrictEventListenerOrEventListenerObject< + WebSocketTransportEventMap[EventType] + > | null, + options?: boolean | AddEventListenerOptions + ): void + + dispatchEvent( + event: WebSocketTransportEventMap[EventType] + ): boolean + + /** + * Send the data from the server to this client. + */ + send(data: WebSocketData): void + + /** + * Close the client connection. + */ + close(code?: number, reason?: string): void +} diff --git a/node_modules/@mswjs/interceptors/src/interceptors/WebSocket/index.ts b/node_modules/@mswjs/interceptors/src/interceptors/WebSocket/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..78e83dd2c10e46d581f39eafd7198dd0cc6df03f --- /dev/null +++ b/node_modules/@mswjs/interceptors/src/interceptors/WebSocket/index.ts @@ -0,0 +1,170 @@ +import { Interceptor } from '../../Interceptor' +import { + type WebSocketClientConnectionProtocol, + WebSocketClientConnection, +} from './WebSocketClientConnection' +import { WebSocketServerConnection } from './WebSocketServerConnection' +import { WebSocketClassTransport } from './WebSocketClassTransport' +import { + kClose, + kPassthroughPromise, + WebSocketOverride, +} from './WebSocketOverride' +import { bindEvent } from './utils/bindEvent' +import { hasConfigurableGlobal } from '../../utils/hasConfigurableGlobal' + +export { type WebSocketData, WebSocketTransport } from './WebSocketTransport' +export { + WebSocketClientConnection, + WebSocketClientConnectionProtocol, + WebSocketServerConnection, +} + +export type WebSocketEventMap = { + connection: [args: WebSocketConnectionData] +} + +export type WebSocketConnectionData = { + /** + * The incoming WebSocket client connection. + */ + client: WebSocketClientConnection + + /** + * The original WebSocket server connection. + */ + server: WebSocketServerConnection + + /** + * The connection information. + */ + info: { + /** + * The protocols supported by the WebSocket client. + */ + protocols: string | Array | undefined + } +} + +/** + * Intercept the outgoing WebSocket connections created using + * the global `WebSocket` class. + */ +export class WebSocketInterceptor extends Interceptor { + static symbol = Symbol('websocket') + + constructor() { + super(WebSocketInterceptor.symbol) + } + + protected checkEnvironment(): boolean { + return hasConfigurableGlobal('WebSocket') + } + + protected setup(): void { + const originalWebSocketDescriptor = Object.getOwnPropertyDescriptor( + globalThis, + 'WebSocket' + ) + + const WebSocketProxy = new Proxy(globalThis.WebSocket, { + construct: ( + target, + args: ConstructorParameters, + newTarget + ) => { + const [url, protocols] = args + + const createConnection = (): WebSocket => { + return Reflect.construct(target, args, newTarget) + } + + // All WebSocket instances are mocked and don't forward + // any events to the original server (no connection established). + // To forward the events, the user must use the "server.send()" API. + const socket = new WebSocketOverride(url, protocols) + const transport = new WebSocketClassTransport(socket) + + // Emit the "connection" event to the interceptor on the next tick + // so the client can modify WebSocket options, like "binaryType" + // while the connection is already pending. + queueMicrotask(() => { + try { + const server = new WebSocketServerConnection( + socket, + transport, + createConnection + ) + + // The "globalThis.WebSocket" class stands for + // the client-side connection. Assume it's established + // as soon as the WebSocket instance is constructed. + const hasConnectionListeners = this.emitter.emit('connection', { + client: new WebSocketClientConnection(socket, transport), + server, + info: { + protocols, + }, + }) + + if (hasConnectionListeners) { + socket[kPassthroughPromise].resolve(false) + } else { + socket[kPassthroughPromise].resolve(true) + + server.connect() + + // Forward the "open" event from the original server + // to the mock WebSocket client in the case of a passthrough connection. + server.addEventListener('open', () => { + socket.dispatchEvent(bindEvent(socket, new Event('open'))) + + // Forward the original connection protocol to the + // mock WebSocket client. + if (server['realWebSocket']) { + socket.protocol = server['realWebSocket'].protocol + } + }) + } + } catch (error) { + /** + * @note Translate unhandled exceptions during the connection + * handling (i.e. interceptor exceptions) as WebSocket connection + * closures with error. This prevents from the exceptions occurring + * in `queueMicrotask` from being process-wide and uncatchable. + */ + if (error instanceof Error) { + socket.dispatchEvent(new Event('error')) + + // No need to close the connection if it's already being closed. + // E.g. the interceptor called `client.close()` and then threw an error. + if ( + socket.readyState !== WebSocket.CLOSING && + socket.readyState !== WebSocket.CLOSED + ) { + socket[kClose](1011, error.message, false) + } + + console.error(error) + } + } + }) + + return socket + }, + }) + + Object.defineProperty(globalThis, 'WebSocket', { + value: WebSocketProxy, + configurable: true, + }) + + this.subscriptions.push(() => { + Object.defineProperty( + globalThis, + 'WebSocket', + originalWebSocketDescriptor! + ) + }) + } +} diff --git a/node_modules/@mswjs/interceptors/src/interceptors/WebSocket/utils/bindEvent.test.ts b/node_modules/@mswjs/interceptors/src/interceptors/WebSocket/utils/bindEvent.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..7871961f0f24e4665cbddfdd5d2bfe91ee9b7741 --- /dev/null +++ b/node_modules/@mswjs/interceptors/src/interceptors/WebSocket/utils/bindEvent.test.ts @@ -0,0 +1,27 @@ +/** + * @vitest-environment node + */ +import { it, expect } from 'vitest' +import { bindEvent } from './bindEvent' + +it('sets the "target" on the given event', () => { + class Target {} + const target = new Target() + const event = new Event('open') + bindEvent(target, event) + + expect(event.type).toBe('open') + expect(event.target).toEqual(target) +}) + +it('overrides existing "target" on the given event', () => { + class Target {} + const oldTarget = new Target() + const newTarget = new Target() + const event = new Event('open') + bindEvent(oldTarget, event) + bindEvent(newTarget, event) + + expect(event.type).toBe('open') + expect(event.target).toEqual(newTarget) +}) diff --git a/node_modules/@mswjs/interceptors/src/interceptors/WebSocket/utils/bindEvent.ts b/node_modules/@mswjs/interceptors/src/interceptors/WebSocket/utils/bindEvent.ts new file mode 100644 index 0000000000000000000000000000000000000000..8efa6820263a83eb6ff9d892ad92c19ca2074626 --- /dev/null +++ b/node_modules/@mswjs/interceptors/src/interceptors/WebSocket/utils/bindEvent.ts @@ -0,0 +1,21 @@ +type EventWithTarget = E & { target: T } + +export function bindEvent( + target: T, + event: E +): EventWithTarget { + Object.defineProperties(event, { + target: { + value: target, + enumerable: true, + writable: true, + }, + currentTarget: { + value: target, + enumerable: true, + writable: true, + }, + }) + + return event as EventWithTarget +} diff --git a/node_modules/@mswjs/interceptors/src/interceptors/WebSocket/utils/events.test.ts b/node_modules/@mswjs/interceptors/src/interceptors/WebSocket/utils/events.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..84a2116335b1ca8a9f11f74e1d52023ec2e7a425 --- /dev/null +++ b/node_modules/@mswjs/interceptors/src/interceptors/WebSocket/utils/events.test.ts @@ -0,0 +1,101 @@ +/** + * @vitest-environment node + */ +import { describe, it, expect } from 'vitest' +import { CancelableMessageEvent, CloseEvent } from './events' + +describe(CancelableMessageEvent, () => { + it('initiates with the right defaults', () => { + const event = new CancelableMessageEvent('message', { + data: 'hello', + }) + + expect(event).toBeInstanceOf(MessageEvent) + expect(event.type).toBe('message') + expect(event.data).toBe('hello') + expect(event.cancelable).toBe(false) + expect(event.defaultPrevented).toBe(false) + }) + + it('initiates a cancelable event', () => { + const event = new CancelableMessageEvent('message', { + data: 'hello', + cancelable: true, + }) + + expect(event).toBeInstanceOf(MessageEvent) + expect(event.type).toBe('message') + expect(event.data).toBe('hello') + expect(event.cancelable).toBe(true) + expect(event.defaultPrevented).toBe(false) + }) + + it('cancels a cancelable event when calling "preventDefault()"', () => { + const event = new CancelableMessageEvent('message', { + data: 'hello', + cancelable: true, + }) + + expect(event.defaultPrevented).toBe(false) + event.preventDefault() + expect(event.defaultPrevented).toBe(true) + }) + + it('does nothing when calling "preventDefault()" on a non-cancelable event', () => { + const event = new CancelableMessageEvent('message', { + data: 'hello', + }) + + expect(event.defaultPrevented).toBe(false) + event.preventDefault() + expect(event.defaultPrevented).toBe(false) + }) + + it('supports setting the "cancelable" value directly', () => { + const event = new CancelableMessageEvent('message', {}) + /** + * @note HappyDOM sets the "cancelable" and "preventDefault" + * event properties directly. That's no-op as far as I know + * but they do it and we have to account for that. + */ + event.cancelable = true + expect(event.cancelable).toBe(true) + }) + + it('supports setting the "defaultPrevented" value directly', () => { + const event = new CancelableMessageEvent('message', {}) + /** + * @note HappyDOM sets the "cancelable" and "preventDefault" + * event properties directly. That's no-op as far as I know + * but they do it and we have to account for that. + */ + event.defaultPrevented = true + expect(event.defaultPrevented).toBe(true) + }) +}) + +describe(CloseEvent, () => { + it('initiates with the right defaults', () => { + const event = new CloseEvent('close') + + expect(event).toBeInstanceOf(Event) + expect(event.type).toBe('close') + expect(event.code).toBe(0) + expect(event.reason).toBe('') + expect(event.wasClean).toBe(false) + }) + + it('initiates with custom values', () => { + const event = new CloseEvent('close', { + code: 1003, + reason: 'close reason', + wasClean: true, + }) + + expect(event).toBeInstanceOf(Event) + expect(event.type).toBe('close') + expect(event.code).toBe(1003) + expect(event.reason).toBe('close reason') + expect(event.wasClean).toBe(true) + }) +}) diff --git a/node_modules/@mswjs/interceptors/src/interceptors/WebSocket/utils/events.ts b/node_modules/@mswjs/interceptors/src/interceptors/WebSocket/utils/events.ts new file mode 100644 index 0000000000000000000000000000000000000000..cb4c059ff630767e207e1ecd69afeaeccd57cf39 --- /dev/null +++ b/node_modules/@mswjs/interceptors/src/interceptors/WebSocket/utils/events.ts @@ -0,0 +1,94 @@ +const kCancelable = Symbol('kCancelable') +const kDefaultPrevented = Symbol('kDefaultPrevented') + +/** + * A `MessageEvent` superset that supports event cancellation + * in Node.js. It's rather non-intrusive so it can be safely + * used in the browser as well. + * + * @see https://github.com/nodejs/node/issues/51767 + */ +export class CancelableMessageEvent extends MessageEvent { + [kCancelable]: boolean; + [kDefaultPrevented]: boolean + + constructor(type: string, init: MessageEventInit) { + super(type, init) + this[kCancelable] = !!init.cancelable + this[kDefaultPrevented] = false + } + + get cancelable() { + return this[kCancelable] + } + + set cancelable(nextCancelable) { + this[kCancelable] = nextCancelable + } + + get defaultPrevented() { + return this[kDefaultPrevented] + } + + set defaultPrevented(nextDefaultPrevented) { + this[kDefaultPrevented] = nextDefaultPrevented + } + + public preventDefault(): void { + if (this.cancelable && !this[kDefaultPrevented]) { + this[kDefaultPrevented] = true + } + } +} + +interface CloseEventInit extends EventInit { + code?: number + reason?: string + wasClean?: boolean +} + +export class CloseEvent extends Event { + public code: number + public reason: string + public wasClean: boolean + + constructor(type: string, init: CloseEventInit = {}) { + super(type, init) + this.code = init.code === undefined ? 0 : init.code + this.reason = init.reason === undefined ? '' : init.reason + this.wasClean = init.wasClean === undefined ? false : init.wasClean + } +} + +export class CancelableCloseEvent extends CloseEvent { + [kCancelable]: boolean; + [kDefaultPrevented]: boolean + + constructor(type: string, init: CloseEventInit = {}) { + super(type, init) + this[kCancelable] = !!init.cancelable + this[kDefaultPrevented] = false + } + + get cancelable() { + return this[kCancelable] + } + + set cancelable(nextCancelable) { + this[kCancelable] = nextCancelable + } + + get defaultPrevented() { + return this[kDefaultPrevented] + } + + set defaultPrevented(nextDefaultPrevented) { + this[kDefaultPrevented] = nextDefaultPrevented + } + + public preventDefault(): void { + if (this.cancelable && !this[kDefaultPrevented]) { + this[kDefaultPrevented] = true + } + } +} diff --git a/node_modules/@mswjs/interceptors/src/interceptors/XMLHttpRequest/XMLHttpRequestController.ts b/node_modules/@mswjs/interceptors/src/interceptors/XMLHttpRequest/XMLHttpRequestController.ts new file mode 100644 index 0000000000000000000000000000000000000000..9d96407c0d2065b12426c274ff2b43922f071d7a --- /dev/null +++ b/node_modules/@mswjs/interceptors/src/interceptors/XMLHttpRequest/XMLHttpRequestController.ts @@ -0,0 +1,734 @@ +import { invariant } from 'outvariant' +import { isNodeProcess } from 'is-node-process' +import type { Logger } from '@open-draft/logger' +import { concatArrayBuffer } from './utils/concatArrayBuffer' +import { createEvent } from './utils/createEvent' +import { + decodeBuffer, + encodeBuffer, + toArrayBuffer, +} from '../../utils/bufferUtils' +import { createProxy } from '../../utils/createProxy' +import { isDomParserSupportedType } from './utils/isDomParserSupportedType' +import { parseJson } from '../../utils/parseJson' +import { createResponse } from './utils/createResponse' +import { INTERNAL_REQUEST_ID_HEADER_NAME } from '../../Interceptor' +import { createRequestId } from '../../createRequestId' +import { getBodyByteLength } from './utils/getBodyByteLength' + +const kIsRequestHandled = Symbol('kIsRequestHandled') +const IS_NODE = isNodeProcess() +const kFetchRequest = Symbol('kFetchRequest') + +/** + * An `XMLHttpRequest` instance controller that allows us + * to handle any given request instance (e.g. responding to it). + */ +export class XMLHttpRequestController { + public request: XMLHttpRequest + public requestId: string + public onRequest?: ( + this: XMLHttpRequestController, + args: { + request: Request + requestId: string + } + ) => Promise + public onResponse?: ( + this: XMLHttpRequestController, + args: { + response: Response + isMockedResponse: boolean + request: Request + requestId: string + } + ) => void; + + [kIsRequestHandled]: boolean; + [kFetchRequest]?: Request + private method: string = 'GET' + private url: URL = null as any + private requestHeaders: Headers + private responseBuffer: Uint8Array + private events: Map> + private uploadEvents: Map< + keyof XMLHttpRequestEventTargetEventMap, + Array + > + + constructor(readonly initialRequest: XMLHttpRequest, public logger: Logger) { + this[kIsRequestHandled] = false + + this.events = new Map() + this.uploadEvents = new Map() + this.requestId = createRequestId() + this.requestHeaders = new Headers() + this.responseBuffer = new Uint8Array() + + this.request = createProxy(initialRequest, { + setProperty: ([propertyName, nextValue], invoke) => { + switch (propertyName) { + case 'ontimeout': { + const eventName = propertyName.slice( + 2 + ) as keyof XMLHttpRequestEventTargetEventMap + + /** + * @note Proxy callbacks to event listeners because JSDOM has trouble + * translating these properties to callbacks. It seemed to be operating + * on events exclusively. + */ + this.request.addEventListener(eventName, nextValue as any) + + return invoke() + } + + default: { + return invoke() + } + } + }, + methodCall: ([methodName, args], invoke) => { + switch (methodName) { + case 'open': { + const [method, url] = args as [string, string | undefined] + + if (typeof url === 'undefined') { + this.method = 'GET' + this.url = toAbsoluteUrl(method) + } else { + this.method = method + this.url = toAbsoluteUrl(url) + } + + this.logger = this.logger.extend(`${this.method} ${this.url.href}`) + this.logger.info('open', this.method, this.url.href) + + return invoke() + } + + case 'addEventListener': { + const [eventName, listener] = args as [ + keyof XMLHttpRequestEventTargetEventMap, + Function + ] + + this.registerEvent(eventName, listener) + this.logger.info('addEventListener', eventName, listener) + + return invoke() + } + + case 'setRequestHeader': { + const [name, value] = args as [string, string] + this.requestHeaders.set(name, value) + + this.logger.info('setRequestHeader', name, value) + + return invoke() + } + + case 'send': { + const [body] = args as [ + body?: XMLHttpRequestBodyInit | Document | null + ] + + this.request.addEventListener('load', () => { + if (typeof this.onResponse !== 'undefined') { + // Create a Fetch API Response representation of whichever + // response this XMLHttpRequest received. Note those may + // be either a mocked and the original response. + const fetchResponse = createResponse( + this.request, + /** + * The `response` property is the right way to read + * the ambiguous response body, as the request's "responseType" may differ. + * @see https://xhr.spec.whatwg.org/#the-response-attribute + */ + this.request.response + ) + + // Notify the consumer about the response. + this.onResponse.call(this, { + response: fetchResponse, + isMockedResponse: this[kIsRequestHandled], + request: fetchRequest, + requestId: this.requestId!, + }) + } + }) + + const requestBody = + typeof body === 'string' ? encodeBuffer(body) : body + + // Delegate request handling to the consumer. + const fetchRequest = this.toFetchApiRequest(requestBody) + this[kFetchRequest] = fetchRequest.clone() + + const onceRequestSettled = + this.onRequest?.call(this, { + request: fetchRequest, + requestId: this.requestId!, + }) || Promise.resolve() + + onceRequestSettled.finally(() => { + // If the consumer didn't handle the request (called `.respondWith()`) perform it as-is. + if (!this[kIsRequestHandled]) { + this.logger.info( + 'request callback settled but request has not been handled (readystate %d), performing as-is...', + this.request.readyState + ) + + /** + * @note Set the intercepted request ID on the original request in Node.js + * so that if it triggers any other interceptors, they don't attempt + * to process it once again. + * + * For instance, XMLHttpRequest is often implemented via "http.ClientRequest" + * and we don't want for both XHR and ClientRequest interceptors to + * handle the same request at the same time (e.g. emit the "response" event twice). + */ + if (IS_NODE) { + this.request.setRequestHeader( + INTERNAL_REQUEST_ID_HEADER_NAME, + this.requestId! + ) + } + + return invoke() + } + }) + + break + } + + default: { + return invoke() + } + } + }, + }) + + /** + * Proxy the `.upload` property to gather the event listeners/callbacks. + */ + define( + this.request, + 'upload', + createProxy(this.request.upload, { + setProperty: ([propertyName, nextValue], invoke) => { + switch (propertyName) { + case 'onloadstart': + case 'onprogress': + case 'onaboart': + case 'onerror': + case 'onload': + case 'ontimeout': + case 'onloadend': { + const eventName = propertyName.slice( + 2 + ) as keyof XMLHttpRequestEventTargetEventMap + + this.registerUploadEvent(eventName, nextValue as Function) + } + } + + return invoke() + }, + methodCall: ([methodName, args], invoke) => { + switch (methodName) { + case 'addEventListener': { + const [eventName, listener] = args as [ + keyof XMLHttpRequestEventTargetEventMap, + Function + ] + this.registerUploadEvent(eventName, listener) + this.logger.info('upload.addEventListener', eventName, listener) + + return invoke() + } + } + }, + }) + ) + } + + private registerEvent( + eventName: keyof XMLHttpRequestEventTargetEventMap, + listener: Function + ): void { + const prevEvents = this.events.get(eventName) || [] + const nextEvents = prevEvents.concat(listener) + this.events.set(eventName, nextEvents) + + this.logger.info('registered event "%s"', eventName, listener) + } + + private registerUploadEvent( + eventName: keyof XMLHttpRequestEventTargetEventMap, + listener: Function + ): void { + const prevEvents = this.uploadEvents.get(eventName) || [] + const nextEvents = prevEvents.concat(listener) + this.uploadEvents.set(eventName, nextEvents) + + this.logger.info('registered upload event "%s"', eventName, listener) + } + + /** + * Responds to the current request with the given + * Fetch API `Response` instance. + */ + public async respondWith(response: Response): Promise { + /** + * @note Since `XMLHttpRequestController` delegates the handling of the responses + * to the "load" event listener that doesn't distinguish between the mocked and original + * responses, mark the request that had a mocked response with a corresponding symbol. + * + * Mark this request as having a mocked response immediately since + * calculating request/response total body length is asynchronous. + */ + this[kIsRequestHandled] = true + + /** + * Dispatch request upload events for requests with a body. + * @see https://github.com/mswjs/interceptors/issues/573 + */ + if (this[kFetchRequest]) { + const totalRequestBodyLength = await getBodyByteLength( + this[kFetchRequest] + ) + + this.trigger('loadstart', this.request.upload, { + loaded: 0, + total: totalRequestBodyLength, + }) + this.trigger('progress', this.request.upload, { + loaded: totalRequestBodyLength, + total: totalRequestBodyLength, + }) + this.trigger('load', this.request.upload, { + loaded: totalRequestBodyLength, + total: totalRequestBodyLength, + }) + this.trigger('loadend', this.request.upload, { + loaded: totalRequestBodyLength, + total: totalRequestBodyLength, + }) + } + + this.logger.info( + 'responding with a mocked response: %d %s', + response.status, + response.statusText + ) + + define(this.request, 'status', response.status) + define(this.request, 'statusText', response.statusText) + define(this.request, 'responseURL', this.url.href) + + this.request.getResponseHeader = new Proxy(this.request.getResponseHeader, { + apply: (_, __, args: [name: string]) => { + this.logger.info('getResponseHeader', args[0]) + + if (this.request.readyState < this.request.HEADERS_RECEIVED) { + this.logger.info('headers not received yet, returning null') + + // Headers not received yet, nothing to return. + return null + } + + const headerValue = response.headers.get(args[0]) + this.logger.info( + 'resolved response header "%s" to', + args[0], + headerValue + ) + + return headerValue + }, + }) + + this.request.getAllResponseHeaders = new Proxy( + this.request.getAllResponseHeaders, + { + apply: () => { + this.logger.info('getAllResponseHeaders') + + if (this.request.readyState < this.request.HEADERS_RECEIVED) { + this.logger.info('headers not received yet, returning empty string') + + // Headers not received yet, nothing to return. + return '' + } + + const headersList = Array.from(response.headers.entries()) + const allHeaders = headersList + .map(([headerName, headerValue]) => { + return `${headerName}: ${headerValue}` + }) + .join('\r\n') + + this.logger.info('resolved all response headers to', allHeaders) + + return allHeaders + }, + } + ) + + // Update the response getters to resolve against the mocked response. + Object.defineProperties(this.request, { + response: { + enumerable: true, + configurable: false, + get: () => this.response, + }, + responseText: { + enumerable: true, + configurable: false, + get: () => this.responseText, + }, + responseXML: { + enumerable: true, + configurable: false, + get: () => this.responseXML, + }, + }) + + const totalResponseBodyLength = await getBodyByteLength(response.clone()) + + this.logger.info('calculated response body length', totalResponseBodyLength) + + this.trigger('loadstart', this.request, { + loaded: 0, + total: totalResponseBodyLength, + }) + + this.setReadyState(this.request.HEADERS_RECEIVED) + this.setReadyState(this.request.LOADING) + + const finalizeResponse = () => { + this.logger.info('finalizing the mocked response...') + + this.setReadyState(this.request.DONE) + + this.trigger('load', this.request, { + loaded: this.responseBuffer.byteLength, + total: totalResponseBodyLength, + }) + + this.trigger('loadend', this.request, { + loaded: this.responseBuffer.byteLength, + total: totalResponseBodyLength, + }) + } + + if (response.body) { + this.logger.info('mocked response has body, streaming...') + + const reader = response.body.getReader() + + const readNextResponseBodyChunk = async () => { + const { value, done } = await reader.read() + + if (done) { + this.logger.info('response body stream done!') + finalizeResponse() + return + } + + if (value) { + this.logger.info('read response body chunk:', value) + this.responseBuffer = concatArrayBuffer(this.responseBuffer, value) + + this.trigger('progress', this.request, { + loaded: this.responseBuffer.byteLength, + total: totalResponseBodyLength, + }) + } + + readNextResponseBodyChunk() + } + + readNextResponseBodyChunk() + } else { + finalizeResponse() + } + } + + private responseBufferToText(): string { + return decodeBuffer(this.responseBuffer) + } + + get response(): unknown { + this.logger.info( + 'getResponse (responseType: %s)', + this.request.responseType + ) + + if (this.request.readyState !== this.request.DONE) { + return null + } + + switch (this.request.responseType) { + case 'json': { + const responseJson = parseJson(this.responseBufferToText()) + this.logger.info('resolved response JSON', responseJson) + + return responseJson + } + + case 'arraybuffer': { + const arrayBuffer = toArrayBuffer(this.responseBuffer) + this.logger.info('resolved response ArrayBuffer', arrayBuffer) + + return arrayBuffer + } + + case 'blob': { + const mimeType = + this.request.getResponseHeader('Content-Type') || 'text/plain' + const responseBlob = new Blob([this.responseBufferToText()], { + type: mimeType, + }) + + this.logger.info( + 'resolved response Blob (mime type: %s)', + responseBlob, + mimeType + ) + + return responseBlob + } + + default: { + const responseText = this.responseBufferToText() + this.logger.info( + 'resolving "%s" response type as text', + this.request.responseType, + responseText + ) + + return responseText + } + } + } + + get responseText(): string { + /** + * Throw when trying to read the response body as text when the + * "responseType" doesn't expect text. This just respects the spec better. + * @see https://xhr.spec.whatwg.org/#the-responsetext-attribute + */ + invariant( + this.request.responseType === '' || this.request.responseType === 'text', + 'InvalidStateError: The object is in invalid state.' + ) + + if ( + this.request.readyState !== this.request.LOADING && + this.request.readyState !== this.request.DONE + ) { + return '' + } + + const responseText = this.responseBufferToText() + this.logger.info('getResponseText: "%s"', responseText) + + return responseText + } + + get responseXML(): Document | null { + invariant( + this.request.responseType === '' || + this.request.responseType === 'document', + 'InvalidStateError: The object is in invalid state.' + ) + + if (this.request.readyState !== this.request.DONE) { + return null + } + + const contentType = this.request.getResponseHeader('Content-Type') || '' + + if (typeof DOMParser === 'undefined') { + console.warn( + 'Cannot retrieve XMLHttpRequest response body as XML: DOMParser is not defined. You are likely using an environment that is not browser or does not polyfill browser globals correctly.' + ) + return null + } + + if (isDomParserSupportedType(contentType)) { + return new DOMParser().parseFromString( + this.responseBufferToText(), + contentType + ) + } + + return null + } + + public errorWith(error?: Error): void { + /** + * @note Mark this request as handled even if it received a mock error. + * This prevents the controller from trying to perform this request as-is. + */ + this[kIsRequestHandled] = true + this.logger.info('responding with an error') + + this.setReadyState(this.request.DONE) + this.trigger('error', this.request) + this.trigger('loadend', this.request) + } + + /** + * Transitions this request's `readyState` to the given one. + */ + private setReadyState(nextReadyState: number): void { + this.logger.info( + 'setReadyState: %d -> %d', + this.request.readyState, + nextReadyState + ) + + if (this.request.readyState === nextReadyState) { + this.logger.info('ready state identical, skipping transition...') + return + } + + define(this.request, 'readyState', nextReadyState) + + this.logger.info('set readyState to: %d', nextReadyState) + + if (nextReadyState !== this.request.UNSENT) { + this.logger.info('triggerring "readystatechange" event...') + + this.trigger('readystatechange', this.request) + } + } + + /** + * Triggers given event on the `XMLHttpRequest` instance. + */ + private trigger< + EventName extends keyof (XMLHttpRequestEventTargetEventMap & { + readystatechange: ProgressEvent + }) + >( + eventName: EventName, + target: XMLHttpRequest | XMLHttpRequestUpload, + options?: ProgressEventInit + ): void { + const callback = (target as XMLHttpRequest)[`on${eventName}`] + const event = createEvent(target, eventName, options) + + this.logger.info('trigger "%s"', eventName, options || '') + + // Invoke direct callbacks. + if (typeof callback === 'function') { + this.logger.info('found a direct "%s" callback, calling...', eventName) + callback.call(target as XMLHttpRequest, event) + } + + // Invoke event listeners. + const events = + target instanceof XMLHttpRequestUpload ? this.uploadEvents : this.events + + for (const [registeredEventName, listeners] of events) { + if (registeredEventName === eventName) { + this.logger.info( + 'found %d listener(s) for "%s" event, calling...', + listeners.length, + eventName + ) + + listeners.forEach((listener) => listener.call(target, event)) + } + } + } + + /** + * Converts this `XMLHttpRequest` instance into a Fetch API `Request` instance. + */ + private toFetchApiRequest( + body: XMLHttpRequestBodyInit | Document | null | undefined + ): Request { + this.logger.info('converting request to a Fetch API Request...') + + // If the `Document` is used as the body of this XMLHttpRequest, + // set its inner text as the Fetch API Request body. + const resolvedBody = + body instanceof Document ? body.documentElement.innerText : body + + const fetchRequest = new Request(this.url.href, { + method: this.method, + headers: this.requestHeaders, + /** + * @see https://xhr.spec.whatwg.org/#cross-origin-credentials + */ + credentials: this.request.withCredentials ? 'include' : 'same-origin', + body: ['GET', 'HEAD'].includes(this.method.toUpperCase()) + ? null + : resolvedBody, + }) + + const proxyHeaders = createProxy(fetchRequest.headers, { + methodCall: ([methodName, args], invoke) => { + // Forward the latest state of the internal request headers + // because the interceptor might have modified them + // without responding to the request. + switch (methodName) { + case 'append': + case 'set': { + const [headerName, headerValue] = args as [string, string] + this.request.setRequestHeader(headerName, headerValue) + break + } + + case 'delete': { + const [headerName] = args as [string] + console.warn( + `XMLHttpRequest: Cannot remove a "${headerName}" header from the Fetch API representation of the "${fetchRequest.method} ${fetchRequest.url}" request. XMLHttpRequest headers cannot be removed.` + ) + break + } + } + + return invoke() + }, + }) + define(fetchRequest, 'headers', proxyHeaders) + + this.logger.info('converted request to a Fetch API Request!', fetchRequest) + + return fetchRequest + } +} + +function toAbsoluteUrl(url: string | URL): URL { + /** + * @note XMLHttpRequest interceptor may run in environments + * that implement XMLHttpRequest but don't implement "location" + * (for example, React Native). If that's the case, return the + * input URL as-is (nothing to be relative to). + * @see https://github.com/mswjs/msw/issues/1777 + */ + if (typeof location === 'undefined') { + return new URL(url) + } + + return new URL(url.toString(), location.href) +} + +function define( + target: object, + property: string | symbol, + value: unknown +): void { + Reflect.defineProperty(target, property, { + // Ensure writable properties to allow redefining readonly properties. + writable: true, + enumerable: true, + value, + }) +} diff --git a/node_modules/@mswjs/interceptors/src/interceptors/XMLHttpRequest/XMLHttpRequestProxy.ts b/node_modules/@mswjs/interceptors/src/interceptors/XMLHttpRequest/XMLHttpRequestProxy.ts new file mode 100644 index 0000000000000000000000000000000000000000..997f06fa0bbfa122a9e6c0756ac0172bcc65b213 --- /dev/null +++ b/node_modules/@mswjs/interceptors/src/interceptors/XMLHttpRequest/XMLHttpRequestProxy.ts @@ -0,0 +1,118 @@ +import type { Logger } from '@open-draft/logger' +import { XMLHttpRequestEmitter } from '.' +import { RequestController } from '../../RequestController' +import { XMLHttpRequestController } from './XMLHttpRequestController' +import { handleRequest } from '../../utils/handleRequest' + +export interface XMLHttpRequestProxyOptions { + emitter: XMLHttpRequestEmitter + logger: Logger +} + +/** + * Create a proxied `XMLHttpRequest` class. + * The proxied class establishes spies on certain methods, + * allowing us to intercept requests and respond to them. + */ +export function createXMLHttpRequestProxy({ + emitter, + logger, +}: XMLHttpRequestProxyOptions) { + const XMLHttpRequestProxy = new Proxy(globalThis.XMLHttpRequest, { + construct(target, args, newTarget) { + logger.info('constructed new XMLHttpRequest') + + const originalRequest = Reflect.construct( + target, + args, + newTarget + ) as XMLHttpRequest + + /** + * @note Forward prototype descriptors onto the proxied object. + * XMLHttpRequest is implemented in JSDOM in a way that assigns + * a bunch of descriptors, like "set responseType()" on the prototype. + * With this propagation, we make sure that those descriptors trigger + * when the user operates with the proxied request instance. + */ + const prototypeDescriptors = Object.getOwnPropertyDescriptors( + target.prototype + ) + for (const propertyName in prototypeDescriptors) { + Reflect.defineProperty( + originalRequest, + propertyName, + prototypeDescriptors[propertyName] + ) + } + + const xhrRequestController = new XMLHttpRequestController( + originalRequest, + logger + ) + + xhrRequestController.onRequest = async function ({ request, requestId }) { + const controller = new RequestController(request) + + this.logger.info('awaiting mocked response...') + + this.logger.info( + 'emitting the "request" event for %s listener(s)...', + emitter.listenerCount('request') + ) + + const isRequestHandled = await handleRequest({ + request, + requestId, + controller, + emitter, + onResponse: async (response) => { + await this.respondWith(response) + }, + onRequestError: () => { + this.errorWith(new TypeError('Network error')) + }, + onError: (error) => { + this.logger.info('request errored!', { error }) + + if (error instanceof Error) { + this.errorWith(error) + } + }, + }) + + if (!isRequestHandled) { + this.logger.info( + 'no mocked response received, performing request as-is...' + ) + } + } + + xhrRequestController.onResponse = async function ({ + response, + isMockedResponse, + request, + requestId, + }) { + this.logger.info( + 'emitting the "response" event for %s listener(s)...', + emitter.listenerCount('response') + ) + + emitter.emit('response', { + response, + isMockedResponse, + request, + requestId, + }) + } + + // Return the proxied request from the controller + // so that the controller can react to the consumer's interactions + // with this request (opening/sending/etc). + return xhrRequestController.request + }, + }) + + return XMLHttpRequestProxy +} diff --git a/node_modules/@mswjs/interceptors/src/interceptors/XMLHttpRequest/index.ts b/node_modules/@mswjs/interceptors/src/interceptors/XMLHttpRequest/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..6b5208c702fcf18accbdd3596efd3eeb6eef5bb4 --- /dev/null +++ b/node_modules/@mswjs/interceptors/src/interceptors/XMLHttpRequest/index.ts @@ -0,0 +1,61 @@ +import { invariant } from 'outvariant' +import { Emitter } from 'strict-event-emitter' +import { HttpRequestEventMap, IS_PATCHED_MODULE } from '../../glossary' +import { Interceptor } from '../../Interceptor' +import { createXMLHttpRequestProxy } from './XMLHttpRequestProxy' +import { hasConfigurableGlobal } from '../../utils/hasConfigurableGlobal' + +export type XMLHttpRequestEmitter = Emitter + +export class XMLHttpRequestInterceptor extends Interceptor { + static interceptorSymbol = Symbol('xhr') + + constructor() { + super(XMLHttpRequestInterceptor.interceptorSymbol) + } + + protected checkEnvironment() { + return hasConfigurableGlobal('XMLHttpRequest') + } + + protected setup() { + const logger = this.logger.extend('setup') + + logger.info('patching "XMLHttpRequest" module...') + + const PureXMLHttpRequest = globalThis.XMLHttpRequest + + invariant( + !(PureXMLHttpRequest as any)[IS_PATCHED_MODULE], + 'Failed to patch the "XMLHttpRequest" module: already patched.' + ) + + globalThis.XMLHttpRequest = createXMLHttpRequestProxy({ + emitter: this.emitter, + logger: this.logger, + }) + + logger.info( + 'native "XMLHttpRequest" module patched!', + globalThis.XMLHttpRequest.name + ) + + Object.defineProperty(globalThis.XMLHttpRequest, IS_PATCHED_MODULE, { + enumerable: true, + configurable: true, + value: true, + }) + + this.subscriptions.push(() => { + Object.defineProperty(globalThis.XMLHttpRequest, IS_PATCHED_MODULE, { + value: undefined, + }) + + globalThis.XMLHttpRequest = PureXMLHttpRequest + logger.info( + 'native "XMLHttpRequest" module restored!', + globalThis.XMLHttpRequest.name + ) + }) + } +} diff --git a/node_modules/@mswjs/interceptors/src/interceptors/XMLHttpRequest/polyfills/EventPolyfill.ts b/node_modules/@mswjs/interceptors/src/interceptors/XMLHttpRequest/polyfills/EventPolyfill.ts new file mode 100644 index 0000000000000000000000000000000000000000..4c44e50956064d9ad94f7800555a662901b292f8 --- /dev/null +++ b/node_modules/@mswjs/interceptors/src/interceptors/XMLHttpRequest/polyfills/EventPolyfill.ts @@ -0,0 +1,51 @@ +export class EventPolyfill implements Event { + readonly NONE = 0 + readonly CAPTURING_PHASE = 1 + readonly AT_TARGET = 2 + readonly BUBBLING_PHASE = 3 + + public type: string = '' + public srcElement: EventTarget | null = null + public target: EventTarget | null + public currentTarget: EventTarget | null = null + public eventPhase: number = 0 + public timeStamp: number + public isTrusted: boolean = true + public composed: boolean = false + public cancelable: boolean = true + public defaultPrevented: boolean = false + public bubbles: boolean = true + public lengthComputable: boolean = true + public loaded: number = 0 + public total: number = 0 + + cancelBubble: boolean = false + returnValue: boolean = true + + constructor( + type: string, + options?: { target: EventTarget; currentTarget: EventTarget } + ) { + this.type = type + this.target = options?.target || null + this.currentTarget = options?.currentTarget || null + this.timeStamp = Date.now() + } + + public composedPath(): EventTarget[] { + return [] + } + + public initEvent(type: string, bubbles?: boolean, cancelable?: boolean) { + this.type = type + this.bubbles = !!bubbles + this.cancelable = !!cancelable + } + + public preventDefault() { + this.defaultPrevented = true + } + + public stopPropagation() {} + public stopImmediatePropagation() {} +} diff --git a/node_modules/@mswjs/interceptors/src/interceptors/XMLHttpRequest/polyfills/ProgressEventPolyfill.ts b/node_modules/@mswjs/interceptors/src/interceptors/XMLHttpRequest/polyfills/ProgressEventPolyfill.ts new file mode 100644 index 0000000000000000000000000000000000000000..20a318816ab8c5f7976e6f3ab9aa237511bd8d00 --- /dev/null +++ b/node_modules/@mswjs/interceptors/src/interceptors/XMLHttpRequest/polyfills/ProgressEventPolyfill.ts @@ -0,0 +1,17 @@ +import { EventPolyfill } from './EventPolyfill' + +export class ProgressEventPolyfill extends EventPolyfill { + readonly lengthComputable: boolean + readonly composed: boolean + readonly loaded: number + readonly total: number + + constructor(type: string, init?: ProgressEventInit) { + super(type) + + this.lengthComputable = init?.lengthComputable || false + this.composed = init?.composed || false + this.loaded = init?.loaded || 0 + this.total = init?.total || 0 + } +} diff --git a/node_modules/@mswjs/interceptors/src/interceptors/XMLHttpRequest/utils/concatArrayBuffer.ts b/node_modules/@mswjs/interceptors/src/interceptors/XMLHttpRequest/utils/concatArrayBuffer.ts new file mode 100644 index 0000000000000000000000000000000000000000..e8b9fb46606a36ebf169aaf45b9e0a3864010bb3 --- /dev/null +++ b/node_modules/@mswjs/interceptors/src/interceptors/XMLHttpRequest/utils/concatArrayBuffer.ts @@ -0,0 +1,12 @@ +/** + * Concatenate two `Uint8Array` buffers. + */ +export function concatArrayBuffer( + left: Uint8Array, + right: Uint8Array +): Uint8Array { + const result = new Uint8Array(left.byteLength + right.byteLength) + result.set(left, 0) + result.set(right, left.byteLength) + return result +} diff --git a/node_modules/@mswjs/interceptors/src/interceptors/XMLHttpRequest/utils/concateArrayBuffer.test.ts b/node_modules/@mswjs/interceptors/src/interceptors/XMLHttpRequest/utils/concateArrayBuffer.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..fab59abd6225d4c8e6671a1a2c208fff88ceba07 --- /dev/null +++ b/node_modules/@mswjs/interceptors/src/interceptors/XMLHttpRequest/utils/concateArrayBuffer.test.ts @@ -0,0 +1,12 @@ +import { it, expect } from 'vitest' +import { concatArrayBuffer } from './concatArrayBuffer' + +const encoder = new TextEncoder() + +it('concatenates two Uint8Array buffers', () => { + const result = concatArrayBuffer( + encoder.encode('hello'), + encoder.encode('world') + ) + expect(result).toEqual(encoder.encode('helloworld')) +}) diff --git a/node_modules/@mswjs/interceptors/src/interceptors/XMLHttpRequest/utils/createEvent.test.ts b/node_modules/@mswjs/interceptors/src/interceptors/XMLHttpRequest/utils/createEvent.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..0b23216913ebdc16e6c5749e007da19201aba589 --- /dev/null +++ b/node_modules/@mswjs/interceptors/src/interceptors/XMLHttpRequest/utils/createEvent.test.ts @@ -0,0 +1,26 @@ +// @vitest-environment jsdom +import { it, expect } from 'vitest' +import { createEvent } from './createEvent' +import { EventPolyfill } from '../polyfills/EventPolyfill' + +const request = new XMLHttpRequest() +request.open('POST', '/user') + +it('returns an EventPolyfill instance with the given target set', () => { + const event = createEvent(request, 'my-event') + const target = event.target as XMLHttpRequest + + expect(event).toBeInstanceOf(EventPolyfill) + expect(target).toBeInstanceOf(XMLHttpRequest) +}) + +it('returns the ProgressEvent instance', () => { + const event = createEvent(request, 'load', { + loaded: 100, + total: 500, + }) + + expect(event).toBeInstanceOf(ProgressEvent) + expect(event.loaded).toBe(100) + expect(event.total).toBe(500) +}) diff --git a/node_modules/@mswjs/interceptors/src/interceptors/XMLHttpRequest/utils/createEvent.ts b/node_modules/@mswjs/interceptors/src/interceptors/XMLHttpRequest/utils/createEvent.ts new file mode 100644 index 0000000000000000000000000000000000000000..be87b3692760dd3cf814d8852e493c5d591440d9 --- /dev/null +++ b/node_modules/@mswjs/interceptors/src/interceptors/XMLHttpRequest/utils/createEvent.ts @@ -0,0 +1,41 @@ +import { EventPolyfill } from '../polyfills/EventPolyfill' +import { ProgressEventPolyfill } from '../polyfills/ProgressEventPolyfill' + +const SUPPORTS_PROGRESS_EVENT = typeof ProgressEvent !== 'undefined' + +export function createEvent( + target: XMLHttpRequest | XMLHttpRequestUpload, + type: string, + init?: ProgressEventInit +): EventPolyfill | ProgressEvent { + const progressEvents = [ + 'error', + 'progress', + 'loadstart', + 'loadend', + 'load', + 'timeout', + 'abort', + ] + + /** + * `ProgressEvent` is not supported in React Native. + * @see https://github.com/mswjs/interceptors/issues/40 + */ + const ProgressEventClass = SUPPORTS_PROGRESS_EVENT + ? ProgressEvent + : ProgressEventPolyfill + + const event = progressEvents.includes(type) + ? new ProgressEventClass(type, { + lengthComputable: true, + loaded: init?.loaded || 0, + total: init?.total || 0, + }) + : new EventPolyfill(type, { + target, + currentTarget: target, + }) + + return event +} diff --git a/node_modules/@mswjs/interceptors/src/interceptors/XMLHttpRequest/utils/createResponse.ts b/node_modules/@mswjs/interceptors/src/interceptors/XMLHttpRequest/utils/createResponse.ts new file mode 100644 index 0000000000000000000000000000000000000000..d0e8d1d86824e1acd4cf6e1741b9bb132d1b9ca7 --- /dev/null +++ b/node_modules/@mswjs/interceptors/src/interceptors/XMLHttpRequest/utils/createResponse.ts @@ -0,0 +1,49 @@ +import { FetchResponse } from '../../../utils/fetchUtils' + +/** + * Creates a Fetch API `Response` instance from the given + * `XMLHttpRequest` instance and a response body. + */ +export function createResponse( + request: XMLHttpRequest, + body: BodyInit | null +): Response { + /** + * Handle XMLHttpRequest responses that must have null as the + * response body when represented using Fetch API Response. + * XMLHttpRequest response will always have an empty string + * as the "request.response" in those cases, resulting in an error + * when constructing a Response instance. + * @see https://github.com/mswjs/interceptors/issues/379 + */ + const responseBodyOrNull = FetchResponse.isResponseWithBody(request.status) + ? body + : null + + return new FetchResponse(responseBodyOrNull, { + url: request.responseURL, + status: request.status, + statusText: request.statusText, + headers: createHeadersFromXMLHttpReqestHeaders( + request.getAllResponseHeaders() + ), + }) +} + +function createHeadersFromXMLHttpReqestHeaders(headersString: string): Headers { + const headers = new Headers() + + const lines = headersString.split(/[\r\n]+/) + for (const line of lines) { + if (line.trim() === '') { + continue + } + + const [name, ...parts] = line.split(': ') + const value = parts.join(': ') + + headers.append(name, value) + } + + return headers +} diff --git a/node_modules/@mswjs/interceptors/src/interceptors/XMLHttpRequest/utils/getBodyByteLength.test.ts b/node_modules/@mswjs/interceptors/src/interceptors/XMLHttpRequest/utils/getBodyByteLength.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..f2a41c8e8ce753eabf12f84a4d7169227c4f295d --- /dev/null +++ b/node_modules/@mswjs/interceptors/src/interceptors/XMLHttpRequest/utils/getBodyByteLength.test.ts @@ -0,0 +1,164 @@ +// @vitest-environment node +import { it, expect } from 'vitest' +import { getBodyByteLength } from './getBodyByteLength' + +const url = 'http://localhost' + +it('returns explicit body length set in the "Content-Length" header', async () => { + await expect( + getBodyByteLength(new Request(url, { headers: { 'Content-Length': '10' } })) + ).resolves.toBe(10) + + await expect( + getBodyByteLength( + new Response('hello', { headers: { 'Content-Length': '5' } }) + ) + ).resolves.toBe(5) +}) + +/** + * Request. + */ + +it('returns 0 for a request with an empty body', async () => { + await expect(getBodyByteLength(new Request(url))).resolves.toBe(0) + await expect( + getBodyByteLength(new Request(url, { method: 'POST', body: null })) + ).resolves.toBe(0) + await expect( + getBodyByteLength(new Request(url, { method: 'POST', body: undefined })) + ).resolves.toBe(0) + await expect( + getBodyByteLength(new Request(url, { method: 'POST', body: '' })) + ).resolves.toBe(0) +}) + +it('calculates body length from the text request body', async () => { + await expect( + getBodyByteLength( + new Request(url, { + method: 'POST', + body: 'hello world', + }) + ) + ).resolves.toBe(11) +}) + +it('calculates body length from the URLSearchParams request body', async () => { + await expect( + getBodyByteLength( + new Request(url, { + method: 'POST', + body: new URLSearchParams([['hello', 'world']]), + }) + ) + ).resolves.toBe(11) +}) + +it('calculates body length from the Blob request body', async () => { + await expect( + getBodyByteLength( + new Request(url, { + method: 'POST', + body: new Blob(['hello world']), + }) + ) + ).resolves.toBe(11) +}) + +it('calculates body length from the ArrayBuffer request body', async () => { + await expect( + getBodyByteLength( + new Request(url, { + method: 'POST', + body: await new Blob(['hello world']).arrayBuffer(), + }) + ) + ).resolves.toBe(11) +}) + +it('calculates body length from the FormData request body', async () => { + const formData = new FormData() + formData.append('hello', 'world') + + await expect( + getBodyByteLength( + new Request(url, { + method: 'POST', + body: formData, + }) + ) + ).resolves.toBe(127) +}) + +it('calculates body length from the ReadableStream request body', async () => { + const stream = new ReadableStream({ + start(controller) { + controller.enqueue(new TextEncoder().encode('hello world')) + controller.close() + }, + }) + + await expect( + getBodyByteLength( + new Request(url, { + method: 'POST', + body: stream, + // @ts-expect-error Undocumented required Undici property. + duplex: 'half', + }) + ) + ).resolves.toBe(11) +}) + +/** + * Response. + */ +it('returns 0 for a response with an empty body', async () => { + await expect(getBodyByteLength(new Response())).resolves.toBe(0) + await expect(getBodyByteLength(new Response(null))).resolves.toBe(0) + await expect(getBodyByteLength(new Response(undefined))).resolves.toBe(0) + await expect(getBodyByteLength(new Response(''))).resolves.toBe(0) +}) + +it('calculates body length from the text response body', async () => { + await expect(getBodyByteLength(new Response('hello world'))).resolves.toBe(11) +}) + +it('calculates body length from the URLSearchParams response body', async () => { + await expect( + getBodyByteLength(new Response(new URLSearchParams([['hello', 'world']]))) + ).resolves.toBe(11) +}) + +it('calculates body length from the Blob response body', async () => { + await expect( + getBodyByteLength(new Response(new Blob(['hello world']))) + ).resolves.toBe(11) +}) + +it('calculates body length from the ArrayBuffer response body', async () => { + await expect( + getBodyByteLength( + new Response(await new Blob(['hello world']).arrayBuffer()) + ) + ).resolves.toBe(11) +}) + +it('calculates body length from the FormData response body', async () => { + const formData = new FormData() + formData.append('hello', 'world') + + await expect(getBodyByteLength(new Response(formData))).resolves.toBe(127) +}) + +it('calculates body length from the ReadableStream response body', async () => { + const stream = new ReadableStream({ + start(controller) { + controller.enqueue(new TextEncoder().encode('hello world')) + controller.close() + }, + }) + + await expect(getBodyByteLength(new Response(stream))).resolves.toBe(11) +}) diff --git a/node_modules/@mswjs/interceptors/src/interceptors/XMLHttpRequest/utils/getBodyByteLength.ts b/node_modules/@mswjs/interceptors/src/interceptors/XMLHttpRequest/utils/getBodyByteLength.ts new file mode 100644 index 0000000000000000000000000000000000000000..dd7655ab0ce9134873a071045e51a98aa3ec59f0 --- /dev/null +++ b/node_modules/@mswjs/interceptors/src/interceptors/XMLHttpRequest/utils/getBodyByteLength.ts @@ -0,0 +1,16 @@ +/** + * Return a total byte length of the given request/response body. + * If the `Content-Length` header is present, it will be used as the byte length. + */ +export async function getBodyByteLength( + input: Request | Response +): Promise { + const explicitContentLength = input.headers.get('content-length') + + if (explicitContentLength != null && explicitContentLength !== '') { + return Number(explicitContentLength) + } + + const buffer = await input.arrayBuffer() + return buffer.byteLength +} diff --git a/node_modules/@mswjs/interceptors/src/interceptors/XMLHttpRequest/utils/isDomParserSupportedType.ts b/node_modules/@mswjs/interceptors/src/interceptors/XMLHttpRequest/utils/isDomParserSupportedType.ts new file mode 100644 index 0000000000000000000000000000000000000000..3cf18b04002ed477d343e4a5a058a66766eebb3c --- /dev/null +++ b/node_modules/@mswjs/interceptors/src/interceptors/XMLHttpRequest/utils/isDomParserSupportedType.ts @@ -0,0 +1,14 @@ +export function isDomParserSupportedType( + type: string +): type is DOMParserSupportedType { + const supportedTypes: Array = [ + 'application/xhtml+xml', + 'application/xml', + 'image/svg+xml', + 'text/html', + 'text/xml', + ] + return supportedTypes.some((supportedType) => { + return type.startsWith(supportedType) + }) +} diff --git a/node_modules/@mswjs/interceptors/src/interceptors/fetch/index.ts b/node_modules/@mswjs/interceptors/src/interceptors/fetch/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..d134fc1611fe6501b415b49897761479fe0e4ff5 --- /dev/null +++ b/node_modules/@mswjs/interceptors/src/interceptors/fetch/index.ts @@ -0,0 +1,186 @@ +import { invariant } from 'outvariant' +import { DeferredPromise } from '@open-draft/deferred-promise' +import { HttpRequestEventMap, IS_PATCHED_MODULE } from '../../glossary' +import { Interceptor } from '../../Interceptor' +import { RequestController } from '../../RequestController' +import { emitAsync } from '../../utils/emitAsync' +import { handleRequest } from '../../utils/handleRequest' +import { canParseUrl } from '../../utils/canParseUrl' +import { createRequestId } from '../../createRequestId' +import { createNetworkError } from './utils/createNetworkError' +import { followFetchRedirect } from './utils/followRedirect' +import { decompressResponse } from './utils/decompression' +import { hasConfigurableGlobal } from '../../utils/hasConfigurableGlobal' +import { FetchResponse } from '../../utils/fetchUtils' + +export class FetchInterceptor extends Interceptor { + static symbol = Symbol('fetch') + + constructor() { + super(FetchInterceptor.symbol) + } + + protected checkEnvironment() { + return hasConfigurableGlobal('fetch') + } + + protected async setup() { + const pureFetch = globalThis.fetch + + invariant( + !(pureFetch as any)[IS_PATCHED_MODULE], + 'Failed to patch the "fetch" module: already patched.' + ) + + globalThis.fetch = async (input, init) => { + const requestId = createRequestId() + + /** + * @note Resolve potentially relative request URL + * against the present `location`. This is mainly + * for native `fetch` in JSDOM. + * @see https://github.com/mswjs/msw/issues/1625 + */ + const resolvedInput = + typeof input === 'string' && + typeof location !== 'undefined' && + !canParseUrl(input) + ? new URL(input, location.origin) + : input + + const request = new Request(resolvedInput, init) + const responsePromise = new DeferredPromise() + const controller = new RequestController(request) + + this.logger.info('[%s] %s', request.method, request.url) + this.logger.info('awaiting for the mocked response...') + + this.logger.info( + 'emitting the "request" event for %s listener(s)...', + this.emitter.listenerCount('request') + ) + + const isRequestHandled = await handleRequest({ + request, + requestId, + emitter: this.emitter, + controller, + onResponse: async (rawResponse) => { + this.logger.info('received mocked response!', { + rawResponse, + }) + + // Decompress the mocked response body, if applicable. + const decompressedStream = decompressResponse(rawResponse) + const response = + decompressedStream === null + ? rawResponse + : new FetchResponse(decompressedStream, rawResponse) + + FetchResponse.setUrl(request.url, response) + + /** + * Undici's handling of following redirect responses. + * Treat the "manual" redirect mode as a regular mocked response. + * This way, the client can manually follow the redirect it receives. + * @see https://github.com/nodejs/undici/blob/a6dac3149c505b58d2e6d068b97f4dc993da55f0/lib/web/fetch/index.js#L1173 + */ + if (FetchResponse.isRedirectResponse(response.status)) { + // Reject the request promise if its `redirect` is set to `error` + // and it receives a mocked redirect response. + if (request.redirect === 'error') { + responsePromise.reject(createNetworkError('unexpected redirect')) + return + } + + if (request.redirect === 'follow') { + followFetchRedirect(request, response).then( + (response) => { + responsePromise.resolve(response) + }, + (reason) => { + responsePromise.reject(reason) + } + ) + return + } + } + + if (this.emitter.listenerCount('response') > 0) { + this.logger.info('emitting the "response" event...') + + // Await the response listeners to finish before resolving + // the response promise. This ensures all your logic finishes + // before the interceptor resolves the pending response. + await emitAsync(this.emitter, 'response', { + // Clone the mocked response for the "response" event listener. + // This way, the listener can read the response and not lock its body + // for the actual fetch consumer. + response: response.clone(), + isMockedResponse: true, + request, + requestId, + }) + } + + responsePromise.resolve(response) + }, + onRequestError: (response) => { + this.logger.info('request has errored!', { response }) + responsePromise.reject(createNetworkError(response)) + }, + onError: (error) => { + this.logger.info('request has been aborted!', { error }) + responsePromise.reject(error) + }, + }) + + if (isRequestHandled) { + this.logger.info('request has been handled, returning mock promise...') + return responsePromise + } + + this.logger.info( + 'no mocked response received, performing request as-is...' + ) + + return pureFetch(request).then(async (response) => { + this.logger.info('original fetch performed', response) + + if (this.emitter.listenerCount('response') > 0) { + this.logger.info('emitting the "response" event...') + + const responseClone = response.clone() + + await emitAsync(this.emitter, 'response', { + response: responseClone, + isMockedResponse: false, + request, + requestId, + }) + } + + return response + }) + } + + Object.defineProperty(globalThis.fetch, IS_PATCHED_MODULE, { + enumerable: true, + configurable: true, + value: true, + }) + + this.subscriptions.push(() => { + Object.defineProperty(globalThis.fetch, IS_PATCHED_MODULE, { + value: undefined, + }) + + globalThis.fetch = pureFetch + + this.logger.info( + 'restored native "globalThis.fetch"!', + globalThis.fetch.name + ) + }) + } +} diff --git a/node_modules/@mswjs/interceptors/src/interceptors/fetch/utils/brotli-decompress.browser.ts b/node_modules/@mswjs/interceptors/src/interceptors/fetch/utils/brotli-decompress.browser.ts new file mode 100644 index 0000000000000000000000000000000000000000..d88ca784f93391995cff90456b7ed18fd78fd891 --- /dev/null +++ b/node_modules/@mswjs/interceptors/src/interceptors/fetch/utils/brotli-decompress.browser.ts @@ -0,0 +1,14 @@ +export class BrotliDecompressionStream extends TransformStream { + constructor() { + console.warn( + '[Interceptors]: Brotli decompression of response streams is not supported in the browser' + ) + + super({ + transform(chunk, controller) { + // Keep the stream as passthrough, it does nothing. + controller.enqueue(chunk) + }, + }) + } +} diff --git a/node_modules/@mswjs/interceptors/src/interceptors/fetch/utils/brotli-decompress.ts b/node_modules/@mswjs/interceptors/src/interceptors/fetch/utils/brotli-decompress.ts new file mode 100644 index 0000000000000000000000000000000000000000..dbfa622e59ce6a76e882595dcc5bef159028d0c9 --- /dev/null +++ b/node_modules/@mswjs/interceptors/src/interceptors/fetch/utils/brotli-decompress.ts @@ -0,0 +1,31 @@ +import zlib from 'node:zlib' + +export class BrotliDecompressionStream extends TransformStream { + constructor() { + const decompress = zlib.createBrotliDecompress({ + flush: zlib.constants.BROTLI_OPERATION_FLUSH, + finishFlush: zlib.constants.BROTLI_OPERATION_FLUSH, + }) + + super({ + async transform(chunk, controller) { + const buffer = Buffer.from(chunk) + + const decompressed = await new Promise((resolve, reject) => { + decompress.write(buffer, (error) => { + if (error) reject(error) + }) + + decompress.flush() + decompress.once('data', (data) => resolve(data)) + decompress.once('error', (error) => reject(error)) + decompress.once('end', () => controller.terminate()) + }).catch((error) => { + controller.error(error) + }) + + controller.enqueue(decompressed) + }, + }) + } +} diff --git a/node_modules/@mswjs/interceptors/src/interceptors/fetch/utils/createNetworkError.ts b/node_modules/@mswjs/interceptors/src/interceptors/fetch/utils/createNetworkError.ts new file mode 100644 index 0000000000000000000000000000000000000000..bf58f070803f4624ad27b7e0b392629cde49908a --- /dev/null +++ b/node_modules/@mswjs/interceptors/src/interceptors/fetch/utils/createNetworkError.ts @@ -0,0 +1,5 @@ +export function createNetworkError(cause?: unknown) { + return Object.assign(new TypeError('Failed to fetch'), { + cause, + }) +} diff --git a/node_modules/@mswjs/interceptors/src/interceptors/fetch/utils/decompression.ts b/node_modules/@mswjs/interceptors/src/interceptors/fetch/utils/decompression.ts new file mode 100644 index 0000000000000000000000000000000000000000..583d4a37edf9d372af8ab4fa07f33b46e506051c --- /dev/null +++ b/node_modules/@mswjs/interceptors/src/interceptors/fetch/utils/decompression.ts @@ -0,0 +1,85 @@ +// Import from an internal alias that resolves to different modules +// depending on the environment. This way, we can keep the fetch interceptor +// intact while using different strategies for Brotli decompression. +import { BrotliDecompressionStream } from 'internal:brotli-decompress' + +class PipelineStream extends TransformStream { + constructor( + transformStreams: Array, + ...strategies: Array + ) { + super({}, ...strategies) + + const readable = [super.readable as any, ...transformStreams].reduce( + (readable, transform) => readable.pipeThrough(transform) + ) + + Object.defineProperty(this, 'readable', { + get() { + return readable + }, + }) + } +} + +export function parseContentEncoding(contentEncoding: string): Array { + return contentEncoding + .toLowerCase() + .split(',') + .map((coding) => coding.trim()) +} + +function createDecompressionStream( + contentEncoding: string +): TransformStream | null { + if (contentEncoding === '') { + return null + } + + const codings = parseContentEncoding(contentEncoding) + + if (codings.length === 0) { + return null + } + + const transformers = codings.reduceRight>( + (transformers, coding) => { + if (coding === 'gzip' || coding === 'x-gzip') { + return transformers.concat(new DecompressionStream('gzip')) + } else if (coding === 'deflate') { + return transformers.concat(new DecompressionStream('deflate')) + } else if (coding === 'br') { + return transformers.concat(new BrotliDecompressionStream()) + } else { + transformers.length = 0 + } + + return transformers + }, + [] + ) + + return new PipelineStream(transformers) +} + +export function decompressResponse( + response: Response +): ReadableStream | null { + if (response.body === null) { + return null + } + + const decompressionStream = createDecompressionStream( + response.headers.get('content-encoding') || '' + ) + + if (!decompressionStream) { + return null + } + + // Use `pipeTo` and return the decompression stream's readable + // instead of `pipeThrough` because that will lock the original + // response stream, making it unusable as the input to Response. + response.body.pipeTo(decompressionStream.writable) + return decompressionStream.readable +} diff --git a/node_modules/@mswjs/interceptors/src/interceptors/fetch/utils/followRedirect.ts b/node_modules/@mswjs/interceptors/src/interceptors/fetch/utils/followRedirect.ts new file mode 100644 index 0000000000000000000000000000000000000000..bd76e63b70ca26aaf19c3431650b1d90d4e8cbea --- /dev/null +++ b/node_modules/@mswjs/interceptors/src/interceptors/fetch/utils/followRedirect.ts @@ -0,0 +1,108 @@ +import { createNetworkError } from './createNetworkError' + +const REQUEST_BODY_HEADERS = [ + 'content-encoding', + 'content-language', + 'content-location', + 'content-type', + 'content-length', +] + +const kRedirectCount = Symbol('kRedirectCount') + +/** + * @see https://github.com/nodejs/undici/blob/a6dac3149c505b58d2e6d068b97f4dc993da55f0/lib/web/fetch/index.js#L1210 + */ +export async function followFetchRedirect( + request: Request, + response: Response +): Promise { + if (response.status !== 303 && request.body != null) { + return Promise.reject(createNetworkError()) + } + + const requestUrl = new URL(request.url) + + let locationUrl: URL + try { + // If the location is a relative URL, use the request URL as the base URL. + locationUrl = new URL(response.headers.get('location')!, request.url) + } catch (error) { + return Promise.reject(createNetworkError(error)) + } + + if ( + !(locationUrl.protocol === 'http:' || locationUrl.protocol === 'https:') + ) { + return Promise.reject( + createNetworkError('URL scheme must be a HTTP(S) scheme') + ) + } + + if (Reflect.get(request, kRedirectCount) > 20) { + return Promise.reject(createNetworkError('redirect count exceeded')) + } + + Object.defineProperty(request, kRedirectCount, { + value: (Reflect.get(request, kRedirectCount) || 0) + 1, + }) + + if ( + request.mode === 'cors' && + (locationUrl.username || locationUrl.password) && + !sameOrigin(requestUrl, locationUrl) + ) { + return Promise.reject( + createNetworkError('cross origin not allowed for request mode "cors"') + ) + } + + const requestInit: RequestInit = {} + + if ( + ([301, 302].includes(response.status) && request.method === 'POST') || + (response.status === 303 && !['HEAD', 'GET'].includes(request.method)) + ) { + requestInit.method = 'GET' + requestInit.body = null + + REQUEST_BODY_HEADERS.forEach((headerName) => { + request.headers.delete(headerName) + }) + } + + if (!sameOrigin(requestUrl, locationUrl)) { + request.headers.delete('authorization') + request.headers.delete('proxy-authorization') + request.headers.delete('cookie') + request.headers.delete('host') + } + + /** + * @note Undici "safely" extracts the request body. + * I suspect we cannot dispatch this request again + * since its body has been read and the stream is locked. + */ + + requestInit.headers = request.headers + return fetch(new Request(locationUrl, requestInit)) +} + +/** + * @see https://github.com/nodejs/undici/blob/a6dac3149c505b58d2e6d068b97f4dc993da55f0/lib/web/fetch/util.js#L761 + */ +function sameOrigin(left: URL, right: URL): boolean { + if (left.origin === right.origin && left.origin === 'null') { + return true + } + + if ( + left.protocol === right.protocol && + left.hostname === right.hostname && + left.port === right.port + ) { + return true + } + + return false +} diff --git a/node_modules/@mswjs/interceptors/src/presets/browser.ts b/node_modules/@mswjs/interceptors/src/presets/browser.ts new file mode 100644 index 0000000000000000000000000000000000000000..c609adc5e7dca8993d68109684d12455f468a456 --- /dev/null +++ b/node_modules/@mswjs/interceptors/src/presets/browser.ts @@ -0,0 +1,11 @@ +import { FetchInterceptor } from '../interceptors/fetch' +import { XMLHttpRequestInterceptor } from '../interceptors/XMLHttpRequest' + +/** + * The default preset provisions the interception of requests + * regardless of their type (fetch/XMLHttpRequest). + */ +export default [ + new FetchInterceptor(), + new XMLHttpRequestInterceptor(), +] as const diff --git a/node_modules/@mswjs/interceptors/src/presets/node.ts b/node_modules/@mswjs/interceptors/src/presets/node.ts new file mode 100644 index 0000000000000000000000000000000000000000..63fbe0f459e67bdc693121f8cc55903bd18100df --- /dev/null +++ b/node_modules/@mswjs/interceptors/src/presets/node.ts @@ -0,0 +1,13 @@ +import { ClientRequestInterceptor } from '../interceptors/ClientRequest' +import { XMLHttpRequestInterceptor } from '../interceptors/XMLHttpRequest' +import { FetchInterceptor } from '../interceptors/fetch' + +/** + * The default preset provisions the interception of requests + * regardless of their type (http/https/XMLHttpRequest). + */ +export default [ + new ClientRequestInterceptor(), + new XMLHttpRequestInterceptor(), + new FetchInterceptor(), +] as const diff --git a/node_modules/@mswjs/interceptors/src/utils/RequestController.ts b/node_modules/@mswjs/interceptors/src/utils/RequestController.ts new file mode 100644 index 0000000000000000000000000000000000000000..d93e70b3d5e43604f65d3ca8ecb22ef6f396e094 --- /dev/null +++ b/node_modules/@mswjs/interceptors/src/utils/RequestController.ts @@ -0,0 +1,21 @@ +import { invariant } from 'outvariant' +import { DeferredPromise } from '@open-draft/deferred-promise' + +export class RequestController { + public responsePromise: DeferredPromise + + constructor(protected request: Request) { + this.responsePromise = new DeferredPromise() + } + + public respondWith(response?: Response): void { + invariant( + this.responsePromise.state === 'pending', + 'Failed to respond to "%s %s" request: the "request" event has already been responded to.', + this.request.method, + this.request.url + ) + + this.responsePromise.resolve(response) + } +} diff --git a/node_modules/@mswjs/interceptors/src/utils/bufferUtils.test.ts b/node_modules/@mswjs/interceptors/src/utils/bufferUtils.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..7c554556164da88a34dfced42ee641e1a8ed590c --- /dev/null +++ b/node_modules/@mswjs/interceptors/src/utils/bufferUtils.test.ts @@ -0,0 +1,21 @@ +import { it, expect } from 'vitest' +import { decodeBuffer, encodeBuffer } from './bufferUtils' + +it('encodes utf-8 string', () => { + const encoded = encodeBuffer('😁') + expect(new Uint8Array(encoded)).toEqual(new Uint8Array([240, 159, 152, 129])) +}) + +it('decodes utf-8 string', () => { + const array = new Uint8Array([240, 159, 152, 129]) + const decoded = decodeBuffer(array.buffer) + expect(decoded).toEqual('😁') +}) + +it('decodes string with custom encoding', () => { + const array = new Uint8Array([ + 207, 240, 232, 226, 229, 242, 44, 32, 236, 232, 240, 33, + ]) + const decoded = decodeBuffer(array.buffer, 'windows-1251') + expect(decoded).toEqual('Привет, мир!') +}) diff --git a/node_modules/@mswjs/interceptors/src/utils/bufferUtils.ts b/node_modules/@mswjs/interceptors/src/utils/bufferUtils.ts new file mode 100644 index 0000000000000000000000000000000000000000..b4b1c3784d2859669e6e209234d974bb0a2d3784 --- /dev/null +++ b/node_modules/@mswjs/interceptors/src/utils/bufferUtils.ts @@ -0,0 +1,22 @@ +const encoder = new TextEncoder() + +export function encodeBuffer(text: string): Uint8Array { + return encoder.encode(text) +} + +export function decodeBuffer(buffer: ArrayBuffer, encoding?: string): string { + const decoder = new TextDecoder(encoding) + return decoder.decode(buffer) +} + +/** + * Create an `ArrayBuffer` from the given `Uint8Array`. + * Takes the byte offset into account to produce the right buffer + * in the case when the buffer is bigger than the data view. + */ +export function toArrayBuffer(array: Uint8Array): ArrayBuffer { + return array.buffer.slice( + array.byteOffset, + array.byteOffset + array.byteLength + ) +} diff --git a/node_modules/@mswjs/interceptors/src/utils/canParseUrl.ts b/node_modules/@mswjs/interceptors/src/utils/canParseUrl.ts new file mode 100644 index 0000000000000000000000000000000000000000..7f814cd5269c9779271770971bba049e7304dd04 --- /dev/null +++ b/node_modules/@mswjs/interceptors/src/utils/canParseUrl.ts @@ -0,0 +1,13 @@ +/** + * Returns a boolean indicating whether the given URL string + * can be parsed into a `URL` instance. + * A substitute for `URL.canParse()` for Node.js 18. + */ +export function canParseUrl(url: string): boolean { + try { + new URL(url) + return true + } catch (_error) { + return false + } +} diff --git a/node_modules/@mswjs/interceptors/src/utils/cloneObject.test.ts b/node_modules/@mswjs/interceptors/src/utils/cloneObject.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..85a1dbbb3f32f70005390ab883a93f5553136a5c --- /dev/null +++ b/node_modules/@mswjs/interceptors/src/utils/cloneObject.test.ts @@ -0,0 +1,94 @@ +import { it, expect } from 'vitest' +import { cloneObject } from './cloneObject' + +it('clones a shallow object', () => { + const original = { a: 1, b: 2, c: [1, 2, 3] } + const clone = cloneObject(original) + + expect(clone).toEqual(original) + + clone.a = 5 + clone.b = 6 + clone.c = [5, 6, 7] + + expect(clone).toHaveProperty('a', 5) + expect(clone).toHaveProperty('b', 6) + expect(clone).toHaveProperty('c', [5, 6, 7]) + expect(original).toHaveProperty('a', 1) + expect(original).toHaveProperty('b', 2) + expect(original).toHaveProperty('c', [1, 2, 3]) +}) + +it('clones a nested object', () => { + const original = { a: { b: 1 }, c: { d: { e: 2 } } } + const clone = cloneObject(original) + + expect(clone).toEqual(original) + + clone.a.b = 10 + clone.c.d.e = 20 + + expect(clone).toHaveProperty(['a', 'b'], 10) + expect(clone).toHaveProperty(['c', 'd', 'e'], 20) + expect(original).toHaveProperty(['a', 'b'], 1) + expect(original).toHaveProperty(['c', 'd', 'e'], 2) +}) + +it('clones a class instance', () => { + class Car { + public manufacturer: string + constructor() { + this.manufacturer = 'Audi' + } + getManufacturer() { + return this.manufacturer + } + } + + const car = new Car() + const clone = cloneObject(car) + + expect(clone).toHaveProperty('manufacturer', 'Audi') + expect(clone).toHaveProperty('getManufacturer') + expect(clone.getManufacturer).toBeInstanceOf(Function) + expect(clone.getManufacturer()).toEqual('Audi') +}) + +it('ignores nested class instances', () => { + class Car { + name: string + constructor(name: string) { + this.name = name + } + getName() { + return this.name + } + } + const original = { + a: 1, + car: new Car('Audi'), + } + const clone = cloneObject(original) + + expect(clone).toEqual(original) + expect(clone.car).toBeInstanceOf(Car) + expect(clone.car.getName()).toEqual('Audi') + + clone.car = new Car('BMW') + + expect(clone.car).toBeInstanceOf(Car) + expect(clone.car.getName()).toEqual('BMW') + expect(original.car).toBeInstanceOf(Car) + expect(original.car.getName()).toEqual('Audi') +}) + +it('clones an object with null prototype', () => { + const original = { + key: Object.create(null), + } + const clone = cloneObject(original) + + expect(clone).toEqual({ + key: {}, + }) +}) diff --git a/node_modules/@mswjs/interceptors/src/utils/cloneObject.ts b/node_modules/@mswjs/interceptors/src/utils/cloneObject.ts new file mode 100644 index 0000000000000000000000000000000000000000..521f2ea0032dfae61a1254ce734254303dc1ba89 --- /dev/null +++ b/node_modules/@mswjs/interceptors/src/utils/cloneObject.ts @@ -0,0 +1,36 @@ +import { Logger } from '@open-draft/logger' + +const logger = new Logger('cloneObject') + +function isPlainObject(obj?: Record): boolean { + logger.info('is plain object?', obj) + + if (obj == null || !obj.constructor?.name) { + logger.info('given object is undefined, not a plain object...') + return false + } + + logger.info('checking the object constructor:', obj.constructor.name) + return obj.constructor.name === 'Object' +} + +export function cloneObject>( + obj: ObjectType +): ObjectType { + logger.info('cloning object:', obj) + + const enumerableProperties = Object.entries(obj).reduce>( + (acc, [key, value]) => { + logger.info('analyzing key-value pair:', key, value) + + // Recursively clone only plain objects, omitting class instances. + acc[key] = isPlainObject(value) ? cloneObject(value) : value + return acc + }, + {} + ) + + return isPlainObject(obj) + ? enumerableProperties + : Object.assign(Object.getPrototypeOf(obj), enumerableProperties) +} diff --git a/node_modules/@mswjs/interceptors/src/utils/createProxy.test.ts b/node_modules/@mswjs/interceptors/src/utils/createProxy.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..0688aacc3bb64a15d45a61348a1f20a21e12383d --- /dev/null +++ b/node_modules/@mswjs/interceptors/src/utils/createProxy.test.ts @@ -0,0 +1,162 @@ +import { vi, it, expect } from 'vitest' +import { createProxy } from './createProxy' + +it('does not interfere with default constructors', () => { + const ProxyClass = createProxy( + class { + constructor(public name: string) {} + }, + {} + ) + + const instance = new ProxyClass('John') + expect(instance.name).toBe('John') +}) + +it('does not interfere with default getters', () => { + const proxy = createProxy({ foo: 'initial' }, {}) + expect(proxy.foo).toBe('initial') +}) + +it('does not interfere with default setters', () => { + const proxy = createProxy({ foo: 'initial' }, {}) + proxy.foo = 'next' + + expect(proxy.foo).toBe('next') +}) + +it('does not interfere with default methods', () => { + const proxy = createProxy({ getValue: () => 'initial' }, {}) + expect(proxy.getValue()).toBe('initial') +}) + +it('does not interfere with existing descriptors', () => { + const target = {} as { foo: string; bar: number } + let internalBar = 0 + + Object.defineProperties(target, { + foo: { + get: () => 'initial', + }, + bar: { + set: (value) => { + internalBar = value + 10 + }, + }, + }) + + const proxy = createProxy(target, { + getProperty(data, next) { + return next() + }, + }) + expect(proxy.foo).toBe('initial') + + proxy.bar = 5 + expect(proxy.bar).toBeUndefined() + expect(internalBar).toBe(15) +}) + +it('infer prototype descriptors', () => { + class Child { + ok: boolean + + set status(nextStatus: number) { + this.ok = nextStatus >= 200 && nextStatus < 300 + } + } + + Object.defineProperties(Child.prototype, { + status: { enumerable: true }, + }) + + const scope = {} as { child: typeof Child } + + Object.defineProperty(scope, 'child', { + enumerable: true, + value: Child, + }) + + const ProxyClass = createProxy(scope.child, {}) + const instance = new ProxyClass() + + instance.status = 201 + expect(instance.ok).toBe(true) +}) + +it('spies on the constructor', () => { + const OriginalClass = class { + constructor(public name: string, public age: number) {} + } + + const constructorCall = vi.fn< + [ConstructorParameters, Function], + typeof OriginalClass + >((args, next) => next()) + + const ProxyClass = createProxy(OriginalClass, { + constructorCall, + }) + + new ProxyClass('John', 32) + + expect(constructorCall).toHaveBeenCalledTimes(1) + expect(constructorCall).toHaveBeenCalledWith( + ['John', 32], + expect.any(Function) + ) +}) + +it('spies on property getters', () => { + const getProperty = vi.fn((args, next) => next()) + const proxy = createProxy({ foo: 'initial' }, { getProperty }) + + proxy.foo + + expect(getProperty).toHaveBeenCalledTimes(1) + expect(getProperty).toHaveBeenCalledWith(['foo', proxy], expect.any(Function)) +}) + +it('spies on property setters', () => { + const setProperty = vi.fn((args, next) => next()) + const proxy = createProxy({ foo: 'initial' }, { setProperty }) + + proxy.foo = 'next' + + expect(setProperty).toHaveBeenCalledTimes(1) + expect(setProperty).toHaveBeenCalledWith( + ['foo', 'next'], + expect.any(Function) + ) +}) + +it('spies on method calls', () => { + const methodCall = vi.fn((args, next) => next()) + const proxy = createProxy( + { + greet: (name: string) => `hello ${name}`, + }, + { methodCall } + ) + + proxy.greet('Clair') + + expect(methodCall).toHaveBeenCalledTimes(1) + expect(methodCall).toHaveBeenCalledWith( + ['greet', ['Clair']], + expect.any(Function) + ) +}) + +it('proxies properties on the prototype level', () => { + const method = vi.fn() + const prototype = { method } + + const proxy = createProxy(Object.create(prototype), {}) + const proxyMethod = vi.fn() + proxy.method = proxyMethod + + prototype.method() + expect(method).toHaveBeenCalledTimes(0) + expect(proxyMethod).toHaveBeenCalledTimes(1) +}) diff --git a/node_modules/@mswjs/interceptors/src/utils/createProxy.ts b/node_modules/@mswjs/interceptors/src/utils/createProxy.ts new file mode 100644 index 0000000000000000000000000000000000000000..054e752437f1059fa43804fb354beaad68393977 --- /dev/null +++ b/node_modules/@mswjs/interceptors/src/utils/createProxy.ts @@ -0,0 +1,104 @@ +import { findPropertySource } from './findPropertySource' + +export interface ProxyOptions> { + constructorCall?(args: Array, next: NextFunction): Target + + methodCall?( + this: Target, + data: [methodName: F, args: Array], + next: NextFunction + ): void + + setProperty?( + data: [propertyName: string | symbol, nextValue: unknown], + next: NextFunction + ): boolean + + getProperty?( + data: [propertyName: string | symbol, receiver: Target], + next: NextFunction + ): void +} + +export type NextFunction = () => ReturnType + +export function createProxy( + target: Target, + options: ProxyOptions +): Target { + const proxy = new Proxy(target, optionsToProxyHandler(options)) + + return proxy +} + +function optionsToProxyHandler>( + options: ProxyOptions +): ProxyHandler { + const { constructorCall, methodCall, getProperty, setProperty } = options + const handler: ProxyHandler = {} + + if (typeof constructorCall !== 'undefined') { + handler.construct = function (target, args, newTarget) { + const next = Reflect.construct.bind(null, target as any, args, newTarget) + return constructorCall.call(newTarget, args, next) + } + } + + handler.set = function (target, propertyName, nextValue) { + const next = () => { + const propertySource = findPropertySource(target, propertyName) || target + const ownDescriptors = Reflect.getOwnPropertyDescriptor( + propertySource, + propertyName + ) + + // Respect any custom setters present for this property. + if (typeof ownDescriptors?.set !== 'undefined') { + ownDescriptors.set.apply(target, [nextValue]) + return true + } + + // Otherwise, set the property on the source. + return Reflect.defineProperty(propertySource, propertyName, { + writable: true, + enumerable: true, + configurable: true, + value: nextValue, + }) + } + + if (typeof setProperty !== 'undefined') { + return setProperty.call(target, [propertyName, nextValue], next) + } + + return next() + } + + handler.get = function (target, propertyName, receiver) { + /** + * @note Using `Reflect.get()` here causes "TypeError: Illegal invocation". + */ + const next = () => target[propertyName as any] + + const value = + typeof getProperty !== 'undefined' + ? getProperty.call(target, [propertyName, receiver], next) + : next() + + if (typeof value === 'function') { + return (...args: Array) => { + const next = value.bind(target, ...args) + + if (typeof methodCall !== 'undefined') { + return methodCall.call(target, [propertyName as any, args], next) + } + + return next() + } + } + + return value + } + + return handler +} diff --git a/node_modules/@mswjs/interceptors/src/utils/emitAsync.ts b/node_modules/@mswjs/interceptors/src/utils/emitAsync.ts new file mode 100644 index 0000000000000000000000000000000000000000..09b43fcbee12f0a63580d13b6e4c2353be5656e8 --- /dev/null +++ b/node_modules/@mswjs/interceptors/src/utils/emitAsync.ts @@ -0,0 +1,25 @@ +import { Emitter, EventMap } from 'strict-event-emitter' + +/** + * Emits an event on the given emitter but executes + * the listeners sequentially. This accounts for asynchronous + * listeners (e.g. those having "sleep" and handling the request). + */ +export async function emitAsync< + Events extends EventMap, + EventName extends keyof Events +>( + emitter: Emitter, + eventName: EventName, + ...data: Events[EventName] +): Promise { + const listners = emitter.listeners(eventName) + + if (listners.length === 0) { + return + } + + for (const listener of listners) { + await listener.apply(emitter, data) + } +} diff --git a/node_modules/@mswjs/interceptors/src/utils/fetchUtils.ts b/node_modules/@mswjs/interceptors/src/utils/fetchUtils.ts new file mode 100644 index 0000000000000000000000000000000000000000..37f759294194e3cc6460de71b2677d74f1dca0ed --- /dev/null +++ b/node_modules/@mswjs/interceptors/src/utils/fetchUtils.ts @@ -0,0 +1,93 @@ +export interface FetchResponseInit extends ResponseInit { + url?: string +} + +export class FetchResponse extends Response { + /** + * Response status codes for responses that cannot have body. + * @see https://fetch.spec.whatwg.org/#statuses + */ + static readonly STATUS_CODES_WITHOUT_BODY = [101, 103, 204, 205, 304] + + static readonly STATUS_CODES_WITH_REDIRECT = [301, 302, 303, 307, 308] + + static isConfigurableStatusCode(status: number): boolean { + return status >= 200 && status <= 599 + } + + static isRedirectResponse(status: number): boolean { + return FetchResponse.STATUS_CODES_WITH_REDIRECT.includes(status) + } + + /** + * Returns a boolean indicating whether the given response status + * code represents a response that can have a body. + */ + static isResponseWithBody(status: number): boolean { + return !FetchResponse.STATUS_CODES_WITHOUT_BODY.includes(status) + } + + static setUrl(url: string | undefined, response: Response): void { + if (!url) { + return + } + + if (response.url != '') { + return + } + + Object.defineProperty(response, 'url', { + value: url, + enumerable: true, + configurable: true, + writable: false, + }) + } + + /** + * Parses the given raw HTTP headers into a Fetch API `Headers` instance. + */ + static parseRawHeaders(rawHeaders: Array): Headers { + const headers = new Headers() + for (let line = 0; line < rawHeaders.length; line += 2) { + headers.append(rawHeaders[line], rawHeaders[line + 1]) + } + return headers + } + + constructor(body?: BodyInit | null, init: FetchResponseInit = {}) { + const status = init.status ?? 200 + const safeStatus = FetchResponse.isConfigurableStatusCode(status) + ? status + : 200 + const finalBody = FetchResponse.isResponseWithBody(status) ? body : null + + super(finalBody, { + ...init, + status: safeStatus, + }) + + if (status !== safeStatus) { + /** + * @note Undici keeps an internal "Symbol(state)" that holds + * the actual value of response status. Update that in Node.js. + */ + const stateSymbol = Object.getOwnPropertySymbols(this).find( + (symbol) => symbol.description === 'state' + ) + if (stateSymbol) { + const state = Reflect.get(this, stateSymbol) as object + Reflect.set(state, 'status', status) + } else { + Object.defineProperty(this, 'status', { + value: status, + enumerable: true, + configurable: true, + writable: false, + }) + } + } + + FetchResponse.setUrl(init.url, this) + } +} diff --git a/node_modules/@mswjs/interceptors/src/utils/findPropertySource.test.ts b/node_modules/@mswjs/interceptors/src/utils/findPropertySource.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..cce02ca9eb099feda1cdde43b0f29e82f715323c --- /dev/null +++ b/node_modules/@mswjs/interceptors/src/utils/findPropertySource.test.ts @@ -0,0 +1,27 @@ +import { it, expect } from 'vitest' +import { findPropertySource } from './findPropertySource' + +it('returns the source for objects without prototypes', () => { + const obj = Object.create(null) + obj.test = undefined + const source = findPropertySource(obj, 'test') + expect(source).toBe(obj) +}) + +it('returns the source for objects with prototypes', () => { + const prototype = Object.create(null) + prototype.test = undefined + + const obj = Object.create(prototype) + + const source = findPropertySource(obj, 'test') + expect(source).toBe(prototype) +}) + +it('returns null if the prototype chain does not contain the property', () => { + const prototype = Object.create(null) + const obj = Object.create(prototype) + + const source = findPropertySource(obj, 'test') + expect(source).toBeNull() +}) diff --git a/node_modules/@mswjs/interceptors/src/utils/findPropertySource.ts b/node_modules/@mswjs/interceptors/src/utils/findPropertySource.ts new file mode 100644 index 0000000000000000000000000000000000000000..26ca44af82e00e5feb046e5ee8dab2339d5fc35d --- /dev/null +++ b/node_modules/@mswjs/interceptors/src/utils/findPropertySource.ts @@ -0,0 +1,20 @@ +/** + * Returns the source object of the given property on the target object + * (the target itself, any parent in its prototype, or null). + */ +export function findPropertySource( + target: object, + propertyName: string | symbol +): object | null { + if (!(propertyName in target)) { + return null + } + + const hasProperty = Object.prototype.hasOwnProperty.call(target, propertyName) + if (hasProperty) { + return target + } + + const prototype = Reflect.getPrototypeOf(target) + return prototype ? findPropertySource(prototype, propertyName) : null +} diff --git a/node_modules/@mswjs/interceptors/src/utils/getCleanUrl.test.ts b/node_modules/@mswjs/interceptors/src/utils/getCleanUrl.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..9f70ca81d5e08954b9e7c6cf3499a9862170fb67 --- /dev/null +++ b/node_modules/@mswjs/interceptors/src/utils/getCleanUrl.test.ts @@ -0,0 +1,32 @@ +import { describe, it, expect } from 'vitest' +import { getCleanUrl } from './getCleanUrl' + +describe('getCleanUrl', () => { + describe('given a URL without query parameters', () => { + it('should return url href as-is', () => { + const url = new URL('https://github.com') + expect(getCleanUrl(url)).toEqual('https://github.com/') + }) + }) + + describe('given a URL with query parameters', () => { + it('should return url without parameters', () => { + const url = new URL('https://github.com/mswjs/?userId=abc-123') + expect(getCleanUrl(url)).toEqual('https://github.com/mswjs/') + }) + }) + + describe('given a URL with a hash', () => { + it('should return a url without hash', () => { + const url = new URL('https://github.com/mswjs/#hello-world') + expect(getCleanUrl(url)).toEqual('https://github.com/mswjs/') + }) + }) + + describe('given an absolute URL ', () => { + it('should return a clean relative URL', () => { + const url = new URL('/login?query=value', 'https://github.com') + expect(getCleanUrl(url, false)).toEqual('/login') + }) + }) +}) diff --git a/node_modules/@mswjs/interceptors/src/utils/getCleanUrl.ts b/node_modules/@mswjs/interceptors/src/utils/getCleanUrl.ts new file mode 100644 index 0000000000000000000000000000000000000000..14165674a3dc626a1445e7d117edc639b05e839a --- /dev/null +++ b/node_modules/@mswjs/interceptors/src/utils/getCleanUrl.ts @@ -0,0 +1,6 @@ +/** + * Removes query parameters and hashes from a given URL. + */ +export function getCleanUrl(url: URL, isAbsolute: boolean = true): string { + return [isAbsolute && url.origin, url.pathname].filter(Boolean).join('') +} diff --git a/node_modules/@mswjs/interceptors/src/utils/getUrlByRequestOptions.test.ts b/node_modules/@mswjs/interceptors/src/utils/getUrlByRequestOptions.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..cc9423609d32be0399fb0ace18f5891f461c1f67 --- /dev/null +++ b/node_modules/@mswjs/interceptors/src/utils/getUrlByRequestOptions.test.ts @@ -0,0 +1,163 @@ +import { it, expect } from 'vitest' +import { Agent as HttpAgent } from 'http' +import { RequestOptions, Agent as HttpsAgent } from 'https' +import { getUrlByRequestOptions } from './getUrlByRequestOptions' + +it('returns a URL based on the basic RequestOptions', () => { + expect( + getUrlByRequestOptions({ + protocol: 'https:', + host: '127.0.0.1', + path: '/resource', + }).href + ).toBe('https://127.0.0.1/resource') +}) + +it('inherits protocol and port from http.Agent, if set', () => { + expect( + getUrlByRequestOptions({ + host: '127.0.0.1', + path: '/', + agent: new HttpAgent(), + }).href + ).toBe('http://127.0.0.1/') +}) + +it('inherits protocol and port from https.Agent, if set', () => { + expect( + getUrlByRequestOptions({ + host: '127.0.0.1', + path: '/', + agent: new HttpsAgent({ + port: 3080, + }), + }).href + ).toBe('https://127.0.0.1:3080/') +}) + +it('resolves protocol to "http" given no explicit protocol and no certificate', () => { + expect( + getUrlByRequestOptions({ + host: '127.0.0.1', + path: '/', + }).href + ).toBe('http://127.0.0.1/') +}) + +it('resolves protocol to "https" given no explicit protocol, but certificate', () => { + expect( + getUrlByRequestOptions({ + host: '127.0.0.1', + path: '/secure', + cert: '', + }).href + ).toBe('https://127.0.0.1/secure') +}) + +it('resolves protocol to "https" given no explicit protocol, but port is 443', () => { + expect( + getUrlByRequestOptions({ + host: '127.0.0.1', + port: 443, + path: '/resource', + }).href + ).toBe('https://127.0.0.1/resource') +}) + +it('resolves protocol to "https" given no explicit protocol, but agent port is 443', () => { + expect( + getUrlByRequestOptions({ + host: '127.0.0.1', + agent: new HttpsAgent({ + port: 443, + }), + path: '/resource', + }).href + ).toBe('https://127.0.0.1/resource') +}) + +it('respects explicitly provided port', () => { + expect( + getUrlByRequestOptions({ + protocol: 'http:', + host: '127.0.0.1', + port: 4002, + path: '/', + }).href + ).toBe('http://127.0.0.1:4002/') +}) + +it('inherits "username" and "password"', () => { + const url = getUrlByRequestOptions({ + protocol: 'https:', + host: '127.0.0.1', + path: '/user', + auth: 'admin:abc-123', + }) + + expect(url).toBeInstanceOf(URL) + expect(url).toHaveProperty('username', 'admin') + expect(url).toHaveProperty('password', 'abc-123') + expect(url).toHaveProperty('href', 'https://admin:abc-123@127.0.0.1/user') +}) + +it('resolves hostname to localhost if none provided', () => { + expect(getUrlByRequestOptions({}).hostname).toBe('localhost') +}) + +it('resolves host to localhost if none provided', () => { + expect(getUrlByRequestOptions({}).host).toBe('localhost') +}) + +it('supports "hostname" and "port"', () => { + const options: RequestOptions = { + protocol: 'https:', + hostname: '127.0.0.1', + port: 1234, + path: '/resource', + } + + expect(getUrlByRequestOptions(options).href).toBe( + 'https://127.0.0.1:1234/resource' + ) +}) + +it('use "hostname" if both "hostname" and "host" are specified', () => { + const options: RequestOptions = { + protocol: 'https:', + host: 'host', + hostname: 'hostname', + path: '/resource', + } + + expect(getUrlByRequestOptions(options).href).toBe( + 'https://hostname/resource' + ) +}) + +it('parses "host" in IPv6', () => { + expect( + getUrlByRequestOptions({ + host: '::1', + path: '/resource', + }).href + ).toBe('http://[::1]/resource') + + expect( + getUrlByRequestOptions({ + host: '[::1]', + path: '/resource', + }).href + ).toBe('http://[::1]/resource') + +}) + +it('parses "host" and "port" in IPv6', () => { + expect( + getUrlByRequestOptions({ + host: '::1', + port: 3001, + path: '/resource', + }).href + ).toBe('http://[::1]:3001/resource') +}) diff --git a/node_modules/@mswjs/interceptors/src/utils/getUrlByRequestOptions.ts b/node_modules/@mswjs/interceptors/src/utils/getUrlByRequestOptions.ts new file mode 100644 index 0000000000000000000000000000000000000000..0b8a5ef76010de2a957bbdc0b54b783b5cd9b836 --- /dev/null +++ b/node_modules/@mswjs/interceptors/src/utils/getUrlByRequestOptions.ts @@ -0,0 +1,152 @@ +import { Agent } from 'http' +import { RequestOptions, Agent as HttpsAgent } from 'https' +import { Logger } from '@open-draft/logger' + +const logger = new Logger('utils getUrlByRequestOptions') + +// Request instance constructed by the "request" library +// has a "self" property that has a "uri" field. This is +// reproducible by performing a "XMLHttpRequest" request in JSDOM. +export interface RequestSelf { + uri?: URL +} + +export type ResolvedRequestOptions = RequestOptions & RequestSelf + +export const DEFAULT_PATH = '/' +const DEFAULT_PROTOCOL = 'http:' +const DEFAULT_HOSTNAME = 'localhost' +const SSL_PORT = 443 + +function getAgent( + options: ResolvedRequestOptions +): Agent | HttpsAgent | undefined { + return options.agent instanceof Agent ? options.agent : undefined +} + +function getProtocolByRequestOptions(options: ResolvedRequestOptions): string { + if (options.protocol) { + return options.protocol + } + + const agent = getAgent(options) + const agentProtocol = (agent as RequestOptions)?.protocol + + if (agentProtocol) { + return agentProtocol + } + + const port = getPortByRequestOptions(options) + const isSecureRequest = options.cert || port === SSL_PORT + + return isSecureRequest ? 'https:' : options.uri?.protocol || DEFAULT_PROTOCOL +} + +function getPortByRequestOptions( + options: ResolvedRequestOptions +): number | undefined { + // Use the explicitly provided port. + if (options.port) { + return Number(options.port) + } + + // Otherwise, try to resolve port from the agent. + const agent = getAgent(options) + + if ((agent as HttpsAgent)?.options.port) { + return Number((agent as HttpsAgent).options.port) + } + + if ((agent as RequestOptions)?.defaultPort) { + return Number((agent as RequestOptions).defaultPort) + } + + // Lastly, return undefined indicating that the port + // must inferred from the protocol. Do not infer it here. + return undefined +} + +interface RequestAuth { + username: string + password: string +} + +function getAuthByRequestOptions( + options: ResolvedRequestOptions +): RequestAuth | undefined { + if (options.auth) { + const [username, password] = options.auth.split(':') + return { username, password } + } +} + +/** + * Returns true if host looks like an IPv6 address without surrounding brackets + * It assumes any host containing `:` is definitely not IPv4 and probably IPv6, + * but note that this could include invalid IPv6 addresses as well. + */ +function isRawIPv6Address(host: string): boolean { + return host.includes(':') && !host.startsWith('[') && !host.endsWith(']') +} + +function getHostname(options: ResolvedRequestOptions): string | undefined { + let host = options.hostname || options.host + + if (host) { + if (isRawIPv6Address(host)) { + host = `[${host}]` + } + + // Check the presence of the port, and if it's present, + // remove it from the host, returning a hostname. + return new URL(`http://${host}`).hostname + } + + return DEFAULT_HOSTNAME +} + +/** + * Creates a `URL` instance from a given `RequestOptions` object. + */ +export function getUrlByRequestOptions(options: ResolvedRequestOptions): URL { + logger.info('request options', options) + + if (options.uri) { + logger.info( + 'constructing url from explicitly provided "options.uri": %s', + options.uri + ) + return new URL(options.uri.href) + } + + logger.info('figuring out url from request options...') + + const protocol = getProtocolByRequestOptions(options) + logger.info('protocol', protocol) + + const port = getPortByRequestOptions(options) + logger.info('port', port) + + const hostname = getHostname(options) + logger.info('hostname', hostname) + + const path = options.path || DEFAULT_PATH + logger.info('path', path) + + const credentials = getAuthByRequestOptions(options) + logger.info('credentials', credentials) + + const authString = credentials + ? `${credentials.username}:${credentials.password}@` + : '' + logger.info('auth string:', authString) + + const portString = typeof port !== 'undefined' ? `:${port}` : '' + const url = new URL(`${protocol}//${hostname}${portString}${path}`) + url.username = credentials?.username || '' + url.password = credentials?.password || '' + + logger.info('created url:', url) + + return url +} diff --git a/node_modules/@mswjs/interceptors/src/utils/getValueBySymbol.test.ts b/node_modules/@mswjs/interceptors/src/utils/getValueBySymbol.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..9e2b21c8ceda848d594162356257be11555811d4 --- /dev/null +++ b/node_modules/@mswjs/interceptors/src/utils/getValueBySymbol.test.ts @@ -0,0 +1,14 @@ +import { it, expect } from 'vitest' +import { getValueBySymbol } from './getValueBySymbol' + +it('returns undefined given a non-existing symbol', () => { + expect(getValueBySymbol('non-existing', {})).toBeUndefined() +}) + +it('returns value behind the given symbol', () => { + const symbol = Symbol('kInternal') + + expect(getValueBySymbol('kInternal', { [symbol]: null })).toBe(null) + expect(getValueBySymbol('kInternal', { [symbol]: true })).toBe(true) + expect(getValueBySymbol('kInternal', { [symbol]: 'value' })).toBe('value') +}) diff --git a/node_modules/@mswjs/interceptors/src/utils/getValueBySymbol.ts b/node_modules/@mswjs/interceptors/src/utils/getValueBySymbol.ts new file mode 100644 index 0000000000000000000000000000000000000000..2c2e9541f44094b2e07b35154aeae9a2cc1a813c --- /dev/null +++ b/node_modules/@mswjs/interceptors/src/utils/getValueBySymbol.ts @@ -0,0 +1,19 @@ +/** + * Returns the value behind the symbol with the given name. + */ +export function getValueBySymbol( + symbolName: string, + source: object +): T | undefined { + const ownSymbols = Object.getOwnPropertySymbols(source) + + const symbol = ownSymbols.find((symbol) => { + return symbol.description === symbolName + }) + + if (symbol) { + return Reflect.get(source, symbol) + } + + return +} diff --git a/node_modules/@mswjs/interceptors/src/utils/handleRequest.ts b/node_modules/@mswjs/interceptors/src/utils/handleRequest.ts new file mode 100644 index 0000000000000000000000000000000000000000..546f62ab6ceb4f69a65ccbc14ca1d033a1aad605 --- /dev/null +++ b/node_modules/@mswjs/interceptors/src/utils/handleRequest.ts @@ -0,0 +1,217 @@ +import type { Emitter } from 'strict-event-emitter' +import { DeferredPromise } from '@open-draft/deferred-promise' +import { until } from '@open-draft/until' +import type { HttpRequestEventMap } from '../glossary' +import { emitAsync } from './emitAsync' +import { kResponsePromise, RequestController } from '../RequestController' +import { + createServerErrorResponse, + isResponseError, + ResponseError, +} from './responseUtils' +import { InterceptorError } from '../InterceptorError' +import { isNodeLikeError } from './isNodeLikeError' + +interface HandleRequestOptions { + requestId: string + request: Request + emitter: Emitter + controller: RequestController + + /** + * Called when the request has been handled + * with the given `Response` instance. + */ + onResponse: (response: Response) => void | Promise + + /** + * Called when the request has been handled + * with the given `Response.error()` instance. + */ + onRequestError: (response: ResponseError) => void + + /** + * Called when an unhandled error happens during the + * request handling. This is never a thrown error/response. + */ + onError: (error: unknown) => void +} + +/** + * @returns {Promise} Indicates whether the request has been handled. + */ +export async function handleRequest( + options: HandleRequestOptions +): Promise { + const handleResponse = async (response: Response | Error) => { + if (response instanceof Error) { + options.onError(response) + } + + // Handle "Response.error()" instances. + else if (isResponseError(response)) { + options.onRequestError(response) + } else { + await options.onResponse(response) + } + + return true + } + + const handleResponseError = async (error: unknown): Promise => { + // Forward the special interceptor error instances + // to the developer. These must not be handled in any way. + if (error instanceof InterceptorError) { + throw result.error + } + + // Support mocking Node.js-like errors. + if (isNodeLikeError(error)) { + options.onError(error) + return true + } + + // Handle thrown responses. + if (error instanceof Response) { + return await handleResponse(error) + } + + return false + } + + // Add the last "request" listener to check if the request + // has been handled in any way. If it hasn't, resolve the + // response promise with undefined. + options.emitter.once('request', ({ requestId: pendingRequestId }) => { + if (pendingRequestId !== options.requestId) { + return + } + + if (options.controller[kResponsePromise].state === 'pending') { + options.controller[kResponsePromise].resolve(undefined) + } + }) + + const requestAbortPromise = new DeferredPromise() + + /** + * @note `signal` is not always defined in React Native. + */ + if (options.request.signal) { + if (options.request.signal.aborted) { + requestAbortPromise.reject(options.request.signal.reason) + } else { + options.request.signal.addEventListener( + 'abort', + () => { + requestAbortPromise.reject(options.request.signal.reason) + }, + { once: true } + ) + } + } + + const result = await until(async () => { + // Emit the "request" event and wait until all the listeners + // for that event are finished (e.g. async listeners awaited). + // By the end of this promise, the developer cannot affect the + // request anymore. + const requestListtenersPromise = emitAsync(options.emitter, 'request', { + requestId: options.requestId, + request: options.request, + controller: options.controller, + }) + + await Promise.race([ + // Short-circuit the request handling promise if the request gets aborted. + requestAbortPromise, + requestListtenersPromise, + options.controller[kResponsePromise], + ]) + + // The response promise will settle immediately once + // the developer calls either "respondWith" or "errorWith". + const mockedResponse = await options.controller[kResponsePromise] + return mockedResponse + }) + + // Handle the request being aborted while waiting for the request listeners. + if (requestAbortPromise.state === 'rejected') { + options.onError(requestAbortPromise.rejectionReason) + return true + } + + if (result.error) { + // Handle the error during the request listener execution. + // These can be thrown responses or request errors. + if (await handleResponseError(result.error)) { + return true + } + + // If the developer has added "unhandledException" listeners, + // allow them to handle the error. They can translate it to a + // mocked response, network error, or forward it as-is. + if (options.emitter.listenerCount('unhandledException') > 0) { + // Create a new request controller just for the unhandled exception case. + // This is needed because the original controller might have been already + // interacted with (e.g. "respondWith" or "errorWith" called on it). + const unhandledExceptionController = new RequestController( + options.request + ) + + await emitAsync(options.emitter, 'unhandledException', { + error: result.error, + request: options.request, + requestId: options.requestId, + controller: unhandledExceptionController, + }).then(() => { + // If all the "unhandledException" listeners have finished + // but have not handled the response in any way, preemptively + // resolve the pending response promise from the new controller. + // This prevents it from hanging forever. + if ( + unhandledExceptionController[kResponsePromise].state === 'pending' + ) { + unhandledExceptionController[kResponsePromise].resolve(undefined) + } + }) + + const nextResult = await until( + () => unhandledExceptionController[kResponsePromise] + ) + + /** + * @note Handle the result of the unhandled controller + * in the same way as the original request controller. + * The exception here is that thrown errors within the + * "unhandledException" event do NOT result in another + * emit of the same event. They are forwarded as-is. + */ + if (nextResult.error) { + return handleResponseError(nextResult.error) + } + + if (nextResult.data) { + return handleResponse(nextResult.data) + } + } + + // Otherwise, coerce unhandled exceptions to a 500 Internal Server Error response. + options.onResponse(createServerErrorResponse(result.error)) + return true + } + + /** + * Handle a mocked Response instance. + * @note That this can also be an Error in case + * the developer called "errorWith". This differentiates + * unhandled exceptions from intended errors. + */ + if (result.data) { + return handleResponse(result.data) + } + + // In all other cases, consider the request unhandled. + // The interceptor must perform it as-is. + return false +} diff --git a/node_modules/@mswjs/interceptors/src/utils/hasConfigurableGlobal.test.ts b/node_modules/@mswjs/interceptors/src/utils/hasConfigurableGlobal.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..9bade24939b27eeffa89f5417a1b6b065d1c8c76 --- /dev/null +++ b/node_modules/@mswjs/interceptors/src/utils/hasConfigurableGlobal.test.ts @@ -0,0 +1,83 @@ +import { vi, beforeAll, afterEach, afterAll, it, expect } from 'vitest' +import { hasConfigurableGlobal } from './hasConfigurableGlobal' + +beforeAll(() => { + vi.spyOn(console, 'error').mockImplementation(() => {}) +}) + +afterEach(() => { + vi.resetAllMocks() +}) + +afterAll(() => { + vi.restoreAllMocks() +}) + +it('returns true if the global property exists and is configurable', () => { + Object.defineProperty(global, '_existsAndConfigurable', { + value: 'something', + configurable: true, + }) + + expect(hasConfigurableGlobal('_existsAndConfigurable')).toBe(true) +}) + +it('returns false if the global property does not exist', () => { + expect(hasConfigurableGlobal('_non-existing')).toBe(false) +}) + +it('returns false for existing global with undefined as a value', () => { + Object.defineProperty(global, '_existsAndUndefined', { + value: undefined, + configurable: true, + }) + expect(hasConfigurableGlobal('_existsAndUndefined')).toBe(false) +}) + +it('returns false for existing global with null as a value', () => { + Object.defineProperty(global, '_existsAndNull', { + value: null, + configurable: true, + }) + expect(hasConfigurableGlobal('_existsAndNull')).toBe(false) +}) + +it('returns false for existing global with a getter that returns undefined', () => { + Object.defineProperty(global, '_existsGetterUndefined', { + get: () => undefined, + configurable: true, + }) + expect(hasConfigurableGlobal('_existsGetterUndefined')).toBe(false) +}) + +it('returns false and prints an error for implicitly non-configurable global property', () => { + Object.defineProperty(global, '_implicitlyNonConfigurable', { + value: 'something', + }) + + expect(hasConfigurableGlobal('_implicitlyNonConfigurable')).toBe(false) + expect(console.error).toHaveBeenCalledWith( + '[MSW] Failed to apply interceptor: the global `_implicitlyNonConfigurable` property is non-configurable. This is likely an issue with your environment. If you are using a framework, please open an issue about this in their repository.' + ) +}) + +it('returns false and prints an error for explicitly non-configurable global property', () => { + Object.defineProperty(global, '_explicitlyNonConfigurable', { + value: 'something', + configurable: false, + }) + + expect(hasConfigurableGlobal('_explicitlyNonConfigurable')).toBe(false) + expect(console.error).toHaveBeenCalledWith( + '[MSW] Failed to apply interceptor: the global `_explicitlyNonConfigurable` property is non-configurable. This is likely an issue with your environment. If you are using a framework, please open an issue about this in their repository.' + ) +}) + +it('returns false and prints an error for global property that only has a getter', () => { + Object.defineProperty(global, '_onlyGetter', { get: () => 'something' }) + + expect(hasConfigurableGlobal('_onlyGetter')).toBe(false) + expect(console.error).toHaveBeenCalledWith( + '[MSW] Failed to apply interceptor: the global `_onlyGetter` property is non-configurable. This is likely an issue with your environment. If you are using a framework, please open an issue about this in their repository.' + ) +}) diff --git a/node_modules/@mswjs/interceptors/src/utils/hasConfigurableGlobal.ts b/node_modules/@mswjs/interceptors/src/utils/hasConfigurableGlobal.ts new file mode 100644 index 0000000000000000000000000000000000000000..c8304533221b9e5a7da5fce123f089e9d2ce96d8 --- /dev/null +++ b/node_modules/@mswjs/interceptors/src/utils/hasConfigurableGlobal.ts @@ -0,0 +1,34 @@ +/** + * Returns a boolean indicating whether the given global property + * is defined and is configurable. + */ +export function hasConfigurableGlobal(propertyName: string): boolean { + const descriptor = Object.getOwnPropertyDescriptor(globalThis, propertyName) + + // The property is not set at all. + if (typeof descriptor === 'undefined') { + return false + } + + // The property is set to a getter that returns undefined. + if ( + typeof descriptor.get === 'function' && + typeof descriptor.get() === 'undefined' + ) { + return false + } + + // The property is set to a value equal to undefined. + if (typeof descriptor.get === 'undefined' && descriptor.value == null) { + return false + } + + if (typeof descriptor.set === 'undefined' && !descriptor.configurable) { + console.error( + `[MSW] Failed to apply interceptor: the global \`${propertyName}\` property is non-configurable. This is likely an issue with your environment. If you are using a framework, please open an issue about this in their repository.` + ) + return false + } + + return true +} diff --git a/node_modules/@mswjs/interceptors/src/utils/isNodeLikeError.ts b/node_modules/@mswjs/interceptors/src/utils/isNodeLikeError.ts new file mode 100644 index 0000000000000000000000000000000000000000..f74dea789c9fd82fece9a8e57495f5fefc410bc1 --- /dev/null +++ b/node_modules/@mswjs/interceptors/src/utils/isNodeLikeError.ts @@ -0,0 +1,13 @@ +export function isNodeLikeError( + error: unknown +): error is NodeJS.ErrnoException { + if (error == null) { + return false + } + + if (!(error instanceof Error)) { + return false + } + + return 'code' in error && 'errno' in error +} diff --git a/node_modules/@mswjs/interceptors/src/utils/isObject.test.ts b/node_modules/@mswjs/interceptors/src/utils/isObject.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..ea4e99d60a605eb74731c51d405e3dee30845ca5 --- /dev/null +++ b/node_modules/@mswjs/interceptors/src/utils/isObject.test.ts @@ -0,0 +1,21 @@ +import { it, expect } from 'vitest' +import { isObject } from './isObject' + +it('returns true given an object', () => { + expect(isObject({})).toBe(true) + expect(isObject({ a: 1 })).toBe(true) +}) + +it('returns false given an object-like instance', () => { + expect(isObject([1])).toBe(false) + expect(isObject(function () {})).toBe(false) + expect(isObject(new Response())).toBe(false) +}) + +it('returns false given a non-object instance', () => { + expect(isObject(null)).toBe(false) + expect(isObject(undefined)).toBe(false) + expect(isObject(false)).toBe(false) + expect(isObject(123)).toBe(false) + expect(isObject(Symbol('object Object'))).toBe(false) +}) diff --git a/node_modules/@mswjs/interceptors/src/utils/isObject.ts b/node_modules/@mswjs/interceptors/src/utils/isObject.ts new file mode 100644 index 0000000000000000000000000000000000000000..096e12ea52e8fdefe0819d5717506a8d1a36707a --- /dev/null +++ b/node_modules/@mswjs/interceptors/src/utils/isObject.ts @@ -0,0 +1,8 @@ +/** + * Determines if a given value is an instance of object. + */ +export function isObject(value: any, loose = false): value is T { + return loose + ? Object.prototype.toString.call(value).startsWith('[object ') + : Object.prototype.toString.call(value) === '[object Object]' +} diff --git a/node_modules/@mswjs/interceptors/src/utils/isPropertyAccessible.ts b/node_modules/@mswjs/interceptors/src/utils/isPropertyAccessible.ts new file mode 100644 index 0000000000000000000000000000000000000000..4a80a75bc4b635f6d1e8ea2c8e01756f56da4bb5 --- /dev/null +++ b/node_modules/@mswjs/interceptors/src/utils/isPropertyAccessible.ts @@ -0,0 +1,19 @@ +/** + * A function that validates if property access is possible on an object + * without throwing. It returns `true` if the property access is possible + * and `false` otherwise. + * + * Environments like miniflare will throw on property access on certain objects + * like Request and Response, for unimplemented properties. + */ +export function isPropertyAccessible>( + obj: Obj, + key: keyof Obj +) { + try { + obj[key] + return true + } catch { + return false + } +} diff --git a/node_modules/@mswjs/interceptors/src/utils/nextTick.ts b/node_modules/@mswjs/interceptors/src/utils/nextTick.ts new file mode 100644 index 0000000000000000000000000000000000000000..a080ca1e1f34f4a440497765d1509403b55025ed --- /dev/null +++ b/node_modules/@mswjs/interceptors/src/utils/nextTick.ts @@ -0,0 +1,11 @@ +export function nextTick(callback: () => void) { + setTimeout(callback, 0) +} + +export function nextTickAsync(callback: () => void) { + return new Promise((resolve) => { + setTimeout(() => { + resolve(callback()) + }, 0) + }) +} diff --git a/node_modules/@mswjs/interceptors/src/utils/parseJson.test.ts b/node_modules/@mswjs/interceptors/src/utils/parseJson.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..b0210348163aceceeb7bf077250bb5f7e5143eb2 --- /dev/null +++ b/node_modules/@mswjs/interceptors/src/utils/parseJson.test.ts @@ -0,0 +1,10 @@ +import { it, expect } from 'vitest' +import { parseJson } from './parseJson' + +it('parses a given string into JSON', () => { + expect(parseJson('{"id":1}')).toEqual({ id: 1 }) +}) + +it('returns null given invalid JSON string', () => { + expect(parseJson('{"o:2\'')).toBeNull() +}) diff --git a/node_modules/@mswjs/interceptors/src/utils/parseJson.ts b/node_modules/@mswjs/interceptors/src/utils/parseJson.ts new file mode 100644 index 0000000000000000000000000000000000000000..af8d2e6da6e09485911865eba28b239db6fa26b1 --- /dev/null +++ b/node_modules/@mswjs/interceptors/src/utils/parseJson.ts @@ -0,0 +1,12 @@ +/** + * Parses a given string into JSON. + * Gracefully handles invalid JSON by returning `null`. + */ +export function parseJson(data: string): Record | null { + try { + const json = JSON.parse(data) + return json + } catch (_) { + return null + } +} diff --git a/node_modules/@mswjs/interceptors/src/utils/responseUtils.ts b/node_modules/@mswjs/interceptors/src/utils/responseUtils.ts new file mode 100644 index 0000000000000000000000000000000000000000..68cafbaf10ae46c383b5b16b3c6c6674e2c26ec7 --- /dev/null +++ b/node_modules/@mswjs/interceptors/src/utils/responseUtils.ts @@ -0,0 +1,39 @@ +import { isPropertyAccessible } from './isPropertyAccessible' + +/** + * Creates a generic 500 Unhandled Exception response. + */ +export function createServerErrorResponse(body: unknown): Response { + return new Response( + JSON.stringify( + body instanceof Error + ? { + name: body.name, + message: body.message, + stack: body.stack, + } + : body + ), + { + status: 500, + statusText: 'Unhandled Exception', + headers: { + 'Content-Type': 'application/json', + }, + } + ) +} + +export type ResponseError = Response & { type: 'error' } + +/** + * Check if the given response is a `Response.error()`. + * + * @note Some environments, like Miniflare (Cloudflare) do not + * implement the "Response.type" property and throw on its access. + * Safely check if we can access "type" on "Response" before continuing. + * @see https://github.com/mswjs/msw/issues/1834 + */ +export function isResponseError(response: Response): response is ResponseError { + return isPropertyAccessible(response, 'type') && response.type === 'error' +} diff --git a/node_modules/@open-draft/deferred-promise/README.md b/node_modules/@open-draft/deferred-promise/README.md new file mode 100644 index 0000000000000000000000000000000000000000..e19d242ab6ebde58cbb679f472efa0acef4bcdf5 --- /dev/null +++ b/node_modules/@open-draft/deferred-promise/README.md @@ -0,0 +1,191 @@ +# Deferred Promise + +The `DeferredPromise` class is a Promise-compatible abstraction that defers resolving/rejecting promises to another closure. This class is primarily useful when one part of your system establishes as promise but another part of your system fulfills it. + +> This class is conceptually inspired by the [`createDeferredPromise()`](https://github.com/nodejs/node/blob/696fd4b14fc34cc2d01497a3abd9bb441b89be50/lib/internal/util.js#L468-L477) internal utility in Node.js. Unlike the Node.js implementation, however, `DeferredProimse` _extends_ a native `Promise`, allowing the consumer to handle deferred promises like regular promises (no `.promise` instance nesting). + +## Getting started + +```sh +npm install @open-draft/deferred-promise +``` + +## Documentation + +- [**`createDeferredExecutor()`**](#createdeferredexecutor) + - [`DeferredExecutor.state`](#deferredexecutorstate) + - [`DeferredExecutor.resolve()`](#deferredexecutorresolve) + - [`DeferredExecutor.reject()`](#deferredexecutorreject) + - [`DeferredExecutor.rejectionReason`](#deferredexecutorrejectionreason) +- [**Class: `DeferredPromise`**](#class-deferredpromise) + - [`new DeferredPromise()`](#new-defferedpromise) + - [`deferredPromise.state`](#deferredpromisestate) + - [`deferredPromise.resolve()`](#deferredpromiseresolve) + - [`deferredPromise.reject()`](#deferredpromisereject) + - [`deferredPromise.rejectionReason`](#deferredpromiserejectionreason) + +--- + +## `createDeferredExecutor()` + +Creates a Promise executor function that delegates its resolution to the current scope. + +```js +import { createDeferredExecutor } from '@open-draft/deferred-promise' + +const executor = createDeferredExecutor() +const promise = new Promise(executor) + +executor.resolve('hello') +// executor.reject(new Error('Reason')) +``` + +Deferred executor allows you to control any promise remotely and doesn't affect the Promise instance in any way. Similar to the [`DeferredPromise`](#class-deferredpromise) instance, the deferred executor exposes additional promise properties like `state`, `rejectionReason`, `resolve`, and `reject`. In fact, the `DeferredPromise` class is implemented on top of the deferred executor. + +```js +const executor = createDeferredExecutor() +const promise = new Promise(executor) + +executor.reject('reason') + +nextTick(() => { + console.log(executor.rejectionReason) // "reason" +}) +``` + +### `DeferredExecutor.state` + +- `<"pending" | "fulfilled" | "rejected">` **Default:** `"pending"` + +```js +const executor = createDeferredExecutor() +const promise = new Promise(executor) + +console.log(executor.state) // "pending" +``` + +Calling [`resolve()`](#deferredexecutorresolve) and [`reject()`](#deferredexecutorreject) methods of the executor transitions the state to "fulfilled" and "rejected" respectively. + +### `DeferredExecutor.resolve()` + +Resolves the promise with a given value. + +```js +const executor = createDeferredExecutor() +const promise = new Promise(executor) + +console.log(executor.state) // "pending" + +executor.resolve() + +// The promise state is still "pending" +// because promises are settled in the next microtask. +console.log(executor.state) // "pending" + +nextTick(() => { + // In the next microtask, the promise's state is resolved. + console.log(executor.state) // "fulfilled" +}) +``` + +### `DeferredExecutor.reject()` + +Rejects the promise with a given reason. + +```js +const executor = createDeferredExecutor() +const promise = new Promise(executor) + +executor.reject(new Error('Failed to fetch')) + +nextTick(() => { + console.log(executor.state) // "rejected" + console.log(executor.rejectionReason) // Error("Failed to fetch") +}) +``` + +You can access the rejection reason of the promise at any time by the [`rejectionReason`](#deferredexecutorrejectionreason) property of the deferred executor. + +### `DeferredExecutor.rejectionReason` + +Returns the reason of the promise rejection. If no reason has been provided to the `reject()` call, `undefined` is returned instead. + +```js +const executor = createDeferredExecutor() +const promise = new Promise(executor) + +promise.reject(new Error('Internal Server Error')) + +nextTick(() => { + console.log(promise.rejectionReason) // Error("Internal Server Error") +}) +``` + +--- + +## Class: `DeferredPromise` + +### `new DefferedPromise()` + +Creates a new instance of a deferred promise. + +```js +import { DeferredPromise } from '@open-draft/deferred-promise' + +const promise = new DeferredPromise() +``` + +A deferred promise is a Promise-compatible class that constructs a regular Promise instance under the hood, controlling it via the [deferred executor](#createdeferredexecutor). + +A deferred promise is fully compatible with the regular Promise, both type- and runtime-wise, e.g. a deferred promise can be chained and awaited normally. + +```js +const promise = new DefferredPromise() + .then((value) => value.toUpperCase()) + .then((value) => value.substring(0, 2)) + .catch((error) => console.error(error)) + +await promise +``` + +Unlike the regular Promise, however, a deferred promise doesn't accept the `executor` function as the constructor argument. Instead, the resolution of the deferred promise is deferred to the current scope (thus the name). + +```js +function getPort() { + // Notice that you don't provide any executor function + // when constructing a deferred promise. + const portPromise = new DeferredPromise() + + port.on('open', (port) => { + // Resolve the deferred promise whenever necessary. + portPromise.resolve(port) + }) + + // Return the deferred promise immediately. + return portPromise +} +``` + +Use the [`resolve()`](#deferredpromiseresolve) and [`reject()`](#deferredpromisereject) methods of the deferred promise instance to resolve and reject that promise respectively. + +### `deferredPromise.state` + +See [`DeferredExecutor.state`](#deferredexecutorstate) + +### `deferredPromise.resolve()` + +See [`DeferredExecutor.resolve()`](#deferredexecutorresolve) + +### `deferredPromise.reject()` + +See [`DeferredExecutor.reject()`](#deferredexecutorreject) + +### `deferredPromise.rejectionReason` + +See [`DeferredExecutor.rejectionReason`](#deferredexecutorrejectionreason) + +--- + +## Mentions + +- [Jonas Kuske](https://github.com/jonaskuske) for the phenomenal work around improving Promise-compliance. diff --git a/node_modules/@open-draft/deferred-promise/build/index.d.mts b/node_modules/@open-draft/deferred-promise/build/index.d.mts new file mode 100644 index 0000000000000000000000000000000000000000..f4206473c47a52a6aef67d841aaa65168ad467a7 --- /dev/null +++ b/node_modules/@open-draft/deferred-promise/build/index.d.mts @@ -0,0 +1,27 @@ +declare type PromiseState = 'pending' | 'fulfilled' | 'rejected'; +declare type Executor = ConstructorParameters>[0]; +declare type ResolveFunction = Parameters>[0]; +declare type RejectFunction = Parameters>[1]; +declare type DeferredPromiseExecutor = { + (resolve?: ResolveFunction, reject?: RejectFunction): void; + resolve: ResolveFunction; + reject: RejectFunction; + result?: Output; + state: PromiseState; + rejectionReason?: unknown; +}; +declare function createDeferredExecutor(): DeferredPromiseExecutor; + +declare class DeferredPromise extends Promise { + #private; + resolve: ResolveFunction; + reject: RejectFunction; + constructor(executor?: Executor | null); + get state(): PromiseState; + get rejectionReason(): unknown; + then(onFulfilled?: (value: Input) => ThenResult | PromiseLike, onRejected?: (reason: any) => CatchResult | PromiseLike): DeferredPromise; + catch(onRejected?: (reason: any) => CatchResult | PromiseLike): DeferredPromise; + finally(onfinally?: () => void | Promise): DeferredPromise; +} + +export { DeferredPromise, DeferredPromiseExecutor, Executor, PromiseState, RejectFunction, ResolveFunction, createDeferredExecutor }; diff --git a/node_modules/@open-draft/deferred-promise/build/index.d.ts b/node_modules/@open-draft/deferred-promise/build/index.d.ts new file mode 100644 index 0000000000000000000000000000000000000000..f4206473c47a52a6aef67d841aaa65168ad467a7 --- /dev/null +++ b/node_modules/@open-draft/deferred-promise/build/index.d.ts @@ -0,0 +1,27 @@ +declare type PromiseState = 'pending' | 'fulfilled' | 'rejected'; +declare type Executor = ConstructorParameters>[0]; +declare type ResolveFunction = Parameters>[0]; +declare type RejectFunction = Parameters>[1]; +declare type DeferredPromiseExecutor = { + (resolve?: ResolveFunction, reject?: RejectFunction): void; + resolve: ResolveFunction; + reject: RejectFunction; + result?: Output; + state: PromiseState; + rejectionReason?: unknown; +}; +declare function createDeferredExecutor(): DeferredPromiseExecutor; + +declare class DeferredPromise extends Promise { + #private; + resolve: ResolveFunction; + reject: RejectFunction; + constructor(executor?: Executor | null); + get state(): PromiseState; + get rejectionReason(): unknown; + then(onFulfilled?: (value: Input) => ThenResult | PromiseLike, onRejected?: (reason: any) => CatchResult | PromiseLike): DeferredPromise; + catch(onRejected?: (reason: any) => CatchResult | PromiseLike): DeferredPromise; + finally(onfinally?: () => void | Promise): DeferredPromise; +} + +export { DeferredPromise, DeferredPromiseExecutor, Executor, PromiseState, RejectFunction, ResolveFunction, createDeferredExecutor }; diff --git a/node_modules/@open-draft/deferred-promise/build/index.js b/node_modules/@open-draft/deferred-promise/build/index.js new file mode 100644 index 0000000000000000000000000000000000000000..8612d834cc1d55e2e8e9f49df6c57087ae3084f7 --- /dev/null +++ b/node_modules/@open-draft/deferred-promise/build/index.js @@ -0,0 +1,99 @@ +var __defProp = Object.defineProperty; +var __getOwnPropDesc = Object.getOwnPropertyDescriptor; +var __getOwnPropNames = Object.getOwnPropertyNames; +var __hasOwnProp = Object.prototype.hasOwnProperty; +var __export = (target, all) => { + for (var name in all) + __defProp(target, name, { get: all[name], enumerable: true }); +}; +var __copyProps = (to, from, except, desc) => { + if (from && typeof from === "object" || typeof from === "function") { + for (let key of __getOwnPropNames(from)) + if (!__hasOwnProp.call(to, key) && key !== except) + __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); + } + return to; +}; +var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); + +// src/index.ts +var src_exports = {}; +__export(src_exports, { + DeferredPromise: () => DeferredPromise, + createDeferredExecutor: () => createDeferredExecutor +}); +module.exports = __toCommonJS(src_exports); + +// src/createDeferredExecutor.ts +function createDeferredExecutor() { + const executor = (resolve, reject) => { + executor.state = "pending"; + executor.resolve = (data) => { + if (executor.state !== "pending") { + return; + } + executor.result = data; + const onFulfilled = (value) => { + executor.state = "fulfilled"; + return value; + }; + return resolve( + data instanceof Promise ? data : Promise.resolve(data).then(onFulfilled) + ); + }; + executor.reject = (reason) => { + if (executor.state !== "pending") { + return; + } + queueMicrotask(() => { + executor.state = "rejected"; + }); + return reject(executor.rejectionReason = reason); + }; + }; + return executor; +} + +// src/DeferredPromise.ts +var DeferredPromise = class extends Promise { + #executor; + resolve; + reject; + constructor(executor = null) { + const deferredExecutor = createDeferredExecutor(); + super((originalResolve, originalReject) => { + deferredExecutor(originalResolve, originalReject); + executor?.(deferredExecutor.resolve, deferredExecutor.reject); + }); + this.#executor = deferredExecutor; + this.resolve = this.#executor.resolve; + this.reject = this.#executor.reject; + } + get state() { + return this.#executor.state; + } + get rejectionReason() { + return this.#executor.rejectionReason; + } + then(onFulfilled, onRejected) { + return this.#decorate(super.then(onFulfilled, onRejected)); + } + catch(onRejected) { + return this.#decorate(super.catch(onRejected)); + } + finally(onfinally) { + return this.#decorate(super.finally(onfinally)); + } + #decorate(promise) { + return Object.defineProperties(promise, { + resolve: { configurable: true, value: this.resolve }, + reject: { configurable: true, value: this.reject } + }); + } +}; +// Annotate the CommonJS export names for ESM import in node: +0 && (module.exports = { + DeferredPromise, + createDeferredExecutor +}); +//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/node_modules/@open-draft/deferred-promise/build/index.js.map b/node_modules/@open-draft/deferred-promise/build/index.js.map new file mode 100644 index 0000000000000000000000000000000000000000..55123c69bffa33aa648e4e4b08890b271e83a7b8 --- /dev/null +++ b/node_modules/@open-draft/deferred-promise/build/index.js.map @@ -0,0 +1 @@ +{"version":3,"sources":["../src/index.ts","../src/createDeferredExecutor.ts","../src/DeferredPromise.ts"],"sourcesContent":["export * from './createDeferredExecutor'\nexport * from './DeferredPromise'\n","export type PromiseState = 'pending' | 'fulfilled' | 'rejected'\n\nexport type Executor = ConstructorParameters>[0]\nexport type ResolveFunction = Parameters>[0]\nexport type RejectFunction = Parameters>[1]\n\nexport type DeferredPromiseExecutor = {\n (resolve?: ResolveFunction, reject?: RejectFunction): void\n\n resolve: ResolveFunction\n reject: RejectFunction\n result?: Output\n state: PromiseState\n rejectionReason?: unknown\n}\nexport function createDeferredExecutor<\n Input = never,\n Output = Input\n>(): DeferredPromiseExecutor {\n const executor = >((\n resolve,\n reject\n ) => {\n executor.state = 'pending'\n\n executor.resolve = (data) => {\n if (executor.state !== 'pending') {\n return\n }\n\n executor.result = data as Output\n\n const onFulfilled = (value: Value) => {\n executor.state = 'fulfilled'\n return value\n }\n\n return resolve(\n data instanceof Promise ? data : Promise.resolve(data).then(onFulfilled)\n )\n }\n\n executor.reject = (reason) => {\n if (executor.state !== 'pending') {\n return\n }\n\n queueMicrotask(() => {\n executor.state = 'rejected'\n })\n\n return reject((executor.rejectionReason = reason))\n }\n })\n\n return executor\n}\n","import {\n type Executor,\n type RejectFunction,\n type ResolveFunction,\n type DeferredPromiseExecutor,\n createDeferredExecutor,\n} from './createDeferredExecutor'\n\nexport class DeferredPromise extends Promise {\n #executor: DeferredPromiseExecutor\n\n public resolve: ResolveFunction\n public reject: RejectFunction\n\n constructor(executor: Executor | null = null) {\n const deferredExecutor = createDeferredExecutor()\n super((originalResolve, originalReject) => {\n deferredExecutor(originalResolve, originalReject)\n executor?.(deferredExecutor.resolve, deferredExecutor.reject)\n })\n\n this.#executor = deferredExecutor\n this.resolve = this.#executor.resolve\n this.reject = this.#executor.reject\n }\n\n public get state() {\n return this.#executor.state\n }\n\n public get rejectionReason() {\n return this.#executor.rejectionReason\n }\n\n public then(\n onFulfilled?: (value: Input) => ThenResult | PromiseLike,\n onRejected?: (reason: any) => CatchResult | PromiseLike\n ) {\n return this.#decorate(super.then(onFulfilled, onRejected))\n }\n\n public catch(\n onRejected?: (reason: any) => CatchResult | PromiseLike\n ) {\n return this.#decorate(super.catch(onRejected))\n }\n\n public finally(onfinally?: () => void | Promise) {\n return this.#decorate(super.finally(onfinally))\n }\n\n #decorate(\n promise: Promise\n ): DeferredPromise {\n return Object.defineProperties(promise, {\n resolve: { configurable: true, value: this.resolve },\n reject: { configurable: true, value: this.reject },\n }) as DeferredPromise\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACeO,SAAS,yBAG4B;AAC1C,QAAM,WAAoD,CACxD,SACA,WACG;AACH,aAAS,QAAQ;AAEjB,aAAS,UAAU,CAAC,SAAS;AAC3B,UAAI,SAAS,UAAU,WAAW;AAChC;AAAA,MACF;AAEA,eAAS,SAAS;AAElB,YAAM,cAAc,CAAQ,UAAiB;AAC3C,iBAAS,QAAQ;AACjB,eAAO;AAAA,MACT;AAEA,aAAO;AAAA,QACL,gBAAgB,UAAU,OAAO,QAAQ,QAAQ,IAAI,EAAE,KAAK,WAAW;AAAA,MACzE;AAAA,IACF;AAEA,aAAS,SAAS,CAAC,WAAW;AAC5B,UAAI,SAAS,UAAU,WAAW;AAChC;AAAA,MACF;AAEA,qBAAe,MAAM;AACnB,iBAAS,QAAQ;AAAA,MACnB,CAAC;AAED,aAAO,OAAQ,SAAS,kBAAkB,MAAO;AAAA,IACnD;AAAA,EACF;AAEA,SAAO;AACT;;;AChDO,IAAM,kBAAN,cAAqD,QAAe;AAAA,EACzE;AAAA,EAEO;AAAA,EACA;AAAA,EAEP,YAAY,WAAmC,MAAM;AACnD,UAAM,mBAAmB,uBAAuB;AAChD,UAAM,CAAC,iBAAiB,mBAAmB;AACzC,uBAAiB,iBAAiB,cAAc;AAChD,iBAAW,iBAAiB,SAAS,iBAAiB,MAAM;AAAA,IAC9D,CAAC;AAED,SAAK,YAAY;AACjB,SAAK,UAAU,KAAK,UAAU;AAC9B,SAAK,SAAS,KAAK,UAAU;AAAA,EAC/B;AAAA,EAEA,IAAW,QAAQ;AACjB,WAAO,KAAK,UAAU;AAAA,EACxB;AAAA,EAEA,IAAW,kBAAkB;AAC3B,WAAO,KAAK,UAAU;AAAA,EACxB;AAAA,EAEO,KACL,aACA,YACA;AACA,WAAO,KAAK,UAAU,MAAM,KAAK,aAAa,UAAU,CAAC;AAAA,EAC3D;AAAA,EAEO,MACL,YACA;AACA,WAAO,KAAK,UAAU,MAAM,MAAM,UAAU,CAAC;AAAA,EAC/C;AAAA,EAEO,QAAQ,WAAuC;AACpD,WAAO,KAAK,UAAU,MAAM,QAAQ,SAAS,CAAC;AAAA,EAChD;AAAA,EAEA,UACE,SACqC;AACrC,WAAO,OAAO,iBAAiB,SAAS;AAAA,MACtC,SAAS,EAAE,cAAc,MAAM,OAAO,KAAK,QAAQ;AAAA,MACnD,QAAQ,EAAE,cAAc,MAAM,OAAO,KAAK,OAAO;AAAA,IACnD,CAAC;AAAA,EACH;AACF;","names":[]} \ No newline at end of file diff --git a/node_modules/@open-draft/deferred-promise/build/index.mjs b/node_modules/@open-draft/deferred-promise/build/index.mjs new file mode 100644 index 0000000000000000000000000000000000000000..a1a05c6cd21df1dc8fc65a8725f8853dbc500420 --- /dev/null +++ b/node_modules/@open-draft/deferred-promise/build/index.mjs @@ -0,0 +1,72 @@ +// src/createDeferredExecutor.ts +function createDeferredExecutor() { + const executor = (resolve, reject) => { + executor.state = "pending"; + executor.resolve = (data) => { + if (executor.state !== "pending") { + return; + } + executor.result = data; + const onFulfilled = (value) => { + executor.state = "fulfilled"; + return value; + }; + return resolve( + data instanceof Promise ? data : Promise.resolve(data).then(onFulfilled) + ); + }; + executor.reject = (reason) => { + if (executor.state !== "pending") { + return; + } + queueMicrotask(() => { + executor.state = "rejected"; + }); + return reject(executor.rejectionReason = reason); + }; + }; + return executor; +} + +// src/DeferredPromise.ts +var DeferredPromise = class extends Promise { + #executor; + resolve; + reject; + constructor(executor = null) { + const deferredExecutor = createDeferredExecutor(); + super((originalResolve, originalReject) => { + deferredExecutor(originalResolve, originalReject); + executor?.(deferredExecutor.resolve, deferredExecutor.reject); + }); + this.#executor = deferredExecutor; + this.resolve = this.#executor.resolve; + this.reject = this.#executor.reject; + } + get state() { + return this.#executor.state; + } + get rejectionReason() { + return this.#executor.rejectionReason; + } + then(onFulfilled, onRejected) { + return this.#decorate(super.then(onFulfilled, onRejected)); + } + catch(onRejected) { + return this.#decorate(super.catch(onRejected)); + } + finally(onfinally) { + return this.#decorate(super.finally(onfinally)); + } + #decorate(promise) { + return Object.defineProperties(promise, { + resolve: { configurable: true, value: this.resolve }, + reject: { configurable: true, value: this.reject } + }); + } +}; +export { + DeferredPromise, + createDeferredExecutor +}; +//# sourceMappingURL=index.mjs.map \ No newline at end of file diff --git a/node_modules/@open-draft/deferred-promise/build/index.mjs.map b/node_modules/@open-draft/deferred-promise/build/index.mjs.map new file mode 100644 index 0000000000000000000000000000000000000000..b2340f4a1f44e2de9bc6cd6c9fdcf29a5dae6252 --- /dev/null +++ b/node_modules/@open-draft/deferred-promise/build/index.mjs.map @@ -0,0 +1 @@ +{"version":3,"sources":["../src/createDeferredExecutor.ts","../src/DeferredPromise.ts"],"sourcesContent":["export type PromiseState = 'pending' | 'fulfilled' | 'rejected'\n\nexport type Executor = ConstructorParameters>[0]\nexport type ResolveFunction = Parameters>[0]\nexport type RejectFunction = Parameters>[1]\n\nexport type DeferredPromiseExecutor = {\n (resolve?: ResolveFunction, reject?: RejectFunction): void\n\n resolve: ResolveFunction\n reject: RejectFunction\n result?: Output\n state: PromiseState\n rejectionReason?: unknown\n}\nexport function createDeferredExecutor<\n Input = never,\n Output = Input\n>(): DeferredPromiseExecutor {\n const executor = >((\n resolve,\n reject\n ) => {\n executor.state = 'pending'\n\n executor.resolve = (data) => {\n if (executor.state !== 'pending') {\n return\n }\n\n executor.result = data as Output\n\n const onFulfilled = (value: Value) => {\n executor.state = 'fulfilled'\n return value\n }\n\n return resolve(\n data instanceof Promise ? data : Promise.resolve(data).then(onFulfilled)\n )\n }\n\n executor.reject = (reason) => {\n if (executor.state !== 'pending') {\n return\n }\n\n queueMicrotask(() => {\n executor.state = 'rejected'\n })\n\n return reject((executor.rejectionReason = reason))\n }\n })\n\n return executor\n}\n","import {\n type Executor,\n type RejectFunction,\n type ResolveFunction,\n type DeferredPromiseExecutor,\n createDeferredExecutor,\n} from './createDeferredExecutor'\n\nexport class DeferredPromise extends Promise {\n #executor: DeferredPromiseExecutor\n\n public resolve: ResolveFunction\n public reject: RejectFunction\n\n constructor(executor: Executor | null = null) {\n const deferredExecutor = createDeferredExecutor()\n super((originalResolve, originalReject) => {\n deferredExecutor(originalResolve, originalReject)\n executor?.(deferredExecutor.resolve, deferredExecutor.reject)\n })\n\n this.#executor = deferredExecutor\n this.resolve = this.#executor.resolve\n this.reject = this.#executor.reject\n }\n\n public get state() {\n return this.#executor.state\n }\n\n public get rejectionReason() {\n return this.#executor.rejectionReason\n }\n\n public then(\n onFulfilled?: (value: Input) => ThenResult | PromiseLike,\n onRejected?: (reason: any) => CatchResult | PromiseLike\n ) {\n return this.#decorate(super.then(onFulfilled, onRejected))\n }\n\n public catch(\n onRejected?: (reason: any) => CatchResult | PromiseLike\n ) {\n return this.#decorate(super.catch(onRejected))\n }\n\n public finally(onfinally?: () => void | Promise) {\n return this.#decorate(super.finally(onfinally))\n }\n\n #decorate(\n promise: Promise\n ): DeferredPromise {\n return Object.defineProperties(promise, {\n resolve: { configurable: true, value: this.resolve },\n reject: { configurable: true, value: this.reject },\n }) as DeferredPromise\n }\n}\n"],"mappings":";AAeO,SAAS,yBAG4B;AAC1C,QAAM,WAAoD,CACxD,SACA,WACG;AACH,aAAS,QAAQ;AAEjB,aAAS,UAAU,CAAC,SAAS;AAC3B,UAAI,SAAS,UAAU,WAAW;AAChC;AAAA,MACF;AAEA,eAAS,SAAS;AAElB,YAAM,cAAc,CAAQ,UAAiB;AAC3C,iBAAS,QAAQ;AACjB,eAAO;AAAA,MACT;AAEA,aAAO;AAAA,QACL,gBAAgB,UAAU,OAAO,QAAQ,QAAQ,IAAI,EAAE,KAAK,WAAW;AAAA,MACzE;AAAA,IACF;AAEA,aAAS,SAAS,CAAC,WAAW;AAC5B,UAAI,SAAS,UAAU,WAAW;AAChC;AAAA,MACF;AAEA,qBAAe,MAAM;AACnB,iBAAS,QAAQ;AAAA,MACnB,CAAC;AAED,aAAO,OAAQ,SAAS,kBAAkB,MAAO;AAAA,IACnD;AAAA,EACF;AAEA,SAAO;AACT;;;AChDO,IAAM,kBAAN,cAAqD,QAAe;AAAA,EACzE;AAAA,EAEO;AAAA,EACA;AAAA,EAEP,YAAY,WAAmC,MAAM;AACnD,UAAM,mBAAmB,uBAAuB;AAChD,UAAM,CAAC,iBAAiB,mBAAmB;AACzC,uBAAiB,iBAAiB,cAAc;AAChD,iBAAW,iBAAiB,SAAS,iBAAiB,MAAM;AAAA,IAC9D,CAAC;AAED,SAAK,YAAY;AACjB,SAAK,UAAU,KAAK,UAAU;AAC9B,SAAK,SAAS,KAAK,UAAU;AAAA,EAC/B;AAAA,EAEA,IAAW,QAAQ;AACjB,WAAO,KAAK,UAAU;AAAA,EACxB;AAAA,EAEA,IAAW,kBAAkB;AAC3B,WAAO,KAAK,UAAU;AAAA,EACxB;AAAA,EAEO,KACL,aACA,YACA;AACA,WAAO,KAAK,UAAU,MAAM,KAAK,aAAa,UAAU,CAAC;AAAA,EAC3D;AAAA,EAEO,MACL,YACA;AACA,WAAO,KAAK,UAAU,MAAM,MAAM,UAAU,CAAC;AAAA,EAC/C;AAAA,EAEO,QAAQ,WAAuC;AACpD,WAAO,KAAK,UAAU,MAAM,QAAQ,SAAS,CAAC;AAAA,EAChD;AAAA,EAEA,UACE,SACqC;AACrC,WAAO,OAAO,iBAAiB,SAAS;AAAA,MACtC,SAAS,EAAE,cAAc,MAAM,OAAO,KAAK,QAAQ;AAAA,MACnD,QAAQ,EAAE,cAAc,MAAM,OAAO,KAAK,OAAO;AAAA,IACnD,CAAC;AAAA,EACH;AACF;","names":[]} \ No newline at end of file diff --git a/node_modules/@open-draft/deferred-promise/package.json b/node_modules/@open-draft/deferred-promise/package.json new file mode 100644 index 0000000000000000000000000000000000000000..201c1c56cc8853269aba0c8e21675356e4aaf4eb --- /dev/null +++ b/node_modules/@open-draft/deferred-promise/package.json @@ -0,0 +1,49 @@ +{ + "name": "@open-draft/deferred-promise", + "version": "2.2.0", + "description": "A Promise-compatible abstraction that defers resolving/rejecting promises to another closure.", + "main": "./build/index.js", + "types": "./build/index.d.ts", + "module": "./build/index.mjs", + "exports": { + ".": { + "types": "./build/index.d.ts", + "require": "./build/index.js", + "default": "./build/index.mjs" + } + }, + "scripts": { + "test": "jest", + "test:compliance": "export NODE_OPTIONS=--loader=tsx || set NODE_OPTIONS=--loader=tsx&& npx -y promises-aplus-tests ./test/aplus-tests-adapter.ts", + "prebuild": "rimraf ./build", + "build": "tsup", + "release": "release publish" + }, + "files": [ + "./build" + ], + "keywords": [ + "promise", + "defer", + "deferred", + "resolve", + "reject", + "executor" + ], + "author": "Artem Zakharchenko", + "license": "MIT", + "repository": { + "type": "git", + "url": "https://github.com/open-draft/deferred-promise" + }, + "devDependencies": { + "@ossjs/release": "^0.7.2", + "@types/jest": "^29.0.1", + "jest": "^29.0.3", + "rimraf": "^3.0.2", + "ts-jest": "^29.0.0", + "tsup": "^7.2.0", + "tsx": "^3.12.1", + "typescript": "^4.8.3" + } +} \ No newline at end of file diff --git a/node_modules/@open-draft/logger/LICENSE b/node_modules/@open-draft/logger/LICENSE new file mode 100644 index 0000000000000000000000000000000000000000..7868ade175ae9284aadfba31049213f58147960e --- /dev/null +++ b/node_modules/@open-draft/logger/LICENSE @@ -0,0 +1,9 @@ +MIT License + +Copyright (c) 2023—present Artem Zakharchenko + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/node_modules/@open-draft/logger/README.md b/node_modules/@open-draft/logger/README.md new file mode 100644 index 0000000000000000000000000000000000000000..2da7455957610e71785ad3d5885b512eeed52e8a --- /dev/null +++ b/node_modules/@open-draft/logger/README.md @@ -0,0 +1,225 @@ +# Logger + +Environment-agnostic, ESM-friendly logger for simple needs. + +## Why does this exist? + +I've been using `debug` for quite some time but wanted to migrate my projects to better ESM support. Alas, `debug` doesn't ship as ESM so I went and wrote this little logger just for my needs. You will likely see it printing useful data in Mock Service Worker and beyond. + +## Installation + +```sh +npm install @open-draft/logger +``` + +## Usage + +This package has the same API for both browser and Node.js and can run in those environments out of the box. + +```js +// app.js +import { Logger } from '@open-draft/logger' + +const logger = new Logger('parser') + +logger.info('starting parsing...') +logger.warning('found legacy document format') +logger.success('parsed 120 documents!') +``` + +Logging is disabled by default. To enable logging, provide the `DEBUG` environment variable: + +```sh +DEBUG=1 node ./app.js +``` + +> You can also use `true` instead of `1`. You can also use a specific logger's name to enable [logger filtering](#logger-filtering). + +## API + +- Class: `Logger` + - [`new Logger(name)`](#new-loggername) + - [`logger.debug(message, ...positionals)`](#loggerdebugmessage-positionals) + - [`logger.info(message, ...positionals)`](#loggerinfomessage-positionals) + - [`logger.success(message, ...positionals)`](#loggersuccessmessage-positionals) + - [`logger.warning(message, ...positionals)`](#loggerwarningmessage-positionals) + - [`logger.error(message, ...positionals)`](#loggererrormessage-positionals) + - [`logger.extend(name)`](#loggerextendprefix) + - [`logger.only(callback)`](#loggeronlycallback) + +### `new Logger(name)` + +- `name` `string` the name of the logger. + +Creates a new instance of the logger. Each message printed by the logger will be prefixed with the given `name`. You can have multiple loggers with different names for different areas of your system. + +```js +const logger = new Logger('parser') +``` + +> You can nest loggers via [`logger.extend()`](#loggerextendprefix). + +### `logger.debug(message, ...positionals)` + +- `message` `string` +- `positionals` `unknown[]` + +Prints a debug message. + +```js +logger.debug('no duplicates found, skipping...') +``` + +``` +12:34:56:789 [parser] no duplicates found, skipping... +``` + +### `logger.info(message, ...positionals)` + +- `message` `string` +- `positionals` `unknown[]` + +Prints an info message. + +```js +logger.info('new parse request') +``` + +``` +12:34:56:789 [parser] new parse request +``` + +### `logger.success(message, ...positionals)` + +- `message` `string` +- `positionals` `unknown[]` + +Prints a success message. + +```js +logger.success('prased 123 documents!') +``` + +``` +12:34:56:789 ✔ [parser] prased 123 documents! +``` + +### `logger.warning(message, ...positionals)` + +- `message` `string` +- `positionals` `unknown[]` + +Prints a warning. In Node.js, prints it to `process.stderr`. + +```js +logger.warning('found legacy document format') +``` + +``` +12:34:56:789 ⚠ [parser] found legacy document format +``` + +### `logger.error(message, ...positionals)` + +- `message` `string` +- `positionals` `unknown[]` + +Prints an error. In Node.js, prints it to `process.stderr`. + +```js +logger.error('failed to parse document') +``` + +``` +12:34:56:789 ✖ [parser] failed to parse document +``` + +### `logger.extend(prefix)` + +- `prefix` `string` Additional prefix to append to the logger's name. + +Creates a new logger out of the current one. + +```js +const logger = new Logger('parser') + +function parseRequest(request) { + const requestLogger = logger.extend(`${request.method} ${request.url}`) + requestLogger.info('start parsing...') +} +``` + +``` +12:34:56:789 [parser] [GET https://example.com] start parsing... +``` + +### `logger.only(callback)` + +Executes a given callback only when the logging is activated. Useful for computing additional information for logs. + +```js +logger.only(() => { + const documentSize = getSizeBytes(document) + logger.debug(`document size: ${documentSize}`) +}) +``` + +> You can nest `logger.*` methods in the callback to `logger.only()`. + +## Log levels + +You can specify the log levels to print using the `LOG_LEVEL` environment variable. + +There are the following log levels: + +- `debug` +- `info` +- `success` +- `warning` +- `error` + +> Providing no log level will print all the messages. + +Here's an example of how to print only warnings: + +```js +// app.js +import { Logger } from '@open-draft/logger' + +const logger = new Logger('parser') + +logger.info('some info') +logger.warning('some warning') +logger.error('some error') +``` + +```js +LOG_LEVEL=warning node ./app.js +``` + +``` +12:34:56:789 ⚠ [parser] some warning +``` + +## Logger filtering + +You can only print a specific logger by providing its name as the `DEBUG` environment variable. + +```js +// app.js +import { Logger } from '@open-draft/logger' + +const appLogger = new Logger('app') +const parserLogger = new Logger('parser') + +appLogger.info('starting app...') +parserLogger.info('creating a new parser...') +``` + +```sh +DEBUG=app node ./app.js +``` + +``` +12:34:56:789 [app] starting app... +``` diff --git a/node_modules/@open-draft/logger/lib/index.d.ts b/node_modules/@open-draft/logger/lib/index.d.ts new file mode 100644 index 0000000000000000000000000000000000000000..547acfcd0c5271fd882e66c908996e5e6c71485c --- /dev/null +++ b/node_modules/@open-draft/logger/lib/index.d.ts @@ -0,0 +1,83 @@ +type ColorFunction = (text: string) => void; +declare function yellow(text: string): string; +declare function blue(text: string): string; +declare function gray(text: string): string; +declare function red(text: string): string; +declare function green(text: string): string; + +type colors_ColorFunction = ColorFunction; +declare const colors_blue: typeof blue; +declare const colors_gray: typeof gray; +declare const colors_green: typeof green; +declare const colors_red: typeof red; +declare const colors_yellow: typeof yellow; +declare namespace colors { + export { + colors_ColorFunction as ColorFunction, + colors_blue as blue, + colors_gray as gray, + colors_green as green, + colors_red as red, + colors_yellow as yellow, + }; +} + +type LogLevel = 'debug' | 'info' | 'success' | 'warning' | 'error'; +type LogColors = keyof typeof colors; +interface LogEntry { + timestamp: Date; + level: LogLevel; + message: any; +} +declare class Logger { + private readonly name; + private prefix; + constructor(name: string); + extend(domain: string): Logger; + /** + * Print a debug message. + * @example + * logger.debug('no duplicates found, creating a document...') + */ + debug(message: any, ...positionals: Array): void; + /** + * Print an info message. + * @example + * logger.info('start parsing...') + */ + info(message: any, ...positionals: Array): (message: any, ...positionals: Array) => void; + /** + * Print a success message. + * @example + * logger.success('successfully created document') + */ + success(message: any, ...positionals: Array): void; + /** + * Print a warning. + * @example + * logger.warning('found legacy document format') + */ + warning(message: any, ...positionals: Array): void; + /** + * Print an error message. + * @example + * logger.error('something went wrong') + */ + error(message: any, ...positionals: Array): void; + /** + * Execute the given callback only when the logging is enabled. + * This is skipped in its entirety and has no runtime cost otherwise. + * This executes regardless of the log level. + * @example + * logger.only(() => { + * logger.info('additional info') + * }) + */ + only(callback: () => void): void; + private createEntry; + private logEntry; + private formatTimestamp; + private getWriter; +} + +export { LogColors, LogEntry, LogLevel, Logger }; diff --git a/node_modules/@open-draft/logger/lib/index.js b/node_modules/@open-draft/logger/lib/index.js new file mode 100644 index 0000000000000000000000000000000000000000..ac101aec651bcc45a2cffffcb8e7242a649ce87b --- /dev/null +++ b/node_modules/@open-draft/logger/lib/index.js @@ -0,0 +1,295 @@ +var __defProp = Object.defineProperty; +var __getOwnPropDesc = Object.getOwnPropertyDescriptor; +var __getOwnPropNames = Object.getOwnPropertyNames; +var __hasOwnProp = Object.prototype.hasOwnProperty; +var __export = (target, all) => { + for (var name in all) + __defProp(target, name, { get: all[name], enumerable: true }); +}; +var __copyProps = (to, from, except, desc) => { + if (from && typeof from === "object" || typeof from === "function") { + for (let key of __getOwnPropNames(from)) + if (!__hasOwnProp.call(to, key) && key !== except) + __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); + } + return to; +}; +var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); + +// src/index.ts +var src_exports = {}; +__export(src_exports, { + Logger: () => Logger +}); +module.exports = __toCommonJS(src_exports); +var import_is_node_process = require("is-node-process"); +var import_outvariant = require("outvariant"); + +// src/colors.ts +var colors_exports = {}; +__export(colors_exports, { + blue: () => blue, + gray: () => gray, + green: () => green, + red: () => red, + yellow: () => yellow +}); +function yellow(text) { + return `\x1B[33m${text}\x1B[0m`; +} +function blue(text) { + return `\x1B[34m${text}\x1B[0m`; +} +function gray(text) { + return `\x1B[90m${text}\x1B[0m`; +} +function red(text) { + return `\x1B[31m${text}\x1B[0m`; +} +function green(text) { + return `\x1B[32m${text}\x1B[0m`; +} + +// src/index.ts +var IS_NODE = (0, import_is_node_process.isNodeProcess)(); +var Logger = class { + constructor(name) { + this.name = name; + this.prefix = `[${this.name}]`; + const LOGGER_NAME = getVariable("DEBUG"); + const LOGGER_LEVEL = getVariable("LOG_LEVEL"); + const isLoggingEnabled = LOGGER_NAME === "1" || LOGGER_NAME === "true" || typeof LOGGER_NAME !== "undefined" && this.name.startsWith(LOGGER_NAME); + if (isLoggingEnabled) { + this.debug = isDefinedAndNotEquals(LOGGER_LEVEL, "debug") ? noop : this.debug; + this.info = isDefinedAndNotEquals(LOGGER_LEVEL, "info") ? noop : this.info; + this.success = isDefinedAndNotEquals(LOGGER_LEVEL, "success") ? noop : this.success; + this.warning = isDefinedAndNotEquals(LOGGER_LEVEL, "warning") ? noop : this.warning; + this.error = isDefinedAndNotEquals(LOGGER_LEVEL, "error") ? noop : this.error; + } else { + this.info = noop; + this.success = noop; + this.warning = noop; + this.error = noop; + this.only = noop; + } + } + prefix; + extend(domain) { + return new Logger(`${this.name}:${domain}`); + } + /** + * Print a debug message. + * @example + * logger.debug('no duplicates found, creating a document...') + */ + debug(message, ...positionals) { + this.logEntry({ + level: "debug", + message: gray(message), + positionals, + prefix: this.prefix, + colors: { + prefix: "gray" + } + }); + } + /** + * Print an info message. + * @example + * logger.info('start parsing...') + */ + info(message, ...positionals) { + this.logEntry({ + level: "info", + message, + positionals, + prefix: this.prefix, + colors: { + prefix: "blue" + } + }); + const performance2 = new PerformanceEntry(); + return (message2, ...positionals2) => { + performance2.measure(); + this.logEntry({ + level: "info", + message: `${message2} ${gray(`${performance2.deltaTime}ms`)}`, + positionals: positionals2, + prefix: this.prefix, + colors: { + prefix: "blue" + } + }); + }; + } + /** + * Print a success message. + * @example + * logger.success('successfully created document') + */ + success(message, ...positionals) { + this.logEntry({ + level: "info", + message, + positionals, + prefix: `\u2714 ${this.prefix}`, + colors: { + timestamp: "green", + prefix: "green" + } + }); + } + /** + * Print a warning. + * @example + * logger.warning('found legacy document format') + */ + warning(message, ...positionals) { + this.logEntry({ + level: "warning", + message, + positionals, + prefix: `\u26A0 ${this.prefix}`, + colors: { + timestamp: "yellow", + prefix: "yellow" + } + }); + } + /** + * Print an error message. + * @example + * logger.error('something went wrong') + */ + error(message, ...positionals) { + this.logEntry({ + level: "error", + message, + positionals, + prefix: `\u2716 ${this.prefix}`, + colors: { + timestamp: "red", + prefix: "red" + } + }); + } + /** + * Execute the given callback only when the logging is enabled. + * This is skipped in its entirety and has no runtime cost otherwise. + * This executes regardless of the log level. + * @example + * logger.only(() => { + * logger.info('additional info') + * }) + */ + only(callback) { + callback(); + } + createEntry(level, message) { + return { + timestamp: /* @__PURE__ */ new Date(), + level, + message + }; + } + logEntry(args) { + const { + level, + message, + prefix, + colors: customColors, + positionals = [] + } = args; + const entry = this.createEntry(level, message); + const timestampColor = customColors?.timestamp || "gray"; + const prefixColor = customColors?.prefix || "gray"; + const colorize = { + timestamp: colors_exports[timestampColor], + prefix: colors_exports[prefixColor] + }; + const write = this.getWriter(level); + write( + [colorize.timestamp(this.formatTimestamp(entry.timestamp))].concat(prefix != null ? colorize.prefix(prefix) : []).concat(serializeInput(message)).join(" "), + ...positionals.map(serializeInput) + ); + } + formatTimestamp(timestamp) { + return `${timestamp.toLocaleTimeString( + "en-GB" + )}:${timestamp.getMilliseconds()}`; + } + getWriter(level) { + switch (level) { + case "debug": + case "success": + case "info": { + return log; + } + case "warning": { + return warn; + } + case "error": { + return error; + } + } + } +}; +var PerformanceEntry = class { + startTime; + endTime; + deltaTime; + constructor() { + this.startTime = performance.now(); + } + measure() { + this.endTime = performance.now(); + const deltaTime = this.endTime - this.startTime; + this.deltaTime = deltaTime.toFixed(2); + } +}; +var noop = () => void 0; +function log(message, ...positionals) { + if (IS_NODE) { + process.stdout.write((0, import_outvariant.format)(message, ...positionals) + "\n"); + return; + } + console.log(message, ...positionals); +} +function warn(message, ...positionals) { + if (IS_NODE) { + process.stderr.write((0, import_outvariant.format)(message, ...positionals) + "\n"); + return; + } + console.warn(message, ...positionals); +} +function error(message, ...positionals) { + if (IS_NODE) { + process.stderr.write((0, import_outvariant.format)(message, ...positionals) + "\n"); + return; + } + console.error(message, ...positionals); +} +function getVariable(variableName) { + if (IS_NODE) { + return process.env[variableName]; + } + return globalThis[variableName]?.toString(); +} +function isDefinedAndNotEquals(value, expected) { + return value !== void 0 && value !== expected; +} +function serializeInput(message) { + if (typeof message === "undefined") { + return "undefined"; + } + if (message === null) { + return "null"; + } + if (typeof message === "string") { + return message; + } + if (typeof message === "object") { + return JSON.stringify(message); + } + return message.toString(); +} diff --git a/node_modules/@open-draft/logger/lib/index.mjs b/node_modules/@open-draft/logger/lib/index.mjs new file mode 100644 index 0000000000000000000000000000000000000000..ffb0b88b7a0ccc22ed7cb106b3b48a10b085df0e --- /dev/null +++ b/node_modules/@open-draft/logger/lib/index.mjs @@ -0,0 +1,281 @@ +var __defProp = Object.defineProperty; +var __export = (target, all) => { + for (var name in all) + __defProp(target, name, { get: all[name], enumerable: true }); +}; + +// src/index.ts +import { isNodeProcess } from "is-node-process"; +import { format } from "outvariant"; + +// src/colors.ts +var colors_exports = {}; +__export(colors_exports, { + blue: () => blue, + gray: () => gray, + green: () => green, + red: () => red, + yellow: () => yellow +}); +function yellow(text) { + return `\x1B[33m${text}\x1B[0m`; +} +function blue(text) { + return `\x1B[34m${text}\x1B[0m`; +} +function gray(text) { + return `\x1B[90m${text}\x1B[0m`; +} +function red(text) { + return `\x1B[31m${text}\x1B[0m`; +} +function green(text) { + return `\x1B[32m${text}\x1B[0m`; +} + +// src/index.ts +var IS_NODE = isNodeProcess(); +var Logger = class { + constructor(name) { + this.name = name; + this.prefix = `[${this.name}]`; + const LOGGER_NAME = getVariable("DEBUG"); + const LOGGER_LEVEL = getVariable("LOG_LEVEL"); + const isLoggingEnabled = LOGGER_NAME === "1" || LOGGER_NAME === "true" || typeof LOGGER_NAME !== "undefined" && this.name.startsWith(LOGGER_NAME); + if (isLoggingEnabled) { + this.debug = isDefinedAndNotEquals(LOGGER_LEVEL, "debug") ? noop : this.debug; + this.info = isDefinedAndNotEquals(LOGGER_LEVEL, "info") ? noop : this.info; + this.success = isDefinedAndNotEquals(LOGGER_LEVEL, "success") ? noop : this.success; + this.warning = isDefinedAndNotEquals(LOGGER_LEVEL, "warning") ? noop : this.warning; + this.error = isDefinedAndNotEquals(LOGGER_LEVEL, "error") ? noop : this.error; + } else { + this.info = noop; + this.success = noop; + this.warning = noop; + this.error = noop; + this.only = noop; + } + } + prefix; + extend(domain) { + return new Logger(`${this.name}:${domain}`); + } + /** + * Print a debug message. + * @example + * logger.debug('no duplicates found, creating a document...') + */ + debug(message, ...positionals) { + this.logEntry({ + level: "debug", + message: gray(message), + positionals, + prefix: this.prefix, + colors: { + prefix: "gray" + } + }); + } + /** + * Print an info message. + * @example + * logger.info('start parsing...') + */ + info(message, ...positionals) { + this.logEntry({ + level: "info", + message, + positionals, + prefix: this.prefix, + colors: { + prefix: "blue" + } + }); + const performance2 = new PerformanceEntry(); + return (message2, ...positionals2) => { + performance2.measure(); + this.logEntry({ + level: "info", + message: `${message2} ${gray(`${performance2.deltaTime}ms`)}`, + positionals: positionals2, + prefix: this.prefix, + colors: { + prefix: "blue" + } + }); + }; + } + /** + * Print a success message. + * @example + * logger.success('successfully created document') + */ + success(message, ...positionals) { + this.logEntry({ + level: "info", + message, + positionals, + prefix: `\u2714 ${this.prefix}`, + colors: { + timestamp: "green", + prefix: "green" + } + }); + } + /** + * Print a warning. + * @example + * logger.warning('found legacy document format') + */ + warning(message, ...positionals) { + this.logEntry({ + level: "warning", + message, + positionals, + prefix: `\u26A0 ${this.prefix}`, + colors: { + timestamp: "yellow", + prefix: "yellow" + } + }); + } + /** + * Print an error message. + * @example + * logger.error('something went wrong') + */ + error(message, ...positionals) { + this.logEntry({ + level: "error", + message, + positionals, + prefix: `\u2716 ${this.prefix}`, + colors: { + timestamp: "red", + prefix: "red" + } + }); + } + /** + * Execute the given callback only when the logging is enabled. + * This is skipped in its entirety and has no runtime cost otherwise. + * This executes regardless of the log level. + * @example + * logger.only(() => { + * logger.info('additional info') + * }) + */ + only(callback) { + callback(); + } + createEntry(level, message) { + return { + timestamp: /* @__PURE__ */ new Date(), + level, + message + }; + } + logEntry(args) { + const { + level, + message, + prefix, + colors: customColors, + positionals = [] + } = args; + const entry = this.createEntry(level, message); + const timestampColor = customColors?.timestamp || "gray"; + const prefixColor = customColors?.prefix || "gray"; + const colorize = { + timestamp: colors_exports[timestampColor], + prefix: colors_exports[prefixColor] + }; + const write = this.getWriter(level); + write( + [colorize.timestamp(this.formatTimestamp(entry.timestamp))].concat(prefix != null ? colorize.prefix(prefix) : []).concat(serializeInput(message)).join(" "), + ...positionals.map(serializeInput) + ); + } + formatTimestamp(timestamp) { + return `${timestamp.toLocaleTimeString( + "en-GB" + )}:${timestamp.getMilliseconds()}`; + } + getWriter(level) { + switch (level) { + case "debug": + case "success": + case "info": { + return log; + } + case "warning": { + return warn; + } + case "error": { + return error; + } + } + } +}; +var PerformanceEntry = class { + startTime; + endTime; + deltaTime; + constructor() { + this.startTime = performance.now(); + } + measure() { + this.endTime = performance.now(); + const deltaTime = this.endTime - this.startTime; + this.deltaTime = deltaTime.toFixed(2); + } +}; +var noop = () => void 0; +function log(message, ...positionals) { + if (IS_NODE) { + process.stdout.write(format(message, ...positionals) + "\n"); + return; + } + console.log(message, ...positionals); +} +function warn(message, ...positionals) { + if (IS_NODE) { + process.stderr.write(format(message, ...positionals) + "\n"); + return; + } + console.warn(message, ...positionals); +} +function error(message, ...positionals) { + if (IS_NODE) { + process.stderr.write(format(message, ...positionals) + "\n"); + return; + } + console.error(message, ...positionals); +} +function getVariable(variableName) { + if (IS_NODE) { + return process.env[variableName]; + } + return globalThis[variableName]?.toString(); +} +function isDefinedAndNotEquals(value, expected) { + return value !== void 0 && value !== expected; +} +function serializeInput(message) { + if (typeof message === "undefined") { + return "undefined"; + } + if (message === null) { + return "null"; + } + if (typeof message === "string") { + return message; + } + if (typeof message === "object") { + return JSON.stringify(message); + } + return message.toString(); +} +export { + Logger +}; diff --git a/node_modules/@open-draft/logger/package.json b/node_modules/@open-draft/logger/package.json new file mode 100644 index 0000000000000000000000000000000000000000..796aafc8d7bb912f571bf41ce39fcd8656cb62c9 --- /dev/null +++ b/node_modules/@open-draft/logger/package.json @@ -0,0 +1,56 @@ +{ + "name": "@open-draft/logger", + "version": "0.3.0", + "description": "Environment-agnostic, ESM-friendly logger for simple needs.", + "main": "./lib/index.js", + "module": "./lib/index.mjs", + "types": "./lib/index.d.ts", + "exports": { + ".": { + "types": "./lib/index.d.ts", + "require": "./lib/index.js", + "import": "./lib/index.mjs", + "default": "./lib/index.js" + }, + "./package.json": "./package.json" + }, + "keywords": [ + "log", + "logger", + "logging", + "universal", + "tiny" + ], + "files": [ + "lib", + "LICENSE", + "README.md" + ], + "author": "Artem Zakharchenko", + "license": "MIT", + "repository": { + "type": "git", + "url": "https://github.com/open-draft/logger" + }, + "devDependencies": { + "@ossjs/release": "^0.5.1", + "@playwright/test": "^1.32.3", + "@types/node": "^18.15.11", + "playwright": "^1.32.3", + "tsup": "^6.7.0", + "typescript": "^5.0.3", + "vitest": "^0.29.8", + "webpack-http-server": "^0.5.0" + }, + "dependencies": { + "is-node-process": "^1.2.0", + "outvariant": "^1.4.0" + }, + "scripts": { + "build": "tsup", + "test": "pnpm test:node && pnpm test:browser", + "test:node": "vitest run", + "test:browser": "playwright test", + "release": "release publish" + } +} \ No newline at end of file diff --git a/node_modules/@open-draft/until/LICENSE b/node_modules/@open-draft/until/LICENSE new file mode 100644 index 0000000000000000000000000000000000000000..8a1c628e5112fbb284d8e1cd9988c44d6599ddd5 --- /dev/null +++ b/node_modules/@open-draft/until/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2021 Artem Zakharchenko + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/node_modules/@open-draft/until/README.md b/node_modules/@open-draft/until/README.md new file mode 100644 index 0000000000000000000000000000000000000000..be49a5049f72c28529ce0bb6c8d48080b067ca9a --- /dev/null +++ b/node_modules/@open-draft/until/README.md @@ -0,0 +1,150 @@ +[![Latest release](https://img.shields.io/npm/v/@open-draft/until.svg)](https://www.npmjs.com/package/@open-draft/until) + +# `until` + +Gracefully handle a Promise using `async`/`await`. + +## Why? + +With the addition of `async`/`await` keywords in ECMAScript 2017 the handling of Promises became much easier. However, one must keep in mind that the `await` keyword provides no standard error handling API. Consider this usage: + +```js +function getUser(id) { + const data = await fetchUser(id) + // Work with "data"... +} +``` + +In case `fetchUser()` throws an error, the entire `getUser()` function's scope will terminate. Because of this, it's recommended to implement error handling using `try`/`catch` block wrapping `await` expressions: + +```js +function getUser(id) + let data = null + + try { + data = await asyncAction() + } catch (error) { + console.error(error) + } + + // Work with "data"... +} +``` + +While this is a semantically valid approach, constructing `try`/`catch` around each awaited operation may be tedious and get overlooked at times. Such error handling also introduces separate closures for execution and error scenarios of an asynchronous operation. + +This library encapsulates the `try`/`catch` error handling in a utility function that does not create a separate closure and exposes a NodeJS-friendly API to work with errors and resolved data. + +## Getting started + +### Install + +```bash +npm install @open-draft/until +``` + +### Usage + +```js +import { until } from '@open-draft/until' + +async function(id) { + const { error, data } = await until(() => fetchUser(id)) + + if (error) { + return handleError(error) + } + + return data +} +``` + +### Usage with TypeScript + +```ts +import { until } from '@open-draft/until' + +interface User { + firstName: string + age: number +} + +interface UserFetchError { + type: 'FORBIDDEN' | 'NOT_FOUND' + message?: string +} + +async function(id: string) { + const { error, data } = await until(() => fetchUser(id)) + + if (error) { + handleError(error.type, error.message) + } + + return data.firstName +} +``` + +## Frequently asked questions + +### Why does `until` accept a function and not a `Promise` directly? + +This has been intentionally introduced to await a single logical unit as opposed to a single `Promise`. + +```js +// Notice how a single "until" invocation can handle +// a rather complex piece of logic. This way any rejections +// or exceptions happening within the given function +// can be handled via the same "error". +const { error, data } = until(async () => { + const user = await fetchUser() + const nextUser = normalizeUser(user) + const transaction = await saveModel('user', user) + + invariant(transaction.status === 'OK', 'Saving user failed') + + return transaction.result +}) + +if (error) { + // Handle any exceptions happened within the function. +} +``` + +### Why does `until` return an object and not an array? + +The `until` function used to return an array of shape `[error, data]` prior to `2.0.0`. That has been changed, however, to get proper type-safety using discriminated union type. + +Compare these two examples: + +```ts +const [error, data] = await until(() => action()) + +if (error) { + return null +} + +// Data still has ambiguous "DataType | null" type here +// even after you've checked and handled the "error" above. +console.log(data) +``` + +```ts +const result = await until(() => action()) + +// At this point, "data" is ambiguous "DataType | null" +// which is correct, as you haven't checked nor handled the "error". + +if (result.error) { + return null +} + +// Data is strict "DataType" since you've handled the "error" above. +console.log(result.data) +``` + +> It's crucial to keep the entire result of the `Promise` in a single variable and not destructure it. TypeScript will always keep the type of `error` and `data` as it was upon destructuring, ignoring any type guards you may perform later on. + +## Special thanks + +- [giuseppegurgone](https://twitter.com/giuseppegurgone) for the discussion about the original `until` API. diff --git a/node_modules/@open-draft/until/lib/index.d.ts b/node_modules/@open-draft/until/lib/index.d.ts new file mode 100644 index 0000000000000000000000000000000000000000..19544f40af2d8200543b3de66a7440515b412fcf --- /dev/null +++ b/node_modules/@open-draft/until/lib/index.d.ts @@ -0,0 +1,15 @@ +type AsyncTuple = { + error: ErrorType; + data: null; +} | { + error: null; + data: DataType; +}; +/** + * Gracefully handles a given Promise factory. + * @example + * const { error, data } = await until(() => asyncAction()) + */ +declare const until: (promise: () => Promise) => Promise>; + +export { until }; diff --git a/node_modules/@open-draft/until/lib/index.js b/node_modules/@open-draft/until/lib/index.js new file mode 100644 index 0000000000000000000000000000000000000000..3944d95acf437053955fb9693ab1c5a1846e547f --- /dev/null +++ b/node_modules/@open-draft/until/lib/index.js @@ -0,0 +1,41 @@ +var __defProp = Object.defineProperty; +var __getOwnPropDesc = Object.getOwnPropertyDescriptor; +var __getOwnPropNames = Object.getOwnPropertyNames; +var __hasOwnProp = Object.prototype.hasOwnProperty; +var __export = (target, all) => { + for (var name in all) + __defProp(target, name, { get: all[name], enumerable: true }); +}; +var __copyProps = (to, from, except, desc) => { + if (from && typeof from === "object" || typeof from === "function") { + for (let key of __getOwnPropNames(from)) + if (!__hasOwnProp.call(to, key) && key !== except) + __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); + } + return to; +}; +var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); + +// src/index.ts +var src_exports = {}; +__export(src_exports, { + until: () => until +}); +module.exports = __toCommonJS(src_exports); + +// src/until.ts +var until = async (promise) => { + try { + const data = await promise().catch((error) => { + throw error; + }); + return { error: null, data }; + } catch (error) { + return { error, data: null }; + } +}; +// Annotate the CommonJS export names for ESM import in node: +0 && (module.exports = { + until +}); +//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/node_modules/@open-draft/until/lib/index.js.map b/node_modules/@open-draft/until/lib/index.js.map new file mode 100644 index 0000000000000000000000000000000000000000..71429109f0c6a5f3b4d9ec7cc23e46daa40d58cc --- /dev/null +++ b/node_modules/@open-draft/until/lib/index.js.map @@ -0,0 +1 @@ +{"version":3,"sources":["../src/index.ts","../src/until.ts"],"sourcesContent":["export { until } from './until'","export type AsyncTuple<\n ErrorType extends any = Error,\n DataType extends any = unknown,\n> =\n | {\n error: ErrorType\n data: null\n }\n | { error: null; data: DataType }\n\n/**\n * Gracefully handles a given Promise factory.\n * @example\n * const { error, data } = await until(() => asyncAction())\n */\nexport const until = async <\n ErrorType extends any = Error,\n DataType extends any = unknown,\n>(\n promise: () => Promise,\n): Promise> => {\n try {\n const data = await promise().catch((error) => {\n throw error\n })\n return { error: null, data }\n } catch (error) {\n return { error, data: null }\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACeO,IAAM,QAAQ,OAInB,YAC6C;AAC7C,MAAI;AACF,UAAM,OAAO,MAAM,QAAQ,EAAE,MAAM,CAAC,UAAU;AAC5C,YAAM;AAAA,IACR,CAAC;AACD,WAAO,EAAE,OAAO,MAAM,KAAK;AAAA,EAC7B,SAAS,OAAP;AACA,WAAO,EAAE,OAAO,MAAM,KAAK;AAAA,EAC7B;AACF;","names":[]} \ No newline at end of file diff --git a/node_modules/@open-draft/until/lib/index.mjs b/node_modules/@open-draft/until/lib/index.mjs new file mode 100644 index 0000000000000000000000000000000000000000..12be84c8d15c8e5850d2b16a5f8cc26e69731a30 --- /dev/null +++ b/node_modules/@open-draft/until/lib/index.mjs @@ -0,0 +1,15 @@ +// src/until.ts +var until = async (promise) => { + try { + const data = await promise().catch((error) => { + throw error; + }); + return { error: null, data }; + } catch (error) { + return { error, data: null }; + } +}; +export { + until +}; +//# sourceMappingURL=index.mjs.map \ No newline at end of file diff --git a/node_modules/@open-draft/until/lib/index.mjs.map b/node_modules/@open-draft/until/lib/index.mjs.map new file mode 100644 index 0000000000000000000000000000000000000000..6c246974fcda2bf89d775d88ecc5ddbd27706f4d --- /dev/null +++ b/node_modules/@open-draft/until/lib/index.mjs.map @@ -0,0 +1 @@ +{"version":3,"sources":["../src/until.ts"],"sourcesContent":["export type AsyncTuple<\n ErrorType extends any = Error,\n DataType extends any = unknown,\n> =\n | {\n error: ErrorType\n data: null\n }\n | { error: null; data: DataType }\n\n/**\n * Gracefully handles a given Promise factory.\n * @example\n * const { error, data } = await until(() => asyncAction())\n */\nexport const until = async <\n ErrorType extends any = Error,\n DataType extends any = unknown,\n>(\n promise: () => Promise,\n): Promise> => {\n try {\n const data = await promise().catch((error) => {\n throw error\n })\n return { error: null, data }\n } catch (error) {\n return { error, data: null }\n }\n}\n"],"mappings":";AAeO,IAAM,QAAQ,OAInB,YAC6C;AAC7C,MAAI;AACF,UAAM,OAAO,MAAM,QAAQ,EAAE,MAAM,CAAC,UAAU;AAC5C,YAAM;AAAA,IACR,CAAC;AACD,WAAO,EAAE,OAAO,MAAM,KAAK;AAAA,EAC7B,SAAS,OAAP;AACA,WAAO,EAAE,OAAO,MAAM,KAAK;AAAA,EAC7B;AACF;","names":[]} \ No newline at end of file diff --git a/node_modules/@open-draft/until/package.json b/node_modules/@open-draft/until/package.json new file mode 100644 index 0000000000000000000000000000000000000000..a640d6031c60ddbfedea90b5729d498fd37bb873 --- /dev/null +++ b/node_modules/@open-draft/until/package.json @@ -0,0 +1,37 @@ +{ + "name": "@open-draft/until", + "version": "2.1.0", + "description": "Gracefully handle a Promise using async/await.", + "main": "./lib/index.js", + "module": "./lib/index.mjs", + "types": "./lib/index.d.ts", + "exports": { + ".": { + "types": "./lib/index.d.ts", + "require": "./lib/index.js", + "import": "./lib/index.mjs", + "default": "./lib/index.mjs" + } + }, + "repository": "open-draft/until", + "author": "Artem Zakharchenko ", + "license": "MIT", + "files": [ + "README.md", + "lib" + ], + "devDependencies": { + "@ossjs/release": "^0.5.1", + "@types/jest": "^26.0.22", + "jest": "^26.6.3", + "ts-jest": "^26.5.4", + "tsup": "^6.2.3", + "typescript": "^4.2.4" + }, + "scripts": { + "start": "tsc -w", + "test": "jest", + "build": "tsup", + "release": "release publish" + } +} \ No newline at end of file diff --git a/node_modules/@types/cookie/LICENSE b/node_modules/@types/cookie/LICENSE new file mode 100644 index 0000000000000000000000000000000000000000..9e841e7a26e4eb057b24511e7b92d42b257a80e5 --- /dev/null +++ b/node_modules/@types/cookie/LICENSE @@ -0,0 +1,21 @@ + MIT License + + Copyright (c) Microsoft Corporation. + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE diff --git a/node_modules/@types/cookie/README.md b/node_modules/@types/cookie/README.md new file mode 100644 index 0000000000000000000000000000000000000000..d2811ae8533c36ead77fa781bc99657ffb70c064 --- /dev/null +++ b/node_modules/@types/cookie/README.md @@ -0,0 +1,15 @@ +# Installation +> `npm install --save @types/cookie` + +# Summary +This package contains type definitions for cookie (https://github.com/jshttp/cookie). + +# Details +Files were exported from https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/cookie. + +### Additional Details + * Last updated: Sun, 26 Nov 2023 22:07:01 GMT + * Dependencies: none + +# Credits +These definitions were written by [Pine Mizune](https://github.com/pine), and [Piotr Błażejewicz](https://github.com/peterblazejewicz). diff --git a/node_modules/@types/cookie/index.d.ts b/node_modules/@types/cookie/index.d.ts new file mode 100644 index 0000000000000000000000000000000000000000..4800c73c6f6e66c3f00fc7f1c75203d1b7107156 --- /dev/null +++ b/node_modules/@types/cookie/index.d.ts @@ -0,0 +1,154 @@ +/** + * Basic HTTP cookie parser and serializer for HTTP servers. + */ + +/** + * Additional serialization options + */ +export interface CookieSerializeOptions { + /** + * Specifies the value for the {@link https://tools.ietf.org/html/rfc6265#section-5.2.3|Domain Set-Cookie attribute}. By default, no + * domain is set, and most clients will consider the cookie to apply to only + * the current domain. + */ + domain?: string | undefined; + + /** + * Specifies a function that will be used to encode a cookie's value. Since + * value of a cookie has a limited character set (and must be a simple + * string), this function can be used to encode a value into a string suited + * for a cookie's value. + * + * The default function is the global `encodeURIComponent`, which will + * encode a JavaScript string into UTF-8 byte sequences and then URL-encode + * any that fall outside of the cookie range. + */ + encode?(value: string): string; + + /** + * Specifies the `Date` object to be the value for the {@link https://tools.ietf.org/html/rfc6265#section-5.2.1|`Expires` `Set-Cookie` attribute}. By default, + * no expiration is set, and most clients will consider this a "non-persistent cookie" and will delete + * it on a condition like exiting a web browser application. + * + * *Note* the {@link https://tools.ietf.org/html/rfc6265#section-5.3|cookie storage model specification} + * states that if both `expires` and `maxAge` are set, then `maxAge` takes precedence, but it is + * possible not all clients by obey this, so if both are set, they should + * point to the same date and time. + */ + expires?: Date | undefined; + /** + * Specifies the boolean value for the {@link https://tools.ietf.org/html/rfc6265#section-5.2.6|`HttpOnly` `Set-Cookie` attribute}. + * When truthy, the `HttpOnly` attribute is set, otherwise it is not. By + * default, the `HttpOnly` attribute is not set. + * + * *Note* be careful when setting this to true, as compliant clients will + * not allow client-side JavaScript to see the cookie in `document.cookie`. + */ + httpOnly?: boolean | undefined; + /** + * Specifies the number (in seconds) to be the value for the `Max-Age` + * `Set-Cookie` attribute. The given number will be converted to an integer + * by rounding down. By default, no maximum age is set. + * + * *Note* the {@link https://tools.ietf.org/html/rfc6265#section-5.3|cookie storage model specification} + * states that if both `expires` and `maxAge` are set, then `maxAge` takes precedence, but it is + * possible not all clients by obey this, so if both are set, they should + * point to the same date and time. + */ + maxAge?: number | undefined; + /** + * Specifies the `boolean` value for the [`Partitioned` `Set-Cookie`](rfc-cutler-httpbis-partitioned-cookies) + * attribute. When truthy, the `Partitioned` attribute is set, otherwise it is not. By default, the + * `Partitioned` attribute is not set. + * + * **note** This is an attribute that has not yet been fully standardized, and may change in the future. + * This also means many clients may ignore this attribute until they understand it. + * + * More information about can be found in [the proposal](https://github.com/privacycg/CHIPS) + */ + partitioned?: boolean | undefined; + /** + * Specifies the value for the {@link https://tools.ietf.org/html/rfc6265#section-5.2.4|`Path` `Set-Cookie` attribute}. + * By default, the path is considered the "default path". + */ + path?: string | undefined; + /** + * Specifies the `string` to be the value for the [`Priority` `Set-Cookie` attribute][rfc-west-cookie-priority-00-4.1]. + * + * - `'low'` will set the `Priority` attribute to `Low`. + * - `'medium'` will set the `Priority` attribute to `Medium`, the default priority when not set. + * - `'high'` will set the `Priority` attribute to `High`. + * + * More information about the different priority levels can be found in + * [the specification][rfc-west-cookie-priority-00-4.1]. + * + * **note** This is an attribute that has not yet been fully standardized, and may change in the future. + * This also means many clients may ignore this attribute until they understand it. + */ + priority?: "low" | "medium" | "high" | undefined; + /** + * Specifies the boolean or string to be the value for the {@link https://tools.ietf.org/html/draft-ietf-httpbis-rfc6265bis-03#section-4.1.2.7|`SameSite` `Set-Cookie` attribute}. + * + * - `true` will set the `SameSite` attribute to `Strict` for strict same + * site enforcement. + * - `false` will not set the `SameSite` attribute. + * - `'lax'` will set the `SameSite` attribute to Lax for lax same site + * enforcement. + * - `'strict'` will set the `SameSite` attribute to Strict for strict same + * site enforcement. + * - `'none'` will set the SameSite attribute to None for an explicit + * cross-site cookie. + * + * More information about the different enforcement levels can be found in {@link https://tools.ietf.org/html/draft-ietf-httpbis-rfc6265bis-03#section-4.1.2.7|the specification}. + * + * *note* This is an attribute that has not yet been fully standardized, and may change in the future. This also means many clients may ignore this attribute until they understand it. + */ + sameSite?: true | false | "lax" | "strict" | "none" | undefined; + /** + * Specifies the boolean value for the {@link https://tools.ietf.org/html/rfc6265#section-5.2.5|`Secure` `Set-Cookie` attribute}. When truthy, the + * `Secure` attribute is set, otherwise it is not. By default, the `Secure` attribute is not set. + * + * *Note* be careful when setting this to `true`, as compliant clients will + * not send the cookie back to the server in the future if the browser does + * not have an HTTPS connection. + */ + secure?: boolean | undefined; +} + +/** + * Additional parsing options + */ +export interface CookieParseOptions { + /** + * Specifies a function that will be used to decode a cookie's value. Since + * the value of a cookie has a limited character set (and must be a simple + * string), this function can be used to decode a previously-encoded cookie + * value into a JavaScript string or other object. + * + * The default function is the global `decodeURIComponent`, which will decode + * any URL-encoded sequences into their byte representations. + * + * *Note* if an error is thrown from this function, the original, non-decoded + * cookie value will be returned as the cookie's value. + */ + decode?(value: string): string; +} + +/** + * Parse an HTTP Cookie header string and returning an object of all cookie + * name-value pairs. + * + * @param str the string representing a `Cookie` header value + * @param [options] object containing parsing options + */ +export function parse(str: string, options?: CookieParseOptions): Record; + +/** + * Serialize a cookie name-value pair into a `Set-Cookie` header string. + * + * @param name the name for the cookie + * @param value value to set the cookie to + * @param [options] object containing serialization options + * @throws {TypeError} when `maxAge` options is invalid + */ +export function serialize(name: string, value: string, options?: CookieSerializeOptions): string; diff --git a/node_modules/@types/cookie/package.json b/node_modules/@types/cookie/package.json new file mode 100644 index 0000000000000000000000000000000000000000..683b1e51683e6f57983299ce03e9a2564a96abeb --- /dev/null +++ b/node_modules/@types/cookie/package.json @@ -0,0 +1,30 @@ +{ + "name": "@types/cookie", + "version": "0.6.0", + "description": "TypeScript definitions for cookie", + "homepage": "https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/cookie", + "license": "MIT", + "contributors": [ + { + "name": "Pine Mizune", + "githubUsername": "pine", + "url": "https://github.com/pine" + }, + { + "name": "Piotr Błażejewicz", + "githubUsername": "peterblazejewicz", + "url": "https://github.com/peterblazejewicz" + } + ], + "main": "", + "types": "index.d.ts", + "repository": { + "type": "git", + "url": "https://github.com/DefinitelyTyped/DefinitelyTyped.git", + "directory": "types/cookie" + }, + "scripts": {}, + "dependencies": {}, + "typesPublisherContentHash": "0fbdf9c886fb40c8dc7677b8b7d0f9e02ac5235e163d90244a4fb9004736a575", + "typeScriptVersion": "4.5" +} \ No newline at end of file diff --git a/node_modules/@types/eventsource/LICENSE b/node_modules/@types/eventsource/LICENSE new file mode 100644 index 0000000000000000000000000000000000000000..9e841e7a26e4eb057b24511e7b92d42b257a80e5 --- /dev/null +++ b/node_modules/@types/eventsource/LICENSE @@ -0,0 +1,21 @@ + MIT License + + Copyright (c) Microsoft Corporation. + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE diff --git a/node_modules/@types/eventsource/README.md b/node_modules/@types/eventsource/README.md new file mode 100644 index 0000000000000000000000000000000000000000..10fa78f8a7454691e8f36a64661cbcab2082b489 --- /dev/null +++ b/node_modules/@types/eventsource/README.md @@ -0,0 +1,15 @@ +# Installation +> `npm install --save @types/eventsource` + +# Summary +This package contains type definitions for eventsource (https://github.com/EventSource/eventsource). + +# Details +Files were exported from https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/eventsource. + +### Additional Details + * Last updated: Mon, 06 Nov 2023 22:41:05 GMT + * Dependencies: none + +# Credits +These definitions were written by [Scott Lee Davis](https://github.com/scottleedavis), [Ali Afroozeh](https://github.com/afroozeh), [Pedro Gámez](https://github.com/snakedrak), and [Akuukis](https://github.com/Akuukis). diff --git a/node_modules/@types/eventsource/dom-monkeypatch.d.ts b/node_modules/@types/eventsource/dom-monkeypatch.d.ts new file mode 100644 index 0000000000000000000000000000000000000000..27df09e8638944ba0c74d37c3efff9628b5916d3 --- /dev/null +++ b/node_modules/@types/eventsource/dom-monkeypatch.d.ts @@ -0,0 +1,92 @@ +/** + * The Event interface represents any event which takes place in the DOM; some are user-generated (such as mouse or keyboard events), while others are generated by APIs (such as + * events that indicate an animation has finished running, a video has been paused, and so forth). While events are usually triggered by such "external" sources, they can also be + * triggered programmatically, such as by calling the HTMLElement.click() method of an element, or by defining the event, then sending it to a specified target using + * EventTarget.dispatchEvent(). There are many types of events, some of which use other interfaces based on the main Event interface. Event itself contains the properties and + * methods which are common to all events. + */ +interface Event { + /** + * Returns true or false depending on how event was initialized. True if event goes through its target's ancestors in reverse tree order, and false otherwise. + */ + readonly bubbles: boolean; + cancelBubble: boolean; + readonly cancelable: boolean; + /** + * Returns true or false depending on how event was initialized. True if event invokes listeners past a ShadowRoot node that is the root of its target, and false otherwise. + */ + readonly composed: boolean; + readonly defaultPrevented: boolean; + readonly eventPhase: number; + /** + * Returns true if event was dispatched by the user agent, and + * false otherwise. + */ + readonly isTrusted: boolean; + returnValue: boolean; + /** + * Returns the event's timestamp as the number of milliseconds measured relative to + * the time origin. + */ + readonly timeStamp: number; + /** + * Unauthorized and redirect error status codes (for example 401, 403, 301, 307) + */ + readonly status?: number | undefined; + /** + * Returns the type of event, e.g. + * "click", "hashchange", or + * "submit". + */ + readonly type: string; + readonly AT_TARGET: 2; + readonly BUBBLING_PHASE: 3; + readonly CAPTURING_PHASE: 1; + readonly NONE: 0; + composedPath(): any[]; + initEvent(type: string, bubbles?: boolean, cancelable?: boolean): void; + preventDefault(): void; + /** + * Invoking this method prevents event from reaching + * any registered event listeners after the current one finishes running and, when dispatched in a tree, also prevents event from reaching any + * other objects. + */ + stopImmediatePropagation(): void; + /** + * When dispatched in a tree, invoking this method prevents event from reaching any objects other than the current object. + */ + stopPropagation(): void; +} + +interface EventInit { + bubbles?: boolean | undefined; + cancelable?: boolean | undefined; + composed?: boolean | undefined; +} + +interface MessageEventInit extends EventInit { + data?: T | undefined; + lastEventId?: string | undefined; + origin?: string | undefined; +} + +/** The MessageEvent interface represents a message received by a target object. */ +interface MessageEvent extends Event { + /** + * Returns the data of the message. + */ + readonly data: T; + /** + * Returns the last event ID string, for server-sent events. + */ + readonly lastEventId: string; + /** + * Returns the origin of the message, for server-sent events and + * cross-document messaging. + */ + readonly origin: string; +} +declare var MessageEvent: { + prototype: MessageEvent; + new(type: string, eventInitDict?: MessageEventInit): MessageEvent; +}; diff --git a/node_modules/@types/eventsource/index.d.ts b/node_modules/@types/eventsource/index.d.ts new file mode 100644 index 0000000000000000000000000000000000000000..1ab7bee2989fd6b4e3db9e20cc5c1e6ed6bd52e3 --- /dev/null +++ b/node_modules/@types/eventsource/index.d.ts @@ -0,0 +1,45 @@ +// eventsource uses DOM dependencies which are absent in a browserless environment like node.js. +// to avoid compiler errors this monkey patch is used. See more details in: +// - sinon: https://github.com/DefinitelyTyped/DefinitelyTyped/issues/11351 +// - rxjs: https://github.com/ReactiveX/rxjs/issues/1986 +/// + +declare class EventSource { + static readonly CLOSED: number; + static readonly CONNECTING: number; + static readonly OPEN: number; + + constructor(url: string, eventSourceInitDict?: EventSource.EventSourceInitDict); + + readonly CLOSED: number; + readonly CONNECTING: number; + readonly OPEN: number; + readonly url: string; + readonly readyState: number; + readonly withCredentials: boolean; + onopen: (evt: MessageEvent) => any; + onmessage: (evt: MessageEvent) => any; + onerror: (evt: MessageEvent) => any; + addEventListener(type: string, listener: (evt: MessageEvent) => void): void; + dispatchEvent(evt: Event): boolean; + removeEventListener(type: string, listener: (evt: MessageEvent) => void): void; + close(): void; +} + +declare namespace EventSource { + enum ReadyState { + CONNECTING = 0, + OPEN = 1, + CLOSED = 2, + } + + interface EventSourceInitDict { + withCredentials?: boolean | undefined; + headers?: object | undefined; + proxy?: string | undefined; + https?: object | undefined; + rejectUnauthorized?: boolean | undefined; + } +} + +export = EventSource; diff --git a/node_modules/@types/eventsource/lib/eventsource-polyfill/index.d.ts b/node_modules/@types/eventsource/lib/eventsource-polyfill/index.d.ts new file mode 100644 index 0000000000000000000000000000000000000000..663e82f0ad7b709589d22e042a167101f66e3379 --- /dev/null +++ b/node_modules/@types/eventsource/lib/eventsource-polyfill/index.d.ts @@ -0,0 +1,2 @@ +import * as EventSource from "../../index"; +export = EventSource; diff --git a/node_modules/@types/eventsource/package.json b/node_modules/@types/eventsource/package.json new file mode 100644 index 0000000000000000000000000000000000000000..ae6cba197a5397cc68446439100440d7aa0a68d6 --- /dev/null +++ b/node_modules/@types/eventsource/package.json @@ -0,0 +1,40 @@ +{ + "name": "@types/eventsource", + "version": "1.1.15", + "description": "TypeScript definitions for eventsource", + "homepage": "https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/eventsource", + "license": "MIT", + "contributors": [ + { + "name": "Scott Lee Davis", + "githubUsername": "scottleedavis", + "url": "https://github.com/scottleedavis" + }, + { + "name": "Ali Afroozeh", + "githubUsername": "afroozeh", + "url": "https://github.com/afroozeh" + }, + { + "name": "Pedro Gámez", + "githubUsername": "snakedrak", + "url": "https://github.com/snakedrak" + }, + { + "name": "Akuukis", + "githubUsername": "Akuukis", + "url": "https://github.com/Akuukis" + } + ], + "main": "", + "types": "index.d.ts", + "repository": { + "type": "git", + "url": "https://github.com/DefinitelyTyped/DefinitelyTyped.git", + "directory": "types/eventsource" + }, + "scripts": {}, + "dependencies": {}, + "typesPublisherContentHash": "6a075ca22dc3b8841f58d5e2e758b840c8e2e48ae90c56c69f07cb5694d4a112", + "typeScriptVersion": "5.0" +} \ No newline at end of file diff --git a/node_modules/@types/statuses/LICENSE b/node_modules/@types/statuses/LICENSE new file mode 100644 index 0000000000000000000000000000000000000000..9e841e7a26e4eb057b24511e7b92d42b257a80e5 --- /dev/null +++ b/node_modules/@types/statuses/LICENSE @@ -0,0 +1,21 @@ + MIT License + + Copyright (c) Microsoft Corporation. + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE diff --git a/node_modules/@types/statuses/README.md b/node_modules/@types/statuses/README.md new file mode 100644 index 0000000000000000000000000000000000000000..26fc167d93896a7cb4f01f0af43d89548c64468e --- /dev/null +++ b/node_modules/@types/statuses/README.md @@ -0,0 +1,47 @@ +# Installation +> `npm install --save @types/statuses` + +# Summary +This package contains type definitions for statuses (https://github.com/jshttp/statuses). + +# Details +Files were exported from https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/statuses. +## [index.d.ts](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/statuses/index.d.ts) +````ts +type NumericAscii = "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" | "0"; +type NonNumericAscii = S extends `${NumericAscii}` ? never : any; + +type IsNumericString = S extends `${number}` ? any : never; + +type IsNonNumericString = S extends `${NonNumericAscii}${infer _}` ? any : never; + +export = status; + +declare const status: status; + +interface status { + (code: number): string; + (code: S): status.Result; + + codes: number[]; + code: { [msg: string]: number | undefined }; + empty: { [code: number]: boolean | undefined }; + message: { [code: number]: string | undefined }; + redirect: { [code: number]: boolean | undefined }; + retry: { [code: number]: boolean | undefined }; +} + +declare namespace status { + type Result = S extends IsNumericString ? string + : S extends IsNonNumericString ? number + : string | number; +} + +```` + +### Additional Details + * Last updated: Fri, 08 Mar 2024 17:07:21 GMT + * Dependencies: none + +# Credits +These definitions were written by [Tanguy Krotoff](https://github.com/tkrotoff), and [BendingBender](https://github.com/BendingBender). diff --git a/node_modules/@types/statuses/index.d.ts b/node_modules/@types/statuses/index.d.ts new file mode 100644 index 0000000000000000000000000000000000000000..e9ab3420492e1e47cc2bc57126f29f75e3d02eb7 --- /dev/null +++ b/node_modules/@types/statuses/index.d.ts @@ -0,0 +1,28 @@ +type NumericAscii = "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" | "0"; +type NonNumericAscii = S extends `${NumericAscii}` ? never : any; + +type IsNumericString = S extends `${number}` ? any : never; + +type IsNonNumericString = S extends `${NonNumericAscii}${infer _}` ? any : never; + +export = status; + +declare const status: status; + +interface status { + (code: number): string; + (code: S): status.Result; + + codes: number[]; + code: { [msg: string]: number | undefined }; + empty: { [code: number]: boolean | undefined }; + message: { [code: number]: string | undefined }; + redirect: { [code: number]: boolean | undefined }; + retry: { [code: number]: boolean | undefined }; +} + +declare namespace status { + type Result = S extends IsNumericString ? string + : S extends IsNonNumericString ? number + : string | number; +} diff --git a/node_modules/@types/statuses/package.json b/node_modules/@types/statuses/package.json new file mode 100644 index 0000000000000000000000000000000000000000..7a5a952184b3089c3aec036418540c4a88954617 --- /dev/null +++ b/node_modules/@types/statuses/package.json @@ -0,0 +1,30 @@ +{ + "name": "@types/statuses", + "version": "2.0.5", + "description": "TypeScript definitions for statuses", + "homepage": "https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/statuses", + "license": "MIT", + "contributors": [ + { + "name": "Tanguy Krotoff", + "githubUsername": "tkrotoff", + "url": "https://github.com/tkrotoff" + }, + { + "name": "BendingBender", + "githubUsername": "BendingBender", + "url": "https://github.com/BendingBender" + } + ], + "main": "", + "types": "index.d.ts", + "repository": { + "type": "git", + "url": "https://github.com/DefinitelyTyped/DefinitelyTyped.git", + "directory": "types/statuses" + }, + "scripts": {}, + "dependencies": {}, + "typesPublisherContentHash": "8a0c26e2e94734df65ca7e12ba7c88d0a964685ae88985031b39540e15b4da0e", + "typeScriptVersion": "4.7" +} \ No newline at end of file diff --git a/node_modules/@types/tough-cookie/LICENSE b/node_modules/@types/tough-cookie/LICENSE new file mode 100644 index 0000000000000000000000000000000000000000..9e841e7a26e4eb057b24511e7b92d42b257a80e5 --- /dev/null +++ b/node_modules/@types/tough-cookie/LICENSE @@ -0,0 +1,21 @@ + MIT License + + Copyright (c) Microsoft Corporation. + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE diff --git a/node_modules/@types/tough-cookie/README.md b/node_modules/@types/tough-cookie/README.md new file mode 100644 index 0000000000000000000000000000000000000000..c889560d86ffd04936dfd24e1295ffff941b53f4 --- /dev/null +++ b/node_modules/@types/tough-cookie/README.md @@ -0,0 +1,15 @@ +# Installation +> `npm install --save @types/tough-cookie` + +# Summary +This package contains type definitions for tough-cookie (https://github.com/salesforce/tough-cookie). + +# Details +Files were exported from https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/tough-cookie. + +### Additional Details + * Last updated: Tue, 07 Nov 2023 20:08:00 GMT + * Dependencies: none + +# Credits +These definitions were written by [Leonard Thieu](https://github.com/leonard-thieu), [LiJinyao](https://github.com/LiJinyao), and [Michael Wei](https://github.com/no2chem). diff --git a/node_modules/@types/tough-cookie/index.d.ts b/node_modules/@types/tough-cookie/index.d.ts new file mode 100644 index 0000000000000000000000000000000000000000..0afa14d3870b02bc756936189a8745144ba22177 --- /dev/null +++ b/node_modules/@types/tough-cookie/index.d.ts @@ -0,0 +1,321 @@ +export const version: string; + +export const PrefixSecurityEnum: Readonly<{ + DISABLED: string; + SILENT: string; + STRICT: string; +}>; + +/** + * Parse a cookie date string into a Date. + * Parses according to RFC6265 Section 5.1.1, not Date.parse(). + */ +export function parseDate(string: string): Date; + +/** + * Format a Date into a RFC1123 string (the RFC6265-recommended format). + */ +export function formatDate(date: Date): string; + +/** + * Transforms a domain-name into a canonical domain-name. + * The canonical domain-name is a trimmed, lowercased, stripped-of-leading-dot + * and optionally punycode-encoded domain-name (Section 5.1.2 of RFC6265). + * For the most part, this function is idempotent (can be run again on its output without ill effects). + */ +export function canonicalDomain(str: string): string; + +/** + * Answers "does this real domain match the domain in a cookie?". + * The str is the "current" domain-name and the domStr is the "cookie" domain-name. + * Matches according to RFC6265 Section 5.1.3, but it helps to think of it as a "suffix match". + * + * The canonicalize parameter will run the other two parameters through canonicalDomain or not. + */ +export function domainMatch(str: string, domStr: string, canonicalize?: boolean): boolean; + +/** + * Given a current request/response path, gives the Path apropriate for storing in a cookie. + * This is basically the "directory" of a "file" in the path, but is specified by Section 5.1.4 of the RFC. + * + * The path parameter MUST be only the pathname part of a URI (i.e. excludes the hostname, query, fragment, etc.). + * This is the .pathname property of node's uri.parse() output. + */ +export function defaultPath(path: string): string; + +/** + * Answers "does the request-path path-match a given cookie-path?" as per RFC6265 Section 5.1.4. + * Returns a boolean. + * + * This is essentially a prefix-match where cookiePath is a prefix of reqPath. + */ +export function pathMatch(reqPath: string, cookiePath: string): boolean; + +/** + * alias for Cookie.parse(cookieString[, options]) + */ +export function parse(cookieString: string, options?: Cookie.ParseOptions): Cookie | undefined; + +/** + * alias for Cookie.fromJSON(string) + */ +export function fromJSON(string: string): Cookie; + +export function getPublicSuffix(hostname: string): string | null; + +export function cookieCompare(a: Cookie, b: Cookie): number; + +export function permuteDomain(domain: string, allowSpecialUseDomain?: boolean): string[]; + +export function permutePath(path: string): string[]; + +export class Cookie { + static parse(cookieString: string, options?: Cookie.ParseOptions): Cookie | undefined; + + static fromJSON(strOrObj: string | object): Cookie | null; + + constructor(properties?: Cookie.Properties); + + key: string; + value: string; + expires: Date | "Infinity"; + maxAge: number | "Infinity" | "-Infinity"; + domain: string | null; + path: string | null; + secure: boolean; + httpOnly: boolean; + extensions: string[] | null; + creation: Date | null; + creationIndex: number; + + hostOnly: boolean | null; + pathIsDefault: boolean | null; + lastAccessed: Date | null; + sameSite: string; + + toString(): string; + + cookieString(): string; + + setExpires(exp: Date | string): void; + + setMaxAge(number: number): void; + + expiryTime(now?: number): number; + + expiryDate(now?: number): Date; + + TTL(now?: Date): number | typeof Infinity; + + isPersistent(): boolean; + + canonicalizedDomain(): string | null; + + cdomain(): string | null; + + inspect(): string; + + toJSON(): { [key: string]: any }; + + clone(): Cookie; + + validate(): boolean | string; +} + +export namespace Cookie { + interface ParseOptions { + loose?: boolean | undefined; + } + + interface Properties { + key?: string | undefined; + value?: string | undefined; + expires?: Date | "Infinity" | undefined; + maxAge?: number | "Infinity" | "-Infinity" | undefined; + domain?: string | undefined; + path?: string | undefined; + secure?: boolean | undefined; + httpOnly?: boolean | undefined; + extensions?: string[] | undefined; + creation?: Date | undefined; + creationIndex?: number | undefined; + + hostOnly?: boolean | undefined; + pathIsDefault?: boolean | undefined; + lastAccessed?: Date | undefined; + sameSite?: string | undefined; + } + + interface Serialized { + [key: string]: any; + } +} + +export class CookieJar { + static deserialize(serialized: CookieJar.Serialized | string, store?: Store): Promise; + static deserialize( + serialized: CookieJar.Serialized | string, + store: Store, + cb: (err: Error | null, object: CookieJar) => void, + ): void; + static deserialize( + serialized: CookieJar.Serialized | string, + cb: (err: Error | null, object: CookieJar) => void, + ): void; + + static deserializeSync(serialized: CookieJar.Serialized | string, store?: Store): CookieJar; + + static fromJSON(string: string): CookieJar; + + constructor(store?: Store, options?: CookieJar.Options); + + setCookie( + cookieOrString: Cookie | string, + currentUrl: string, + options?: CookieJar.SetCookieOptions, + ): Promise; + setCookie( + cookieOrString: Cookie | string, + currentUrl: string, + options: CookieJar.SetCookieOptions, + cb: (err: Error | null, cookie: Cookie) => void, + ): void; + setCookie( + cookieOrString: Cookie | string, + currentUrl: string, + cb: (err: Error | null, cookie: Cookie) => void, + ): void; + + setCookieSync(cookieOrString: Cookie | string, currentUrl: string, options?: CookieJar.SetCookieOptions): Cookie; + + getCookies(currentUrl: string, options?: CookieJar.GetCookiesOptions): Promise; + getCookies( + currentUrl: string, + options: CookieJar.GetCookiesOptions, + cb: (err: Error | null, cookies: Cookie[]) => void, + ): void; + getCookies(currentUrl: string, cb: (err: Error | null, cookies: Cookie[]) => void): void; + + getCookiesSync(currentUrl: string, options?: CookieJar.GetCookiesOptions): Cookie[]; + + getCookieString(currentUrl: string, options?: CookieJar.GetCookiesOptions): Promise; + getCookieString( + currentUrl: string, + options: CookieJar.GetCookiesOptions, + cb: (err: Error | null, cookies: string) => void, + ): void; + getCookieString(currentUrl: string, cb: (err: Error | null, cookies: string) => void): void; + + getCookieStringSync(currentUrl: string, options?: CookieJar.GetCookiesOptions): string; + + getSetCookieStrings(currentUrl: string, options?: CookieJar.GetCookiesOptions): Promise; + getSetCookieStrings( + currentUrl: string, + options: CookieJar.GetCookiesOptions, + cb: (err: Error | null, cookies: string[]) => void, + ): void; + getSetCookieStrings(currentUrl: string, cb: (err: Error | null, cookies: string[]) => void): void; + + getSetCookieStringsSync(currentUrl: string, options?: CookieJar.GetCookiesOptions): string[]; + + serialize(): Promise; + serialize(cb: (err: Error | null, serializedObject: CookieJar.Serialized) => void): void; + + serializeSync(): CookieJar.Serialized; + + toJSON(): CookieJar.Serialized; + + clone(store?: Store): Promise; + clone(store: Store, cb: (err: Error | null, newJar: CookieJar) => void): void; + clone(cb: (err: Error | null, newJar: CookieJar) => void): void; + + cloneSync(store?: Store): CookieJar; + + removeAllCookies(): Promise; + removeAllCookies(cb: (err: Error | null) => void): void; + + removeAllCookiesSync(): void; +} + +export namespace CookieJar { + interface Options { + allowSpecialUseDomain?: boolean | undefined; + looseMode?: boolean | undefined; + rejectPublicSuffixes?: boolean | undefined; + prefixSecurity?: string | undefined; + } + + interface SetCookieOptions { + http?: boolean | undefined; + secure?: boolean | undefined; + now?: Date | undefined; + ignoreError?: boolean | undefined; + } + + interface GetCookiesOptions { + http?: boolean | undefined; + secure?: boolean | undefined; + now?: Date | undefined; + expire?: boolean | undefined; + allPaths?: boolean | undefined; + } + + interface Serialized { + version: string; + storeType: string; + rejectPublicSuffixes: boolean; + cookies: Cookie.Serialized[]; + } +} + +export abstract class Store { + synchronous: boolean; + + findCookie(domain: string, path: string, key: string, cb: (err: Error | null, cookie: Cookie | null) => void): void; + + findCookies( + domain: string, + path: string, + allowSpecialUseDomain: boolean, + cb: (err: Error | null, cookie: Cookie[]) => void, + ): void; + + putCookie(cookie: Cookie, cb: (err: Error | null) => void): void; + + updateCookie(oldCookie: Cookie, newCookie: Cookie, cb: (err: Error | null) => void): void; + + removeCookie(domain: string, path: string, key: string, cb: (err: Error | null) => void): void; + + removeCookies(domain: string, path: string, cb: (err: Error | null) => void): void; + + getAllCookies(cb: (err: Error | null, cookie: Cookie[]) => void): void; +} + +export class MemoryCookieStore extends Store { + findCookie(domain: string, path: string, key: string, cb: (err: Error | null, cookie: Cookie | null) => void): void; + findCookie(domain: string, path: string, key: string): Promise; + + findCookies( + domain: string, + path: string, + allowSpecialUseDomain: boolean, + cb: (err: Error | null, cookie: Cookie[]) => void, + ): void; + findCookies(domain: string, path: string, cb: (err: Error | null, cookie: Cookie[]) => void): void; + findCookies(domain: string, path: string, allowSpecialUseDomain?: boolean): Promise; + + putCookie(cookie: Cookie, cb: (err: Error | null) => void): void; + putCookie(cookie: Cookie): Promise; + + updateCookie(oldCookie: Cookie, newCookie: Cookie, cb: (err: Error | null) => void): void; + updateCookie(oldCookie: Cookie, newCookie: Cookie): Promise; + + removeCookie(domain: string, path: string, key: string, cb: (err: Error | null) => void): void; + removeCookie(domain: string, path: string, key: string): Promise; + + removeCookies(domain: string, path: string, cb: (err: Error | null) => void): void; + removeCookies(domain: string, path: string): Promise; + + getAllCookies(cb: (err: Error | null, cookie: Cookie[]) => void): void; + getAllCookies(): Promise; +} diff --git a/node_modules/@types/tough-cookie/package.json b/node_modules/@types/tough-cookie/package.json new file mode 100644 index 0000000000000000000000000000000000000000..f100365094c6b8a1f5967d90c58fe422df3e3b94 --- /dev/null +++ b/node_modules/@types/tough-cookie/package.json @@ -0,0 +1,35 @@ +{ + "name": "@types/tough-cookie", + "version": "4.0.5", + "description": "TypeScript definitions for tough-cookie", + "homepage": "https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/tough-cookie", + "license": "MIT", + "contributors": [ + { + "name": "Leonard Thieu", + "githubUsername": "leonard-thieu", + "url": "https://github.com/leonard-thieu" + }, + { + "name": "LiJinyao", + "githubUsername": "LiJinyao", + "url": "https://github.com/LiJinyao" + }, + { + "name": "Michael Wei", + "githubUsername": "no2chem", + "url": "https://github.com/no2chem" + } + ], + "main": "", + "types": "index.d.ts", + "repository": { + "type": "git", + "url": "https://github.com/DefinitelyTyped/DefinitelyTyped.git", + "directory": "types/tough-cookie" + }, + "scripts": {}, + "dependencies": {}, + "typesPublisherContentHash": "adafa53ff34d3665a708d3ab1af232a46d4efb906d46f48d7d0cd3206c987a58", + "typeScriptVersion": "4.5" +} \ No newline at end of file diff --git a/node_modules/ansi-escapes/index.d.ts b/node_modules/ansi-escapes/index.d.ts new file mode 100644 index 0000000000000000000000000000000000000000..5201942e13d23855034c29e859c4ab6485e6aa63 --- /dev/null +++ b/node_modules/ansi-escapes/index.d.ts @@ -0,0 +1,248 @@ +/// +import {LiteralUnion} from 'type-fest'; + +declare namespace ansiEscapes { + interface ImageOptions { + /** + The width is given as a number followed by a unit, or the word `'auto'`. + + - `N`: N character cells. + - `Npx`: N pixels. + - `N%`: N percent of the session's width or height. + - `auto`: The image's inherent size will be used to determine an appropriate dimension. + */ + readonly width?: LiteralUnion<'auto', number | string>; + + /** + The height is given as a number followed by a unit, or the word `'auto'`. + + - `N`: N character cells. + - `Npx`: N pixels. + - `N%`: N percent of the session's width or height. + - `auto`: The image's inherent size will be used to determine an appropriate dimension. + */ + readonly height?: LiteralUnion<'auto', number | string>; + + readonly preserveAspectRatio?: boolean; + } + + interface AnnotationOptions { + /** + Nonzero number of columns to annotate. + + Default: The remainder of the line. + */ + readonly length?: number; + + /** + Starting X coordinate. + + Must be used with `y` and `length`. + + Default: The cursor position + */ + readonly x?: number; + + /** + Starting Y coordinate. + + Must be used with `x` and `length`. + + Default: Cursor position. + */ + readonly y?: number; + + /** + Create a "hidden" annotation. + + Annotations created this way can be shown using the "Show Annotations" iTerm command. + */ + readonly isHidden?: boolean; + } +} + +declare const ansiEscapes: { + /** + Set the absolute position of the cursor. `x0` `y0` is the top left of the screen. + */ + cursorTo(x: number, y?: number): string; + + /** + Set the position of the cursor relative to its current position. + */ + cursorMove(x: number, y?: number): string; + + /** + Move cursor up a specific amount of rows. + + @param count - Count of rows to move up. Default is `1`. + */ + cursorUp(count?: number): string; + + /** + Move cursor down a specific amount of rows. + + @param count - Count of rows to move down. Default is `1`. + */ + cursorDown(count?: number): string; + + /** + Move cursor forward a specific amount of rows. + + @param count - Count of rows to move forward. Default is `1`. + */ + cursorForward(count?: number): string; + + /** + Move cursor backward a specific amount of rows. + + @param count - Count of rows to move backward. Default is `1`. + */ + cursorBackward(count?: number): string; + + /** + Move cursor to the left side. + */ + cursorLeft: string; + + /** + Save cursor position. + */ + cursorSavePosition: string; + + /** + Restore saved cursor position. + */ + cursorRestorePosition: string; + + /** + Get cursor position. + */ + cursorGetPosition: string; + + /** + Move cursor to the next line. + */ + cursorNextLine: string; + + /** + Move cursor to the previous line. + */ + cursorPrevLine: string; + + /** + Hide cursor. + */ + cursorHide: string; + + /** + Show cursor. + */ + cursorShow: string; + + /** + Erase from the current cursor position up the specified amount of rows. + + @param count - Count of rows to erase. + */ + eraseLines(count: number): string; + + /** + Erase from the current cursor position to the end of the current line. + */ + eraseEndLine: string; + + /** + Erase from the current cursor position to the start of the current line. + */ + eraseStartLine: string; + + /** + Erase the entire current line. + */ + eraseLine: string; + + /** + Erase the screen from the current line down to the bottom of the screen. + */ + eraseDown: string; + + /** + Erase the screen from the current line up to the top of the screen. + */ + eraseUp: string; + + /** + Erase the screen and move the cursor the top left position. + */ + eraseScreen: string; + + /** + Scroll display up one line. + */ + scrollUp: string; + + /** + Scroll display down one line. + */ + scrollDown: string; + + /** + Clear the terminal screen. (Viewport) + */ + clearScreen: string; + + /** + Clear the whole terminal, including scrollback buffer. (Not just the visible part of it) + */ + clearTerminal: string; + + /** + Output a beeping sound. + */ + beep: string; + + /** + Create a clickable link. + + [Supported terminals.](https://gist.github.com/egmontkob/eb114294efbcd5adb1944c9f3cb5feda) Use [`supports-hyperlinks`](https://github.com/jamestalmage/supports-hyperlinks) to detect link support. + */ + link(text: string, url: string): string; + + /** + Display an image. + + _Currently only supported on iTerm2 >=3_ + + See [term-img](https://github.com/sindresorhus/term-img) for a higher-level module. + + @param buffer - Buffer of an image. Usually read in with `fs.readFile()`. + */ + image(buffer: Buffer, options?: ansiEscapes.ImageOptions): string; + + iTerm: { + /** + [Inform iTerm2](https://www.iterm2.com/documentation-escape-codes.html) of the current directory to help semantic history and enable [Cmd-clicking relative paths](https://coderwall.com/p/b7e82q/quickly-open-files-in-iterm-with-cmd-click). + + @param cwd - Current directory. Default: `process.cwd()`. + */ + setCwd(cwd?: string): string; + + /** + An annotation looks like this when shown: + + ![screenshot of iTerm annotation](https://user-images.githubusercontent.com/924465/64382136-b60ac700-cfe9-11e9-8a35-9682e8dc4b72.png) + + See the [iTerm Proprietary Escape Codes documentation](https://iterm2.com/documentation-escape-codes.html) for more information. + + @param message - The message to display within the annotation. The `|` character is disallowed and will be stripped. + @returns An escape code which will create an annotation when printed in iTerm2. + */ + annotation(message: string, options?: ansiEscapes.AnnotationOptions): string; + }; + + // TODO: remove this in the next major version + default: typeof ansiEscapes; +}; + +export = ansiEscapes; diff --git a/node_modules/ansi-escapes/index.js b/node_modules/ansi-escapes/index.js new file mode 100644 index 0000000000000000000000000000000000000000..283331858f02e17ce63e202c0d29a778d9e2939a --- /dev/null +++ b/node_modules/ansi-escapes/index.js @@ -0,0 +1,157 @@ +'use strict'; +const ansiEscapes = module.exports; +// TODO: remove this in the next major version +module.exports.default = ansiEscapes; + +const ESC = '\u001B['; +const OSC = '\u001B]'; +const BEL = '\u0007'; +const SEP = ';'; +const isTerminalApp = process.env.TERM_PROGRAM === 'Apple_Terminal'; + +ansiEscapes.cursorTo = (x, y) => { + if (typeof x !== 'number') { + throw new TypeError('The `x` argument is required'); + } + + if (typeof y !== 'number') { + return ESC + (x + 1) + 'G'; + } + + return ESC + (y + 1) + ';' + (x + 1) + 'H'; +}; + +ansiEscapes.cursorMove = (x, y) => { + if (typeof x !== 'number') { + throw new TypeError('The `x` argument is required'); + } + + let ret = ''; + + if (x < 0) { + ret += ESC + (-x) + 'D'; + } else if (x > 0) { + ret += ESC + x + 'C'; + } + + if (y < 0) { + ret += ESC + (-y) + 'A'; + } else if (y > 0) { + ret += ESC + y + 'B'; + } + + return ret; +}; + +ansiEscapes.cursorUp = (count = 1) => ESC + count + 'A'; +ansiEscapes.cursorDown = (count = 1) => ESC + count + 'B'; +ansiEscapes.cursorForward = (count = 1) => ESC + count + 'C'; +ansiEscapes.cursorBackward = (count = 1) => ESC + count + 'D'; + +ansiEscapes.cursorLeft = ESC + 'G'; +ansiEscapes.cursorSavePosition = isTerminalApp ? '\u001B7' : ESC + 's'; +ansiEscapes.cursorRestorePosition = isTerminalApp ? '\u001B8' : ESC + 'u'; +ansiEscapes.cursorGetPosition = ESC + '6n'; +ansiEscapes.cursorNextLine = ESC + 'E'; +ansiEscapes.cursorPrevLine = ESC + 'F'; +ansiEscapes.cursorHide = ESC + '?25l'; +ansiEscapes.cursorShow = ESC + '?25h'; + +ansiEscapes.eraseLines = count => { + let clear = ''; + + for (let i = 0; i < count; i++) { + clear += ansiEscapes.eraseLine + (i < count - 1 ? ansiEscapes.cursorUp() : ''); + } + + if (count) { + clear += ansiEscapes.cursorLeft; + } + + return clear; +}; + +ansiEscapes.eraseEndLine = ESC + 'K'; +ansiEscapes.eraseStartLine = ESC + '1K'; +ansiEscapes.eraseLine = ESC + '2K'; +ansiEscapes.eraseDown = ESC + 'J'; +ansiEscapes.eraseUp = ESC + '1J'; +ansiEscapes.eraseScreen = ESC + '2J'; +ansiEscapes.scrollUp = ESC + 'S'; +ansiEscapes.scrollDown = ESC + 'T'; + +ansiEscapes.clearScreen = '\u001Bc'; + +ansiEscapes.clearTerminal = process.platform === 'win32' ? + `${ansiEscapes.eraseScreen}${ESC}0f` : + // 1. Erases the screen (Only done in case `2` is not supported) + // 2. Erases the whole screen including scrollback buffer + // 3. Moves cursor to the top-left position + // More info: https://www.real-world-systems.com/docs/ANSIcode.html + `${ansiEscapes.eraseScreen}${ESC}3J${ESC}H`; + +ansiEscapes.beep = BEL; + +ansiEscapes.link = (text, url) => { + return [ + OSC, + '8', + SEP, + SEP, + url, + BEL, + text, + OSC, + '8', + SEP, + SEP, + BEL + ].join(''); +}; + +ansiEscapes.image = (buffer, options = {}) => { + let ret = `${OSC}1337;File=inline=1`; + + if (options.width) { + ret += `;width=${options.width}`; + } + + if (options.height) { + ret += `;height=${options.height}`; + } + + if (options.preserveAspectRatio === false) { + ret += ';preserveAspectRatio=0'; + } + + return ret + ':' + buffer.toString('base64') + BEL; +}; + +ansiEscapes.iTerm = { + setCwd: (cwd = process.cwd()) => `${OSC}50;CurrentDir=${cwd}${BEL}`, + + annotation: (message, options = {}) => { + let ret = `${OSC}1337;`; + + const hasX = typeof options.x !== 'undefined'; + const hasY = typeof options.y !== 'undefined'; + if ((hasX || hasY) && !(hasX && hasY && typeof options.length !== 'undefined')) { + throw new Error('`x`, `y` and `length` must be defined when `x` or `y` is defined'); + } + + message = message.replace(/\|/g, ''); + + ret += options.isHidden ? 'AddHiddenAnnotation=' : 'AddAnnotation='; + + if (options.length > 0) { + ret += + (hasX ? + [message, options.length, options.x, options.y] : + [options.length, message]).join('|'); + } else { + ret += message; + } + + return ret + BEL; + } +}; diff --git a/node_modules/ansi-escapes/license b/node_modules/ansi-escapes/license new file mode 100644 index 0000000000000000000000000000000000000000..fa7ceba3eb4a9657a9db7f3ffca4e4e97a9019de --- /dev/null +++ b/node_modules/ansi-escapes/license @@ -0,0 +1,9 @@ +MIT License + +Copyright (c) Sindre Sorhus (https://sindresorhus.com) + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/node_modules/ansi-escapes/node_modules/type-fest/base.d.ts b/node_modules/ansi-escapes/node_modules/type-fest/base.d.ts new file mode 100644 index 0000000000000000000000000000000000000000..625a05d581a4c64e7ea59e4abad383f05d492dfd --- /dev/null +++ b/node_modules/ansi-escapes/node_modules/type-fest/base.d.ts @@ -0,0 +1,39 @@ +// Types that are compatible with all supported TypeScript versions. +// It's shared between all TypeScript version-specific definitions. + +// Basic +export * from './source/basic'; +export * from './source/typed-array'; + +// Utilities +export {Except} from './source/except'; +export {Mutable} from './source/mutable'; +export {Merge} from './source/merge'; +export {MergeExclusive} from './source/merge-exclusive'; +export {RequireAtLeastOne} from './source/require-at-least-one'; +export {RequireExactlyOne} from './source/require-exactly-one'; +export {PartialDeep} from './source/partial-deep'; +export {ReadonlyDeep} from './source/readonly-deep'; +export {LiteralUnion} from './source/literal-union'; +export {Promisable} from './source/promisable'; +export {Opaque} from './source/opaque'; +export {SetOptional} from './source/set-optional'; +export {SetRequired} from './source/set-required'; +export {ValueOf} from './source/value-of'; +export {PromiseValue} from './source/promise-value'; +export {AsyncReturnType} from './source/async-return-type'; +export {ConditionalExcept} from './source/conditional-except'; +export {ConditionalKeys} from './source/conditional-keys'; +export {ConditionalPick} from './source/conditional-pick'; +export {UnionToIntersection} from './source/union-to-intersection'; +export {Stringified} from './source/stringified'; +export {FixedLengthArray} from './source/fixed-length-array'; +export {IterableElement} from './source/iterable-element'; +export {Entry} from './source/entry'; +export {Entries} from './source/entries'; +export {SetReturnType} from './source/set-return-type'; +export {Asyncify} from './source/asyncify'; + +// Miscellaneous +export {PackageJson} from './source/package-json'; +export {TsConfigJson} from './source/tsconfig-json'; diff --git a/node_modules/ansi-escapes/node_modules/type-fest/index.d.ts b/node_modules/ansi-escapes/node_modules/type-fest/index.d.ts new file mode 100644 index 0000000000000000000000000000000000000000..206261c21d733023b1ab0596f541d7d277ff8c30 --- /dev/null +++ b/node_modules/ansi-escapes/node_modules/type-fest/index.d.ts @@ -0,0 +1,2 @@ +// These are all the basic types that's compatible with all supported TypeScript versions. +export * from './base'; diff --git a/node_modules/ansi-escapes/node_modules/type-fest/license b/node_modules/ansi-escapes/node_modules/type-fest/license new file mode 100644 index 0000000000000000000000000000000000000000..3e4c85ab7effdc0cec4740e58791fc6a0cc144e4 --- /dev/null +++ b/node_modules/ansi-escapes/node_modules/type-fest/license @@ -0,0 +1,9 @@ +MIT License + +Copyright (c) Sindre Sorhus (https:/sindresorhus.com) + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/node_modules/ansi-escapes/node_modules/type-fest/package.json b/node_modules/ansi-escapes/node_modules/type-fest/package.json new file mode 100644 index 0000000000000000000000000000000000000000..a0a37182aa0b609d62c58a769a8b97bd1548a016 --- /dev/null +++ b/node_modules/ansi-escapes/node_modules/type-fest/package.json @@ -0,0 +1,58 @@ +{ + "name": "type-fest", + "version": "0.21.3", + "description": "A collection of essential TypeScript types", + "license": "(MIT OR CC0-1.0)", + "repository": "sindresorhus/type-fest", + "funding": "https://github.com/sponsors/sindresorhus", + "author": { + "name": "Sindre Sorhus", + "email": "sindresorhus@gmail.com", + "url": "https://sindresorhus.com" + }, + "engines": { + "node": ">=10" + }, + "scripts": { + "test": "xo && tsd && tsc" + }, + "files": [ + "index.d.ts", + "base.d.ts", + "source", + "ts41" + ], + "keywords": [ + "typescript", + "ts", + "types", + "utility", + "util", + "utilities", + "omit", + "merge", + "json" + ], + "devDependencies": { + "@sindresorhus/tsconfig": "~0.7.0", + "expect-type": "^0.11.0", + "tsd": "^0.14.0", + "typescript": "^4.1.3", + "xo": "^0.36.1" + }, + "types": "./index.d.ts", + "typesVersions": { + ">=4.1": { + "*": [ + "ts41/*" + ] + } + }, + "xo": { + "rules": { + "@typescript-eslint/ban-types": "off", + "@typescript-eslint/indent": "off", + "node/no-unsupported-features/es-builtins": "off" + } + } +} diff --git a/node_modules/ansi-escapes/node_modules/type-fest/readme.md b/node_modules/ansi-escapes/node_modules/type-fest/readme.md new file mode 100644 index 0000000000000000000000000000000000000000..4fae2d385d2c0487601c8f5b2d971cdb74fd96c6 --- /dev/null +++ b/node_modules/ansi-escapes/node_modules/type-fest/readme.md @@ -0,0 +1,760 @@ +
+
+
+ type-fest +
+
+ A collection of essential TypeScript types +
+
+
+
+
+

+

+ + Sindre Sorhus' open source work is supported by the community + +

+ Special thanks to: +
+
+ + + +

+
+
+
+
+
+
+ +[![](https://img.shields.io/badge/unicorn-approved-ff69b4.svg)](https://giphy.com/gifs/illustration-rainbow-unicorn-26AHG5KGFxSkUWw1i) +[![npm dependents](https://badgen.net/npm/dependents/type-fest)](https://www.npmjs.com/package/type-fest?activeTab=dependents) [![npm downloads](https://badgen.net/npm/dt/type-fest)](https://www.npmjs.com/package/type-fest) + +Many of the types here should have been built-in. You can help by suggesting some of them to the [TypeScript project](https://github.com/Microsoft/TypeScript/blob/master/CONTRIBUTING.md). + +Either add this package as a dependency or copy-paste the needed types. No credit required. 👌 + +PR welcome for additional commonly needed types and docs improvements. Read the [contributing guidelines](.github/contributing.md) first. + +## Install + +``` +$ npm install type-fest +``` + +*Requires TypeScript >=3.4* + +## Usage + +```ts +import {Except} from 'type-fest'; + +type Foo = { + unicorn: string; + rainbow: boolean; +}; + +type FooWithoutRainbow = Except; +//=> {unicorn: string} +``` + +## API + +Click the type names for complete docs. + +### Basic + +- [`Primitive`](source/basic.d.ts) - Matches any [primitive value](https://developer.mozilla.org/en-US/docs/Glossary/Primitive). +- [`Class`](source/basic.d.ts) - Matches a [`class` constructor](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes). +- [`TypedArray`](source/typed-array.d.ts) - Matches any [typed array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypedArray), like `Uint8Array` or `Float64Array`. +- [`JsonObject`](source/basic.d.ts) - Matches a JSON object. +- [`JsonArray`](source/basic.d.ts) - Matches a JSON array. +- [`JsonValue`](source/basic.d.ts) - Matches any valid JSON value. +- [`ObservableLike`](source/basic.d.ts) - Matches a value that is like an [Observable](https://github.com/tc39/proposal-observable). + +### Utilities + +- [`Except`](source/except.d.ts) - Create a type from an object type without certain keys. This is a stricter version of [`Omit`](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-5.html#the-omit-helper-type). +- [`Mutable`](source/mutable.d.ts) - Create a type that strips `readonly` from all or some of an object's keys. The inverse of `Readonly`. +- [`Merge`](source/merge.d.ts) - Merge two types into a new type. Keys of the second type overrides keys of the first type. +- [`MergeExclusive`](source/merge-exclusive.d.ts) - Create a type that has mutually exclusive keys. +- [`RequireAtLeastOne`](source/require-at-least-one.d.ts) - Create a type that requires at least one of the given keys. +- [`RequireExactlyOne`](source/require-exactly-one.d.ts) - Create a type that requires exactly a single key of the given keys and disallows more. +- [`PartialDeep`](source/partial-deep.d.ts) - Create a deeply optional version of another type. Use [`Partial`](https://github.com/Microsoft/TypeScript/blob/2961bc3fc0ea1117d4e53bc8e97fa76119bc33e3/src/lib/es5.d.ts#L1401-L1406) if you only need one level deep. +- [`ReadonlyDeep`](source/readonly-deep.d.ts) - Create a deeply immutable version of an `object`/`Map`/`Set`/`Array` type. Use [`Readonly`](https://github.com/Microsoft/TypeScript/blob/2961bc3fc0ea1117d4e53bc8e97fa76119bc33e3/src/lib/es5.d.ts#L1415-L1420) if you only need one level deep. +- [`LiteralUnion`](source/literal-union.d.ts) - Create a union type by combining primitive types and literal types without sacrificing auto-completion in IDEs for the literal type part of the union. Workaround for [Microsoft/TypeScript#29729](https://github.com/Microsoft/TypeScript/issues/29729). +- [`Promisable`](source/promisable.d.ts) - Create a type that represents either the value or the value wrapped in `PromiseLike`. +- [`Opaque`](source/opaque.d.ts) - Create an [opaque type](https://codemix.com/opaque-types-in-javascript/). +- [`SetOptional`](source/set-optional.d.ts) - Create a type that makes the given keys optional. +- [`SetRequired`](source/set-required.d.ts) - Create a type that makes the given keys required. +- [`ValueOf`](source/value-of.d.ts) - Create a union of the given object's values, and optionally specify which keys to get the values from. +- [`PromiseValue`](source/promise-value.d.ts) - Returns the type that is wrapped inside a `Promise`. +- [`AsyncReturnType`](source/async-return-type.d.ts) - Unwrap the return type of a function that returns a `Promise`. +- [`ConditionalKeys`](source/conditional-keys.d.ts) - Extract keys from a shape where values extend the given `Condition` type. +- [`ConditionalPick`](source/conditional-pick.d.ts) - Like `Pick` except it selects properties from a shape where the values extend the given `Condition` type. +- [`ConditionalExcept`](source/conditional-except.d.ts) - Like `Omit` except it removes properties from a shape where the values extend the given `Condition` type. +- [`UnionToIntersection`](source/union-to-intersection.d.ts) - Convert a union type to an intersection type. +- [`Stringified`](source/stringified.d.ts) - Create a type with the keys of the given type changed to `string` type. +- [`FixedLengthArray`](source/fixed-length-array.d.ts) - Create a type that represents an array of the given type and length. +- [`IterableElement`](source/iterable-element.d.ts) - Get the element type of an `Iterable`/`AsyncIterable`. For example, an array or a generator. +- [`Entry`](source/entry.d.ts) - Create a type that represents the type of an entry of a collection. +- [`Entries`](source/entries.d.ts) - Create a type that represents the type of the entries of a collection. +- [`SetReturnType`](source/set-return-type.d.ts) - Create a function type with a return type of your choice and the same parameters as the given function type. +- [`Asyncify`](source/asyncify.d.ts) - Create an async version of the given function type. + +### Template literal types + +*Note:* These require [TypeScript 4.1 or newer](https://devblogs.microsoft.com/typescript/announcing-typescript-4-1/#template-literal-types). + +- [`CamelCase`](ts41/camel-case.d.ts) – Convert a string literal to camel-case (`fooBar`). +- [`KebabCase`](ts41/kebab-case.d.ts) – Convert a string literal to kebab-case (`foo-bar`). +- [`PascalCase`](ts41/pascal-case.d.ts) – Converts a string literal to pascal-case (`FooBar`) +- [`SnakeCase`](ts41/snake-case.d.ts) – Convert a string literal to snake-case (`foo_bar`). +- [`DelimiterCase`](ts41/delimiter-case.d.ts) – Convert a string literal to a custom string delimiter casing. +- [`Get`](ts41/get.d.ts) - Get a deeply-nested property from an object using a key path, like [Lodash's `.get()`](https://lodash.com/docs/latest#get) function. + +### Miscellaneous + +- [`PackageJson`](source/package-json.d.ts) - Type for [npm's `package.json` file](https://docs.npmjs.com/creating-a-package-json-file). +- [`TsConfigJson`](source/tsconfig-json.d.ts) - Type for [TypeScript's `tsconfig.json` file](https://www.typescriptlang.org/docs/handbook/tsconfig-json.html) (TypeScript 3.7). + +## Declined types + +*If we decline a type addition, we will make sure to document the better solution here.* + +- [`Diff` and `Spread`](https://github.com/sindresorhus/type-fest/pull/7) - The PR author didn't provide any real-world use-cases and the PR went stale. If you think this type is useful, provide some real-world use-cases and we might reconsider. +- [`Dictionary`](https://github.com/sindresorhus/type-fest/issues/33) - You only save a few characters (`Dictionary` vs `Record`) from [`Record`](https://github.com/Microsoft/TypeScript/blob/2961bc3fc0ea1117d4e53bc8e97fa76119bc33e3/src/lib/es5.d.ts#L1429-L1434), which is more flexible and well-known. Also, you shouldn't use an object as a dictionary. We have `Map` in JavaScript now. +- [`SubType`](https://github.com/sindresorhus/type-fest/issues/22) - The type is powerful, but lacks good use-cases and is prone to misuse. +- [`ExtractProperties` and `ExtractMethods`](https://github.com/sindresorhus/type-fest/pull/4) - The types violate the single responsibility principle. Instead, refine your types into more granular type hierarchies. + +## Tips + +### Built-in types + +There are many advanced types most users don't know about. + +- [`Partial`](https://github.com/Microsoft/TypeScript/blob/2961bc3fc0ea1117d4e53bc8e97fa76119bc33e3/src/lib/es5.d.ts#L1401-L1406) - Make all properties in `T` optional. +
+ + Example + + + [Playground](https://www.typescriptlang.org/play/#code/JYOwLgpgTgZghgYwgAgHIHsAmEDC6QzADmyA3gLABQyycADnanALYQBcyAzmFKEQNxUaddFDAcQAV2YAjaIMoBfKlQQAbOJ05osEAIIMAQpOBrsUMkOR1eANziRkCfISKSoD4Pg4ZseAsTIALyW1DS0DEysHADkvvoMMQA0VsKi4sgAzAAMuVaKClY2wPaOknSYDrguADwA0sgQAB6QIJjaANYQAJ7oMDp+LsQAfAAUXd0cdUnI9mo+uv6uANp1ALoAlKHhyGAAFsCcAHTOAW4eYF4gyxNrwbNwago0ypRWp66jH8QcAApwYmAjxq8SWIy2FDCNDA3ToKFBQyIdR69wmfQG1TOhShyBgomQX3w3GQE2Q6IA8jIAFYQBBgI4TTiEs5bTQYsFInrLTbbHZOIlgZDlSqQABqj0kKBC3yINx6a2xfOQwH6o2FVXFaklwSCIUkbQghBAEEwENSfNOlykEGefNe5uhB2O6sgS3GPRmLogmslG1tLxUOKgEDA7hAuydtteryAA) + + ```ts + interface NodeConfig { + appName: string; + port: number; + } + + class NodeAppBuilder { + private configuration: NodeConfig = { + appName: 'NodeApp', + port: 3000 + }; + + private updateConfig(key: Key, value: NodeConfig[Key]) { + this.configuration[key] = value; + } + + config(config: Partial) { + type NodeConfigKey = keyof NodeConfig; + + for (const key of Object.keys(config) as NodeConfigKey[]) { + const updateValue = config[key]; + + if (updateValue === undefined) { + continue; + } + + this.updateConfig(key, updateValue); + } + + return this; + } + } + + // `Partial`` allows us to provide only a part of the + // NodeConfig interface. + new NodeAppBuilder().config({appName: 'ToDoApp'}); + ``` +
+ +- [`Required`](https://github.com/Microsoft/TypeScript/blob/2961bc3fc0ea1117d4e53bc8e97fa76119bc33e3/src/lib/es5.d.ts#L1408-L1413) - Make all properties in `T` required. +
+ + Example + + + [Playground](https://typescript-play.js.org/?target=6#code/AQ4SwOwFwUwJwGYEMDGNgGED21VQGJZwC2wA3gFCjXAzFJgA2A-AFzADOUckA5gNxUaIYjA4ckvGG07c+g6gF8KQkAgCuEFFDA5O6gEbEwUbLm2ESwABQIixACJIoSdgCUYAR3Vg4MACYAPGYuFvYAfACU5Ko0APRxwADKMBD+wFAAFuh2Vv7OSBlYGdmc8ABu8LHKsRyGxqY4oQT21pTCIHQMjOwA5DAAHgACxAAOjDAAdChYxL0ANLHUouKSMH0AEmAAhJhY6ozpAJ77GTCMjMCiV0ToSAb7UJPPC9WRgrEJwAAqR6MwSRQPFGUFocDgRHYxnEfGAowh-zgUCOwF6KwkUl6tXqJhCeEsxDaS1AXSYfUGI3GUxmc0WSneQA) + + ```ts + interface ContactForm { + email?: string; + message?: string; + } + + function submitContactForm(formData: Required) { + // Send the form data to the server. + } + + submitContactForm({ + email: 'ex@mple.com', + message: 'Hi! Could you tell me more about…', + }); + + // TypeScript error: missing property 'message' + submitContactForm({ + email: 'ex@mple.com', + }); + ``` +
+ +- [`Readonly`](https://github.com/Microsoft/TypeScript/blob/2961bc3fc0ea1117d4e53bc8e97fa76119bc33e3/src/lib/es5.d.ts#L1415-L1420) - Make all properties in `T` readonly. +
+ + Example + + + [Playground](https://typescript-play.js.org/?target=6#code/AQ4UwOwVwW2AZA9gc3mAbmANsA3gKFCOAHkAzMgGkOJABEwAjKZa2kAUQCcvEu32AMQCGAF2FYBIAL4BufDRABLCKLBcywgMZgEKZOoDCiCGSXI8i4hGEwwALmABnUVxXJ57YFgzZHSVF8sT1BpBSItLGEnJz1kAy5LLy0TM2RHACUwYQATEywATwAeAITjU3MAPnkrCJMXLigtUT4AClxgGztKbyDgaX99I1TzAEokr1BRAAslJwA6FIqLAF48TtswHp9MHDla9hJGACswZvmyLjAwAC8wVpm5xZHkUZDaMKIwqyWXYCW0oN4sNlsA1h0ug5gAByACyBQAggAHJHQ7ZBIFoXbzBjMCz7OoQP5YIaJNYQMAAdziCVaALGNSIAHomcAACoFJFgADKWjcSNEwG4vC4ji0wggEEQguiTnMEGALWAV1yAFp8gVgEjeFyuKICvMrCTgVxnst5jtsGC4ljsPNhXxGaAWcAAOq6YRXYDCRg+RWIcA5JSC+kWdCepQ+v3RYCU3RInzRMCGwlpC19NYBW1Ye08R1AA) + + ```ts + enum LogLevel { + Off, + Debug, + Error, + Fatal + }; + + interface LoggerConfig { + name: string; + level: LogLevel; + } + + class Logger { + config: Readonly; + + constructor({name, level}: LoggerConfig) { + this.config = {name, level}; + Object.freeze(this.config); + } + } + + const config: LoggerConfig = { + name: 'MyApp', + level: LogLevel.Debug + }; + + const logger = new Logger(config); + + // TypeScript Error: cannot assign to read-only property. + logger.config.level = LogLevel.Error; + + // We are able to edit config variable as we please. + config.level = LogLevel.Error; + ``` +
+ +- [`Pick`](https://github.com/Microsoft/TypeScript/blob/2961bc3fc0ea1117d4e53bc8e97fa76119bc33e3/src/lib/es5.d.ts#L1422-L1427) - From `T`, pick a set of properties whose keys are in the union `K`. +
+ + Example + + + [Playground](https://typescript-play.js.org/?target=6#code/AQ4SwOwFwUwJwGYEMDGNgEE5TCgNugN4BQoZwOUBAXMAM5RyQDmA3KeSFABYCuAtgCMISMHloMmENh04oA9tBjQJjFuzIBfYrOAB6PcADCcGElh1gEGAHcKATwAO6ebyjB5CTNlwFwSxFR0BX5HeToYABNgBDh5fm8cfBg6AHIKG3ldA2BHOOcfFNpUygJ0pAhokr4hETFUgDpswywkggAFUwA3MFtgAF5gQgowKhhVKTYKGuFRcXo1aVZgbTIoJ3RW3xhOmB6+wfbcAGsAHi3kgBpgEtGy4AAfG54BWfqAPnZm4AAlZUj4MAkMA8GAGB4vEgfMlLLw6CwPBA8PYRmMgZVgAC6CgmI4cIommQELwICh8RBgKZKvALh1ur0bHQABR5PYMui0Wk7em2ADaAF0AJS0AASABUALIAGQAogR+Mp3CROCAFBBwVC2ikBpj5CgBIqGjizLA5TAFdAmalImAuqlBRoVQh5HBgEy1eDWfs7J5cjzGYKhroVfpDEhHM4MV6GRR5NN0JrtnRg6BVirTFBeHAKYmYY6QNpdB73LmCJZBlSAXAubtvczeSmQMNSuMbmKNgBlHFgPEUNwusBIPAAQlS1xetTmxT0SDoESgdD0C4aACtHMwxytLrohawgA) + + ```ts + interface Article { + title: string; + thumbnail: string; + content: string; + } + + // Creates new type out of the `Article` interface composed + // from the Articles' two properties: `title` and `thumbnail`. + // `ArticlePreview = {title: string; thumbnail: string}` + type ArticlePreview = Pick; + + // Render a list of articles using only title and description. + function renderArticlePreviews(previews: ArticlePreview[]): HTMLElement { + const articles = document.createElement('div'); + + for (const preview of previews) { + // Append preview to the articles. + } + + return articles; + } + + const articles = renderArticlePreviews([ + { + title: 'TypeScript tutorial!', + thumbnail: '/assets/ts.jpg' + } + ]); + ``` +
+ +- [`Record`](https://github.com/Microsoft/TypeScript/blob/2961bc3fc0ea1117d4e53bc8e97fa76119bc33e3/src/lib/es5.d.ts#L1429-L1434) - Construct a type with a set of properties `K` of type `T`. +
+ + Example + + + [Playground](https://typescript-play.js.org/?target=6#code/AQ4ejYAUHsGcCWAXBMB2dgwGbAKYC2ADgDYwCeeemCaWArgE7ADGMxAhmuQHQBQoYEnJE8wALKEARnkaxEKdMAC8wAOS0kstGuAAfdQBM8ANzxlRjXQbVaWACwC0JPB0NqA3HwGgIwAJJoWozYHCxixnAsjAhStADmwESMMJYo1Fi4HMCIaPEu+MRklHj8gpqyoeHAAKJFFFTAAN4+giDYCIxwSAByHAR4AFw5SDF5Xm2gJBzdfQPD3WPxE5PAlBxdAPLYNQAelgh4aOHDaPQEMowrIAC+3oJ+AMKMrlrAXFhSAFZ4LEhC9g4-0BmA4JBISXgiCkBQABpILrJ5MhUGhYcATGD6Bk4Hh-jNgABrPDkOBlXyQAAq9ngYmJpOAAHcEOCRjAXqwYODfoo6DhakUSph+Uh7GI4P0xER4Cj0OSQGwMP8tP1hgAlX7swwAHgRl2RvIANALSA08ABtAC6AD4VM1Wm0Kow0MMrYaHYJjGYLLJXZb3at1HYnC43Go-QHQDcvA6-JsmEJXARgCDgMYWAhjIYhDAU+YiMAAFIwex0ZmilMITCGF79TLAGRsAgJYAAZRwSEZGzEABFTOZUrJ5Yn+jwnWgeER6HB7AAKJrADpdXqS4ZqYultTG6azVfqHswPBbtauLY7fayQ7HIbAAAMwBuAEoYw9IBq2Ixs9h2eFMOQYPQObALQKJgggABeYhghCIpikkKRpOQRIknAsZUiIeCttECBEP8NSMCkjDDAARMGziuIYxHwYOjDCMBmDNnAuTxA6irdCOBB1Lh5Dqpqn66tISIykawBnOCtqqC0gbjqc9DgpGkxegOliyfJDrRkAA) + + ```ts + // Positions of employees in our company. + type MemberPosition = 'intern' | 'developer' | 'tech-lead'; + + // Interface describing properties of a single employee. + interface Employee { + firstName: string; + lastName: string; + yearsOfExperience: number; + } + + // Create an object that has all possible `MemberPosition` values set as keys. + // Those keys will store a collection of Employees of the same position. + const team: Record = { + intern: [], + developer: [], + 'tech-lead': [], + }; + + // Our team has decided to help John with his dream of becoming Software Developer. + team.intern.push({ + firstName: 'John', + lastName: 'Doe', + yearsOfExperience: 0 + }); + + // `Record` forces you to initialize all of the property keys. + // TypeScript Error: "tech-lead" property is missing + const teamEmpty: Record = { + intern: null, + developer: null, + }; + ``` +
+ +- [`Exclude`](https://github.com/Microsoft/TypeScript/blob/2961bc3fc0ea1117d4e53bc8e97fa76119bc33e3/src/lib/es5.d.ts#L1436-L1439) - Exclude from `T` those types that are assignable to `U`. +
+ + Example + + + [Playground](https://typescript-play.js.org/?target=6#code/JYOwLgpgTgZghgYwgAgMrQG7QMIHsQzADmyA3gFDLIAOuUYAXMiAK4A2byAPsgM5hRQJHqwC2AI2gBucgF9y5MAE9qKAEoQAjiwj8AEnBAATNtGQBeZAAooWphu26wAGmS3e93bRC8IASgsAPmRDJRlyAHoI5ABRAA8ENhYjFFYOZGVVZBgoXFFkAAM0zh5+QRBhZhYJaAKAOkjogEkQZAQ4X2QAdwALCFbaemRgXmQtFjhOMFwq9K6ULuB0lk6U+HYwZAxJnQaYFhAEMGB8ZCIIMAAFOjAANR2IK0HGWISklIAedCgsKDwCYgAbQA5M9gQBdVzFQJ+JhiSRQMiUYYwayZCC4VHPCzmSzAspCYEBWxgFhQAZwKC+FpgJ43VwARgADH4ZFQSWSBjcZPJyPtDsdTvxKWBvr8rD1DCZoJ5HPopaYoK4EPhCEQmGKcKriLCtrhgEYkVQVT5Nr4fmZLLZtMBbFZgT0wGBqES6ghbHBIJqoBKFdBWQpjfh+DQbhY2tqiHVsbjLMVkAB+ZAAZiZaeQTHOVxu9ySjxNaujNwDVHNvzqbBGkBAdPoAfkQA) + + ```ts + interface ServerConfig { + port: null | string | number; + } + + type RequestHandler = (request: Request, response: Response) => void; + + // Exclude `null` type from `null | string | number`. + // In case the port is equal to `null`, we will use default value. + function getPortValue(port: Exclude): number { + if (typeof port === 'string') { + return parseInt(port, 10); + } + + return port; + } + + function startServer(handler: RequestHandler, config: ServerConfig): void { + const server = require('http').createServer(handler); + + const port = config.port === null ? 3000 : getPortValue(config.port); + server.listen(port); + } + ``` +
+ +- [`Extract`](https://github.com/Microsoft/TypeScript/blob/2961bc3fc0ea1117d4e53bc8e97fa76119bc33e3/src/lib/es5.d.ts#L1441-L1444) - Extract from `T` those types that are assignable to `U`. +
+ + Example + + + [Playground](https://typescript-play.js.org/?target=6#code/CYUwxgNghgTiAEAzArgOzAFwJYHtXzSwEdkQBJYACgEoAueVZAWwCMQYBuAKDDwGcM8MgBF4AXngBlAJ6scESgHIRi6ty5ZUGdoihgEABXZ888AN5d48ANoiAuvUat23K6ihMQ9ATE0BzV3goPy8GZjZOLgBfLi4Aejj4AEEICBwAdz54MAALKFQQ+BxEeAAHY1NgKAwoIKy0grr4DByEUpgccpgMaXgAaxBerCzi+B9-ZulygDouFHRsU1z8kKMYE1RhaqgAHkt4AHkWACt4EAAPbVRgLLWNgBp9gGlBs8uQa6yAUUuYPQwdgNpKM7nh7mMML4CgA+R5WABqUAgpDeVxuhxO1he0jsXGh8EoOBO9COx3BQPo2PBADckaR6IjkSA6PBqTgsMBzPsicdrEC7OJWXSQNwYvFEgAVTS9JLXODpeDpKBZFg4GCoWa8VACIJykAKiQWKy2YQOAioYikCg0OEMDyhRSy4DyxS24KhAAMjyi6gS8AAwjh5OD0iBFHAkJoEOksC1mnkMJq8gUQKDNttKPlnfrwYp3J5XfBHXqoKpfYkAOI4ansTxaeDADmoRSCCBYAbxhC6TDx6rwYHIRX5bScjA4bLJwoDmDwDkfbA9JMrVMVdM1TN69LgkTgwgkchUahqIA) + + ```ts + declare function uniqueId(): number; + + const ID = Symbol('ID'); + + interface Person { + [ID]: number; + name: string; + age: number; + } + + // Allows changing the person data as long as the property key is of string type. + function changePersonData< + Obj extends Person, + Key extends Extract, + Value extends Obj[Key] + > (obj: Obj, key: Key, value: Value): void { + obj[key] = value; + } + + // Tiny Andrew was born. + const andrew = { + [ID]: uniqueId(), + name: 'Andrew', + age: 0, + }; + + // Cool, we're fine with that. + changePersonData(andrew, 'name', 'Pony'); + + // Goverment didn't like the fact that you wanted to change your identity. + changePersonData(andrew, ID, uniqueId()); + ``` +
+ +- [`NonNullable`](https://github.com/Microsoft/TypeScript/blob/2961bc3fc0ea1117d4e53bc8e97fa76119bc33e3/src/lib/es5.d.ts#L1446-L1449) - Exclude `null` and `undefined` from `T`. +
+ + Example + + Works with strictNullChecks set to true. (Read more here) + + [Playground](https://typescript-play.js.org/?target=6#code/C4TwDgpgBACg9gJ2AOQK4FsBGEFQLxQDOwCAlgHYDmUAPlORtrnQwDasDcAUFwPQBU-WAEMkUOADMowqAGNWwwoSgATCBIqlgpOOSjAAFsOBRSy1IQgr9cKJlSlW1mZYQA3HFH68u8xcoBlHA8EACEHJ08Aby4oKDBUTFZSWXjEFEYcAEIALihkXTR2YSSIAB54JDQsHAA+blj4xOTUsHSACkMzPKD3HHDHNQQAGjSkPMqMmoQASh7g-oihqBi4uNIpdraxPAI2VhmVxrX9AzMAOm2ppnwoAA4ABifuE4BfKAhWSyOTuK7CS7pao3AhXF5rV48E4ICDAVAIPT-cGQyG+XTEIgLMJLTx7CAAdygvRCA0iCHaMwarhJOIQjUBSHaACJHk8mYdeLwxtdcVAAOSsh58+lXdr7Dlcq7A3n3J4PEUdADMcspUE53OluAIUGVTx46oAKuAIAFZGQwCYAKIIBCILjUxaDHAMnla+iodjcIA) + + ```ts + type PortNumber = string | number | null; + + /** Part of a class definition that is used to build a server */ + class ServerBuilder { + portNumber!: NonNullable; + + port(this: ServerBuilder, port: PortNumber): ServerBuilder { + if (port == null) { + this.portNumber = 8000; + } else { + this.portNumber = port; + } + + return this; + } + } + + const serverBuilder = new ServerBuilder(); + + serverBuilder + .port('8000') // portNumber = '8000' + .port(null) // portNumber = 8000 + .port(3000); // portNumber = 3000 + + // TypeScript error + serverBuilder.portNumber = null; + ``` +
+ +- [`Parameters`](https://github.com/Microsoft/TypeScript/blob/2961bc3fc0ea1117d4e53bc8e97fa76119bc33e3/src/lib/es5.d.ts#L1451-L1454) - Obtain the parameters of a function type in a tuple. +
+ + Example + + + [Playground](https://typescript-play.js.org/?target=6#code/GYVwdgxgLglg9mABAZwBYmMANgUwBQxgAOIUAXIgIZgCeA2gLoCUFAbnDACaIDeAUIkQB6IYgCypSlBxUATrMo1ECsJzgBbLEoipqAc0J7EMKMgDkiHLnU4wp46pwAPHMgB0fAL58+oSLARECEosLAA5ABUYG2QAHgAxJGdpVWREPDdMylk9ZApqemZEAF4APipacrw-CApEgBogkKwAYThwckQwEHUAIxxZJl4BYVEImiIZKF0oZRwiWVdbeygJmThgOYgcGFYcbhqApCJsyhtpWXcR1cnEePBoeDAABVPzgbTixFeFd8uEsClADcIxGiygIFkSEOT3SmTc2VydQeRx+ZxwF2QQ34gkEwDgsnSuFmMBKiAADEDjIhYk1Qm0OlSYABqZnYka4xA1DJZHJYkGc7yCbyeRA+CAIZCzNAYbA4CIAdxg2zJwVCkWirjwMswuEaACYmCCgA) + + ```ts + function shuffle(input: any[]): void { + // Mutate array randomly changing its' elements indexes. + } + + function callNTimes any> (func: Fn, callCount: number) { + // Type that represents the type of the received function parameters. + type FunctionParameters = Parameters; + + return function (...args: FunctionParameters) { + for (let i = 0; i < callCount; i++) { + func(...args); + } + } + } + + const shuffleTwice = callNTimes(shuffle, 2); + ``` +
+ +- [`ConstructorParameters`](https://github.com/Microsoft/TypeScript/blob/2961bc3fc0ea1117d4e53bc8e97fa76119bc33e3/src/lib/es5.d.ts#L1456-L1459) - Obtain the parameters of a constructor function type in a tuple. +
+ + Example + + + [Playground](https://typescript-play.js.org/?target=6#code/MYGwhgzhAECCBOAXAlqApgWQPYBM0mgG8AoaaFRENALmgkXmQDsBzAblOmCycTV4D8teo1YdO3JiICuwRFngAKClWENmLAJRFOZRAAtkEAHQq00ALzlklNBzIBfYk+KhIMAJJTEYJsDQAwmDA+mgAPAAq0GgAHnxMODCKTGgA7tCKxllg8CwQtL4AngDaALraFgB80EWa1SRkAA6MAG5gfNAB4FABPDJyCrQR9tDNyG0dwMGhtBhgjWEiGgA00F70vv4RhY3hEZXVVinpc42KmuJkkv3y8Bly8EPaDWTkhiZd7r3e8LK3llwGCMXGQWGhEOsfH5zJlsrl8p0+gw-goAAo5MAAW3BaHgEEilU0tEhmzQ212BJ0ry4SOg+kg+gBBiMximIGA0nAfAQLGk2N4EAAEgzYcYcnkLsRdDTvNEYkYUKwSdCme9WdM0MYwYhFPSIPpJdTkAAzDKxBUaZX+aAAQgsVmkCTQxuYaBw2ng4Ok8CYcotSu8pMur09iG9vuObxZnx6SN+AyUWTF8MN0CcZE4Ywm5jZHK5aB5fP4iCFIqT4oRRTKRLo6lYVNeAHpG50wOzOe1zHr9NLQ+HoABybsD4HOKXXRA1JCoKhBELmI5pNaB6Fz0KKBAodDYPAgSUTmqYsAALx4m5nC6nW9nGq14KtaEUA9gR9PvuNCjQ9BgACNvcwNBtAcLiAA) + + ```ts + class ArticleModel { + title: string; + content?: string; + + constructor(title: string) { + this.title = title; + } + } + + class InstanceCache any)> { + private ClassConstructor: T; + private cache: Map> = new Map(); + + constructor (ctr: T) { + this.ClassConstructor = ctr; + } + + getInstance (...args: ConstructorParameters): InstanceType { + const hash = this.calculateArgumentsHash(...args); + + const existingInstance = this.cache.get(hash); + if (existingInstance !== undefined) { + return existingInstance; + } + + return new this.ClassConstructor(...args); + } + + private calculateArgumentsHash(...args: any[]): string { + // Calculate hash. + return 'hash'; + } + } + + const articleCache = new InstanceCache(ArticleModel); + const amazonArticle = articleCache.getInstance('Amazon forests burining!'); + ``` +
+ +- [`ReturnType`](https://github.com/Microsoft/TypeScript/blob/2961bc3fc0ea1117d4e53bc8e97fa76119bc33e3/src/lib/es5.d.ts#L1461-L1464) – Obtain the return type of a function type. +
+ + Example + + + [Playground](https://typescript-play.js.org/?target=6#code/MYGwhgzhAECSAmICmBlJAnAbgS2E6A3gFDTTwD2AcuQC4AW2AdgOYAUAlAFzSbnbyEAvkWFFQkGJSQB3GMVI1sNZNwg10TZgG4S0YOUY0kh1es07d+xmvQBXYDXLpWi5UlMaWAGj0GjJ6BtNdkJdBQYIADpXZGgAXmgYpB1ScOwoq38aeN9DYxoU6GFRKzVoJjUwRjwAYXJbPPRuAFkwAAcAHgAxBodsAx9GWwBbACMMAD4cxhloVraOCyYjdAAzMDxoOut1e0d0UNIZ6WhWSPOwdGYIbiqATwBtAF0uaHudUQB6ACpv6ABpJBINqJdAbADW0Do5BOw3u5R2VTwMHIq2gAANtjZ0bkbHsnFCwJh8ONjHp0EgwEZ4JFoN9PkRVr1FAZoMwkDRYIjqkgOrosepoEgAB7+eAwAV2BxOLy6ACCVxgIrFEoMeOl6AACpcwMMORgIB1JRMiBNWKVdhruJKfOdIpdrtwFddXlzKjyACp3Nq842HaDIbL6BrZBIVGhIpB1EMYSLsmjmtWW-YhAA+qegAAYLKQLQj3ZsEsdccmnGcLor2Dn8xGedHGpEIBzEzspfsfMHDNAANTQACMVaIljV5GQkRA5DYmIpVKQAgAJARO9le33BDXIyi0YuLW2nJFGLqkOvxFB0YPdBSaLZ0IwNzyPkO8-xkGgsLh8Al427a3hWAhXwwHA8EHT5PmgAB1bAQBAANJ24adKWpft72RaBUTgRBUCAj89HAM8xCTaBjggABRQx0DuHJv25P9dCkWRZVIAAiBjoFImpmjlFBgA0NpsjadByDacgIDAEAIAAQmYpjoGYgAZSBsmGPw6DtZiiFA8CoJguDmAQmoZ2QvtUKQLdoAYmBTwgdEiCAA) + + ```ts + /** Provides every element of the iterable `iter` into the `callback` function and stores the results in an array. */ + function mapIter< + Elem, + Func extends (elem: Elem) => any, + Ret extends ReturnType + >(iter: Iterable, callback: Func): Ret[] { + const mapped: Ret[] = []; + + for (const elem of iter) { + mapped.push(callback(elem)); + } + + return mapped; + } + + const setObject: Set = new Set(); + const mapObject: Map = new Map(); + + mapIter(setObject, (value: string) => value.indexOf('Foo')); // number[] + + mapIter(mapObject, ([key, value]: [number, string]) => { + return key % 2 === 0 ? value : 'Odd'; + }); // string[] + ``` +
+ +- [`InstanceType`](https://github.com/Microsoft/TypeScript/blob/2961bc3fc0ea1117d4e53bc8e97fa76119bc33e3/src/lib/es5.d.ts#L1466-L1469) – Obtain the instance type of a constructor function type. +
+ + Example + + + [Playground](https://typescript-play.js.org/?target=6#code/MYGwhgzhAECSAmICmBlJAnAbgS2E6A3gFDTTwD2AcuQC4AW2AdgOYAUAlAFzSbnbyEAvkWFFQkGJSQB3GMVI1sNZNwg10TZgG4S0YOUY0kh1es07d+xmvQBXYDXLpWi5UlMaWAGj0GjJ6BtNdkJdBQYIADpXZGgAXmgYpB1ScOwoq38aeN9DYxoU6GFRKzVoJjUwRjwAYXJbPPRuAFkwAAcAHgAxBodsAx9GWwBbACMMAD4cxhloVraOCyYjdAAzMDxoOut1e0d0UNIZ6WhWSPOwdGYIbiqATwBtAF0uaHudUQB6ACpv6ABpJBINqJdAbADW0Do5BOw3u5R2VTwMHIq2gAANtjZ0bkbHsnFCwJh8ONjHp0EgwEZ4JFoN9PkRVr1FAZoMwkDRYIjqkgOrosepoEgAB7+eAwAV2BxOLy6ACCVxgIrFEoMeOl6AACpcwMMORgIB1JRMiBNWKVdhruJKfOdIpdrtwFddXlzKjyACp3Nq842HaDIbL6BrZBIVGhIpB1EMYSLsmjmtWW-YhAA+qegAAYLKQLQj3ZsEsdccmnGcLor2Dn8xGedHGpEIBzEzspfsfMHDNAANTQACMVaIljV5GQkRA5DYmIpVKQAgAJARO9le33BDXIyi0YuLW2nJFGLqkOvxFB0YPdBSaLZ0IwNzyPkO8-xkGgsLh8Al427a3hWAhXwwHA8EHT5PmgAB1bAQBAANJ24adKWpft72RaBUTgRBUCAj89HAM8xCTaBjggABRQx0DuHJv25P9dCkWRZVIAAiBjoFImpmjlFBgA0NpsjadByDacgIDAEAIAAQmYpjoGYgAZSBsmGPw6DtZiiFA8CoJguDmAQmoZ2QvtUKQLdoAYmBTwgdEiCAA) + + ```ts + class IdleService { + doNothing (): void {} + } + + class News { + title: string; + content: string; + + constructor(title: string, content: string) { + this.title = title; + this.content = content; + } + } + + const instanceCounter: Map = new Map(); + + interface Constructor { + new(...args: any[]): any; + } + + // Keep track how many instances of `Constr` constructor have been created. + function getInstance< + Constr extends Constructor, + Args extends ConstructorParameters + >(constructor: Constr, ...args: Args): InstanceType { + let count = instanceCounter.get(constructor) || 0; + + const instance = new constructor(...args); + + instanceCounter.set(constructor, count + 1); + + console.log(`Created ${count + 1} instances of ${Constr.name} class`); + + return instance; + } + + + const idleService = getInstance(IdleService); + // Will log: `Created 1 instances of IdleService class` + const newsEntry = getInstance(News, 'New ECMAScript proposals!', 'Last month...'); + // Will log: `Created 1 instances of News class` + ``` +
+ +- [`Omit`](https://github.com/microsoft/TypeScript/blob/71af02f7459dc812e85ac31365bfe23daf14b4e4/src/lib/es5.d.ts#L1446) – Constructs a type by picking all properties from T and then removing K. +
+ + Example + + + [Playground](https://typescript-play.js.org/?target=6#code/JYOwLgpgTgZghgYwgAgIImAWzgG2QbwChlks4BzCAVShwC5kBnMKUcgbmKYAcIFgIjBs1YgOXMpSFMWbANoBdTiW5woFddwAW0kfKWEAvoUIB6U8gDCUCHEiNkICAHdkYAJ69kz4GC3JcPG4oAHteKDABBxCYNAxsPFBIWEQUCAAPJG4wZABySUFcgJAAEzMLXNV1ck0dIuCw6EjBADpy5AB1FAQ4EGQAV0YUP2AHDy8wEOQbUugmBLwtEIA3OcmQnEjuZBgQqE7gAGtgZAhwKHdkHFGwNvGUdDIcAGUliIBJEF3kAF5kAHlML4ADyPBIAGjyBUYRQAPnkqho4NoYQA+TiEGD9EAISIhPozErQMG4AASK2gn2+AApek9pCSXm8wFSQooAJQMUkAFQAsgAZACiOAgmDOOSIJAQ+OYyGl4DgoDmf2QJRCCH6YvALQQNjsEGFovF1NyJWAy1y7OUyHMyE+yRAuFImG4Iq1YDswHxbRINjA-SgfXlHqVUE4xiAA) + + ```ts + interface Animal { + imageUrl: string; + species: string; + images: string[]; + paragraphs: string[]; + } + + // Creates new type with all properties of the `Animal` interface + // except 'images' and 'paragraphs' properties. We can use this + // type to render small hover tooltip for a wiki entry list. + type AnimalShortInfo = Omit; + + function renderAnimalHoverInfo (animals: AnimalShortInfo[]): HTMLElement { + const container = document.createElement('div'); + // Internal implementation. + return container; + } + ``` +
+ +- [`Uppercase`](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-4-1.html#template-literal-types) - Transforms every character in a string into uppercase. +
+ + Example + + + ```ts + type T = Uppercase<'hello'>; // 'HELLO' + + type T2 = Uppercase<'foo' | 'bar'>; // 'FOO' | 'BAR' + + type T3 = Uppercase<`aB${S}`>; + type T4 = T30<'xYz'>; // 'ABXYZ' + + type T5 = Uppercase; // string + type T6 = Uppercase; // any + type T7 = Uppercase; // never + type T8 = Uppercase<42>; // Error, type 'number' does not satisfy the constraint 'string' + ``` +
+ +- [`Lowercase`](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-4-1.html#template-literal-types) - Transforms every character in a string into lowercase. +
+ + Example + + + ```ts + type T = Lowercase<'HELLO'>; // 'hello' + + type T2 = Lowercase<'FOO' | 'BAR'>; // 'foo' | 'bar' + + type T3 = Lowercase<`aB${S}`>; + type T4 = T32<'xYz'>; // 'abxyz' + + type T5 = Lowercase; // string + type T6 = Lowercase; // any + type T7 = Lowercase; // never + type T8 = Lowercase<42>; // Error, type 'number' does not satisfy the constraint 'string' + ``` +
+ +- [`Capitalize`](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-4-1.html#template-literal-types) - Transforms the first character in a string into uppercase. +
+ + Example + + + ```ts + type T = Capitalize<'hello'>; // 'Hello' + + type T2 = Capitalize<'foo' | 'bar'>; // 'Foo' | 'Bar' + + type T3 = Capitalize<`aB${S}`>; + type T4 = T32<'xYz'>; // 'ABxYz' + + type T5 = Capitalize; // string + type T6 = Capitalize; // any + type T7 = Capitalize; // never + type T8 = Capitalize<42>; // Error, type 'number' does not satisfy the constraint 'string' + ``` +
+ +- [`Uncapitalize`](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-4-1.html#template-literal-types) - Transforms the first character in a string into lowercase. +
+ + Example + + + ```ts + type T = Uncapitalize<'Hello'>; // 'hello' + + type T2 = Uncapitalize<'Foo' | 'Bar'>; // 'foo' | 'bar' + + type T3 = Uncapitalize<`AB${S}`>; + type T4 = T30<'xYz'>; // 'aBxYz' + + type T5 = Uncapitalize; // string + type T6 = Uncapitalize; // any + type T7 = Uncapitalize; // never + type T8 = Uncapitalize<42>; // Error, type 'number' does not satisfy the constraint 'string' + ``` +
+ +You can find some examples in the [TypeScript docs](https://www.typescriptlang.org/docs/handbook/advanced-types.html#predefined-conditional-types). + +## Maintainers + +- [Sindre Sorhus](https://github.com/sindresorhus) +- [Jarek Radosz](https://github.com/CvX) +- [Dimitri Benin](https://github.com/BendingBender) +- [Pelle Wessman](https://github.com/voxpelli) + +## License + +(MIT OR CC0-1.0) + +--- + +
+ + Get professional support for this package with a Tidelift subscription + +
+ + Tidelift helps make open source sustainable for maintainers while giving companies
assurances about security, maintenance, and licensing for their dependencies. +
+
diff --git a/node_modules/ansi-escapes/node_modules/type-fest/source/async-return-type.d.ts b/node_modules/ansi-escapes/node_modules/type-fest/source/async-return-type.d.ts new file mode 100644 index 0000000000000000000000000000000000000000..79ec1e9612606c34a7c39b995f10ccd4afc0da30 --- /dev/null +++ b/node_modules/ansi-escapes/node_modules/type-fest/source/async-return-type.d.ts @@ -0,0 +1,23 @@ +import {PromiseValue} from './promise-value'; + +type AsyncFunction = (...args: any[]) => Promise; + +/** +Unwrap the return type of a function that returns a `Promise`. + +There has been [discussion](https://github.com/microsoft/TypeScript/pull/35998) about implementing this type in TypeScript. + +@example +```ts +import {AsyncReturnType} from 'type-fest'; +import {asyncFunction} from 'api'; + +// This type resolves to the unwrapped return type of `asyncFunction`. +type Value = AsyncReturnType; + +async function doSomething(value: Value) {} + +asyncFunction().then(value => doSomething(value)); +``` +*/ +export type AsyncReturnType = PromiseValue>; diff --git a/node_modules/ansi-escapes/node_modules/type-fest/source/asyncify.d.ts b/node_modules/ansi-escapes/node_modules/type-fest/source/asyncify.d.ts new file mode 100644 index 0000000000000000000000000000000000000000..455f2ebda52425a2f59569a15bfd2876fa0e35bf --- /dev/null +++ b/node_modules/ansi-escapes/node_modules/type-fest/source/asyncify.d.ts @@ -0,0 +1,31 @@ +import {PromiseValue} from './promise-value'; +import {SetReturnType} from './set-return-type'; + +/** +Create an async version of the given function type, by boxing the return type in `Promise` while keeping the same parameter types. + +Use-case: You have two functions, one synchronous and one asynchronous that do the same thing. Instead of having to duplicate the type definition, you can use `Asyncify` to reuse the synchronous type. + +@example +``` +import {Asyncify} from 'type-fest'; + +// Synchronous function. +function getFooSync(someArg: SomeType): Foo { + // … +} + +type AsyncifiedFooGetter = Asyncify; +//=> type AsyncifiedFooGetter = (someArg: SomeType) => Promise; + +// Same as `getFooSync` but asynchronous. +const getFooAsync: AsyncifiedFooGetter = (someArg) => { + // TypeScript now knows that `someArg` is `SomeType` automatically. + // It also knows that this function must return `Promise`. + // If you have `@typescript-eslint/promise-function-async` linter rule enabled, it will even report that "Functions that return promises must be async.". + + // … +} +``` +*/ +export type Asyncify any> = SetReturnType>>>; diff --git a/node_modules/ansi-escapes/node_modules/type-fest/source/basic.d.ts b/node_modules/ansi-escapes/node_modules/type-fest/source/basic.d.ts new file mode 100644 index 0000000000000000000000000000000000000000..f6fba385099b6abe741d4533ba2d593253fd2d24 --- /dev/null +++ b/node_modules/ansi-escapes/node_modules/type-fest/source/basic.d.ts @@ -0,0 +1,51 @@ +/// + +// TODO: This can just be `export type Primitive = not object` when the `not` keyword is out. +/** +Matches any [primitive value](https://developer.mozilla.org/en-US/docs/Glossary/Primitive). +*/ +export type Primitive = + | null + | undefined + | string + | number + | boolean + | symbol + | bigint; + +// TODO: Remove the `= unknown` sometime in the future when most users are on TS 3.5 as it's now the default +/** +Matches a [`class` constructor](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes). +*/ +export type Class = new(...arguments_: Arguments) => T; + +/** +Matches a JSON object. + +This type can be useful to enforce some input to be JSON-compatible or as a super-type to be extended from. Don't use this as a direct return type as the user would have to double-cast it: `jsonObject as unknown as CustomResponse`. Instead, you could extend your CustomResponse type from it to ensure your type only uses JSON-compatible types: `interface CustomResponse extends JsonObject { … }`. +*/ +export type JsonObject = {[Key in string]?: JsonValue}; + +/** +Matches a JSON array. +*/ +export interface JsonArray extends Array {} + +/** +Matches any valid JSON value. +*/ +export type JsonValue = string | number | boolean | null | JsonObject | JsonArray; + +declare global { + interface SymbolConstructor { + readonly observable: symbol; + } +} + +/** +Matches a value that is like an [Observable](https://github.com/tc39/proposal-observable). +*/ +export interface ObservableLike { + subscribe(observer: (value: unknown) => void): void; + [Symbol.observable](): ObservableLike; +} diff --git a/node_modules/ansi-escapes/node_modules/type-fest/source/conditional-except.d.ts b/node_modules/ansi-escapes/node_modules/type-fest/source/conditional-except.d.ts new file mode 100644 index 0000000000000000000000000000000000000000..ac506ccf1422274aef3bebe05bcd33112ebb59d5 --- /dev/null +++ b/node_modules/ansi-escapes/node_modules/type-fest/source/conditional-except.d.ts @@ -0,0 +1,43 @@ +import {Except} from './except'; +import {ConditionalKeys} from './conditional-keys'; + +/** +Exclude keys from a shape that matches the given `Condition`. + +This is useful when you want to create a new type with a specific set of keys from a shape. For example, you might want to exclude all the primitive properties from a class and form a new shape containing everything but the primitive properties. + +@example +``` +import {Primitive, ConditionalExcept} from 'type-fest'; + +class Awesome { + name: string; + successes: number; + failures: bigint; + + run() {} +} + +type ExceptPrimitivesFromAwesome = ConditionalExcept; +//=> {run: () => void} +``` + +@example +``` +import {ConditionalExcept} from 'type-fest'; + +interface Example { + a: string; + b: string | number; + c: () => void; + d: {}; +} + +type NonStringKeysOnly = ConditionalExcept; +//=> {b: string | number; c: () => void; d: {}} +``` +*/ +export type ConditionalExcept = Except< + Base, + ConditionalKeys +>; diff --git a/node_modules/ansi-escapes/node_modules/type-fest/source/conditional-keys.d.ts b/node_modules/ansi-escapes/node_modules/type-fest/source/conditional-keys.d.ts new file mode 100644 index 0000000000000000000000000000000000000000..eb074dc5d56a93f83b11d53bc072827c6aaf754c --- /dev/null +++ b/node_modules/ansi-escapes/node_modules/type-fest/source/conditional-keys.d.ts @@ -0,0 +1,43 @@ +/** +Extract the keys from a type where the value type of the key extends the given `Condition`. + +Internally this is used for the `ConditionalPick` and `ConditionalExcept` types. + +@example +``` +import {ConditionalKeys} from 'type-fest'; + +interface Example { + a: string; + b: string | number; + c?: string; + d: {}; +} + +type StringKeysOnly = ConditionalKeys; +//=> 'a' +``` + +To support partial types, make sure your `Condition` is a union of undefined (for example, `string | undefined`) as demonstrated below. + +@example +``` +type StringKeysAndUndefined = ConditionalKeys; +//=> 'a' | 'c' +``` +*/ +export type ConditionalKeys = NonNullable< + // Wrap in `NonNullable` to strip away the `undefined` type from the produced union. + { + // Map through all the keys of the given base type. + [Key in keyof Base]: + // Pick only keys with types extending the given `Condition` type. + Base[Key] extends Condition + // Retain this key since the condition passes. + ? Key + // Discard this key since the condition fails. + : never; + + // Convert the produced object into a union type of the keys which passed the conditional test. + }[keyof Base] +>; diff --git a/node_modules/ansi-escapes/node_modules/type-fest/source/conditional-pick.d.ts b/node_modules/ansi-escapes/node_modules/type-fest/source/conditional-pick.d.ts new file mode 100644 index 0000000000000000000000000000000000000000..cecc3df14f9656e45617d6f7209de95d810139e2 --- /dev/null +++ b/node_modules/ansi-escapes/node_modules/type-fest/source/conditional-pick.d.ts @@ -0,0 +1,42 @@ +import {ConditionalKeys} from './conditional-keys'; + +/** +Pick keys from the shape that matches the given `Condition`. + +This is useful when you want to create a new type from a specific subset of an existing type. For example, you might want to pick all the primitive properties from a class and form a new automatically derived type. + +@example +``` +import {Primitive, ConditionalPick} from 'type-fest'; + +class Awesome { + name: string; + successes: number; + failures: bigint; + + run() {} +} + +type PickPrimitivesFromAwesome = ConditionalPick; +//=> {name: string; successes: number; failures: bigint} +``` + +@example +``` +import {ConditionalPick} from 'type-fest'; + +interface Example { + a: string; + b: string | number; + c: () => void; + d: {}; +} + +type StringKeysOnly = ConditionalPick; +//=> {a: string} +``` +*/ +export type ConditionalPick = Pick< + Base, + ConditionalKeys +>; diff --git a/node_modules/ansi-escapes/node_modules/type-fest/source/entries.d.ts b/node_modules/ansi-escapes/node_modules/type-fest/source/entries.d.ts new file mode 100644 index 0000000000000000000000000000000000000000..e02237a92046f6e70e6578e9a55ad01727d058ce --- /dev/null +++ b/node_modules/ansi-escapes/node_modules/type-fest/source/entries.d.ts @@ -0,0 +1,57 @@ +import {ArrayEntry, MapEntry, ObjectEntry, SetEntry} from './entry'; + +type ArrayEntries = Array>; +type MapEntries = Array>; +type ObjectEntries = Array>; +type SetEntries> = Array>; + +/** +Many collections have an `entries` method which returns an array of a given object's own enumerable string-keyed property [key, value] pairs. The `Entries` type will return the type of that collection's entries. + +For example the {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/entries|`Object`}, {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/entries|`Map`}, {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/entries|`Array`}, and {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set/entries|`Set`} collections all have this method. Note that `WeakMap` and `WeakSet` do not have this method since their entries are not enumerable. + +@see `Entry` if you want to just access the type of a single entry. + +@example +``` +import {Entries} from 'type-fest'; + +interface Example { + someKey: number; +} + +const manipulatesEntries = (examples: Entries) => examples.map(example => [ + // Does some arbitrary processing on the key (with type information available) + example[0].toUpperCase(), + + // Does some arbitrary processing on the value (with type information available) + example[1].toFixed() +]); + +const example: Example = {someKey: 1}; +const entries = Object.entries(example) as Entries; +const output = manipulatesEntries(entries); + +// Objects +const objectExample = {a: 1}; +const objectEntries: Entries = [['a', 1]]; + +// Arrays +const arrayExample = ['a', 1]; +const arrayEntries: Entries = [[0, 'a'], [1, 1]]; + +// Maps +const mapExample = new Map([['a', 1]]); +const mapEntries: Entries = [['a', 1]]; + +// Sets +const setExample = new Set(['a', 1]); +const setEntries: Entries = [['a', 'a'], [1, 1]]; +``` +*/ +export type Entries = + BaseType extends Map ? MapEntries + : BaseType extends Set ? SetEntries + : BaseType extends unknown[] ? ArrayEntries + : BaseType extends object ? ObjectEntries + : never; diff --git a/node_modules/ansi-escapes/node_modules/type-fest/source/entry.d.ts b/node_modules/ansi-escapes/node_modules/type-fest/source/entry.d.ts new file mode 100644 index 0000000000000000000000000000000000000000..db718216a7d7d0673e2f6fd39a860e1d87bc2a1d --- /dev/null +++ b/node_modules/ansi-escapes/node_modules/type-fest/source/entry.d.ts @@ -0,0 +1,60 @@ +type MapKey = BaseType extends Map ? KeyType : never; +type MapValue = BaseType extends Map ? ValueType : never; + +export type ArrayEntry = [number, BaseType[number]]; +export type MapEntry = [MapKey, MapValue]; +export type ObjectEntry = [keyof BaseType, BaseType[keyof BaseType]]; +export type SetEntry = BaseType extends Set ? [ItemType, ItemType] : never; + +/** +Many collections have an `entries` method which returns an array of a given object's own enumerable string-keyed property [key, value] pairs. The `Entry` type will return the type of that collection's entry. + +For example the {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/entries|`Object`}, {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/entries|`Map`}, {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/entries|`Array`}, and {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set/entries|`Set`} collections all have this method. Note that `WeakMap` and `WeakSet` do not have this method since their entries are not enumerable. + +@see `Entries` if you want to just access the type of the array of entries (which is the return of the `.entries()` method). + +@example +``` +import {Entry} from 'type-fest'; + +interface Example { + someKey: number; +} + +const manipulatesEntry = (example: Entry) => [ + // Does some arbitrary processing on the key (with type information available) + example[0].toUpperCase(), + + // Does some arbitrary processing on the value (with type information available) + example[1].toFixed(), +]; + +const example: Example = {someKey: 1}; +const entry = Object.entries(example)[0] as Entry; +const output = manipulatesEntry(entry); + +// Objects +const objectExample = {a: 1}; +const objectEntry: Entry = ['a', 1]; + +// Arrays +const arrayExample = ['a', 1]; +const arrayEntryString: Entry = [0, 'a']; +const arrayEntryNumber: Entry = [1, 1]; + +// Maps +const mapExample = new Map([['a', 1]]); +const mapEntry: Entry = ['a', 1]; + +// Sets +const setExample = new Set(['a', 1]); +const setEntryString: Entry = ['a', 'a']; +const setEntryNumber: Entry = [1, 1]; +``` +*/ +export type Entry = + BaseType extends Map ? MapEntry + : BaseType extends Set ? SetEntry + : BaseType extends unknown[] ? ArrayEntry + : BaseType extends object ? ObjectEntry + : never; diff --git a/node_modules/ansi-escapes/node_modules/type-fest/source/except.d.ts b/node_modules/ansi-escapes/node_modules/type-fest/source/except.d.ts new file mode 100644 index 0000000000000000000000000000000000000000..7dedbaa4a93f9d214d9a105087914556a7992e84 --- /dev/null +++ b/node_modules/ansi-escapes/node_modules/type-fest/source/except.d.ts @@ -0,0 +1,22 @@ +/** +Create a type from an object type without certain keys. + +This type is a stricter version of [`Omit`](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-5.html#the-omit-helper-type). The `Omit` type does not restrict the omitted keys to be keys present on the given type, while `Except` does. The benefits of a stricter type are avoiding typos and allowing the compiler to pick up on rename refactors automatically. + +Please upvote [this issue](https://github.com/microsoft/TypeScript/issues/30825) if you want to have the stricter version as a built-in in TypeScript. + +@example +``` +import {Except} from 'type-fest'; + +type Foo = { + a: number; + b: string; + c: boolean; +}; + +type FooWithoutA = Except; +//=> {b: string}; +``` +*/ +export type Except = Pick>; diff --git a/node_modules/ansi-escapes/node_modules/type-fest/source/fixed-length-array.d.ts b/node_modules/ansi-escapes/node_modules/type-fest/source/fixed-length-array.d.ts new file mode 100644 index 0000000000000000000000000000000000000000..e3bc0f473dfb0abc10b17330ee1673dc50be8d9f --- /dev/null +++ b/node_modules/ansi-escapes/node_modules/type-fest/source/fixed-length-array.d.ts @@ -0,0 +1,38 @@ +/** +Methods to exclude. +*/ +type ArrayLengthMutationKeys = 'splice' | 'push' | 'pop' | 'shift' | 'unshift'; + +/** +Create a type that represents an array of the given type and length. The array's length and the `Array` prototype methods that manipulate its length are excluded in the resulting type. + +Please participate in [this issue](https://github.com/microsoft/TypeScript/issues/26223) if you want to have a similiar type built into TypeScript. + +Use-cases: +- Declaring fixed-length tuples or arrays with a large number of items. +- Creating a range union (for example, `0 | 1 | 2 | 3 | 4` from the keys of such a type) without having to resort to recursive types. +- Creating an array of coordinates with a static length, for example, length of 3 for a 3D vector. + +@example +``` +import {FixedLengthArray} from 'type-fest'; + +type FencingTeam = FixedLengthArray; + +const guestFencingTeam: FencingTeam = ['Josh', 'Michael', 'Robert']; + +const homeFencingTeam: FencingTeam = ['George', 'John']; +//=> error TS2322: Type string[] is not assignable to type 'FencingTeam' + +guestFencingTeam.push('Sam'); +//=> error TS2339: Property 'push' does not exist on type 'FencingTeam' +``` +*/ +export type FixedLengthArray = Pick< + ArrayPrototype, + Exclude +> & { + [index: number]: Element; + [Symbol.iterator]: () => IterableIterator; + readonly length: Length; +}; diff --git a/node_modules/ansi-escapes/node_modules/type-fest/source/iterable-element.d.ts b/node_modules/ansi-escapes/node_modules/type-fest/source/iterable-element.d.ts new file mode 100644 index 0000000000000000000000000000000000000000..174cfbf4bf128f5efb73ec24e2db6b53e050ee73 --- /dev/null +++ b/node_modules/ansi-escapes/node_modules/type-fest/source/iterable-element.d.ts @@ -0,0 +1,46 @@ +/** +Get the element type of an `Iterable`/`AsyncIterable`. For example, an array or a generator. + +This can be useful, for example, if you want to get the type that is yielded in a generator function. Often the return type of those functions are not specified. + +This type works with both `Iterable`s and `AsyncIterable`s, so it can be use with synchronous and asynchronous generators. + +Here is an example of `IterableElement` in action with a generator function: + +@example +``` +function * iAmGenerator() { + yield 1; + yield 2; +} + +type MeNumber = IterableElement> +``` + +And here is an example with an async generator: + +@example +``` +async function * iAmGeneratorAsync() { + yield 'hi'; + yield true; +} + +type MeStringOrBoolean = IterableElement> +``` + +Many types in JavaScript/TypeScript are iterables. This type works on all types that implement those interfaces. For example, `Array`, `Set`, `Map`, `stream.Readable`, etc. + +An example with an array of strings: + +@example +``` +type MeString = IterableElement +``` +*/ +export type IterableElement = + TargetIterable extends Iterable ? + ElementType : + TargetIterable extends AsyncIterable ? + ElementType : + never; diff --git a/node_modules/ansi-escapes/node_modules/type-fest/source/literal-union.d.ts b/node_modules/ansi-escapes/node_modules/type-fest/source/literal-union.d.ts new file mode 100644 index 0000000000000000000000000000000000000000..8debd93d0348343213c8772428a71f6af312c62a --- /dev/null +++ b/node_modules/ansi-escapes/node_modules/type-fest/source/literal-union.d.ts @@ -0,0 +1,33 @@ +import {Primitive} from './basic'; + +/** +Allows creating a union type by combining primitive types and literal types without sacrificing auto-completion in IDEs for the literal type part of the union. + +Currently, when a union type of a primitive type is combined with literal types, TypeScript loses all information about the combined literals. Thus, when such type is used in an IDE with autocompletion, no suggestions are made for the declared literals. + +This type is a workaround for [Microsoft/TypeScript#29729](https://github.com/Microsoft/TypeScript/issues/29729). It will be removed as soon as it's not needed anymore. + +@example +``` +import {LiteralUnion} from 'type-fest'; + +// Before + +type Pet = 'dog' | 'cat' | string; + +const pet: Pet = ''; +// Start typing in your TypeScript-enabled IDE. +// You **will not** get auto-completion for `dog` and `cat` literals. + +// After + +type Pet2 = LiteralUnion<'dog' | 'cat', string>; + +const pet: Pet2 = ''; +// You **will** get auto-completion for `dog` and `cat` literals. +``` + */ +export type LiteralUnion< + LiteralType, + BaseType extends Primitive +> = LiteralType | (BaseType & {_?: never}); diff --git a/node_modules/ansi-escapes/node_modules/type-fest/source/merge-exclusive.d.ts b/node_modules/ansi-escapes/node_modules/type-fest/source/merge-exclusive.d.ts new file mode 100644 index 0000000000000000000000000000000000000000..059bd2cbe8d7c430cc735c2162a0b09c4dbbd305 --- /dev/null +++ b/node_modules/ansi-escapes/node_modules/type-fest/source/merge-exclusive.d.ts @@ -0,0 +1,39 @@ +// Helper type. Not useful on its own. +type Without = {[KeyType in Exclude]?: never}; + +/** +Create a type that has mutually exclusive keys. + +This type was inspired by [this comment](https://github.com/Microsoft/TypeScript/issues/14094#issuecomment-373782604). + +This type works with a helper type, called `Without`. `Without` produces a type that has only keys from `FirstType` which are not present on `SecondType` and sets the value type for these keys to `never`. This helper type is then used in `MergeExclusive` to remove keys from either `FirstType` or `SecondType`. + +@example +``` +import {MergeExclusive} from 'type-fest'; + +interface ExclusiveVariation1 { + exclusive1: boolean; +} + +interface ExclusiveVariation2 { + exclusive2: string; +} + +type ExclusiveOptions = MergeExclusive; + +let exclusiveOptions: ExclusiveOptions; + +exclusiveOptions = {exclusive1: true}; +//=> Works +exclusiveOptions = {exclusive2: 'hi'}; +//=> Works +exclusiveOptions = {exclusive1: true, exclusive2: 'hi'}; +//=> Error +``` +*/ +export type MergeExclusive = + (FirstType | SecondType) extends object ? + (Without & SecondType) | (Without & FirstType) : + FirstType | SecondType; + diff --git a/node_modules/ansi-escapes/node_modules/type-fest/source/merge.d.ts b/node_modules/ansi-escapes/node_modules/type-fest/source/merge.d.ts new file mode 100644 index 0000000000000000000000000000000000000000..695cb9530c98d468d10d37a96cac6ab065929379 --- /dev/null +++ b/node_modules/ansi-escapes/node_modules/type-fest/source/merge.d.ts @@ -0,0 +1,25 @@ +import {Except} from './except'; +import {Simplify} from './simplify'; + +type Merge_ = Except> & SecondType; + +/** +Merge two types into a new type. Keys of the second type overrides keys of the first type. + +@example +``` +import {Merge} from 'type-fest'; + +type Foo = { + a: number; + b: string; +}; + +type Bar = { + b: number; +}; + +const ab: Merge = {a: 1, b: 2}; +``` +*/ +export type Merge = Simplify>; diff --git a/node_modules/ansi-escapes/node_modules/type-fest/source/mutable.d.ts b/node_modules/ansi-escapes/node_modules/type-fest/source/mutable.d.ts new file mode 100644 index 0000000000000000000000000000000000000000..a465d4132e7c9d45b6b20b02cff3049471fa2bc6 --- /dev/null +++ b/node_modules/ansi-escapes/node_modules/type-fest/source/mutable.d.ts @@ -0,0 +1,38 @@ +import {Except} from './except'; +import {Simplify} from './simplify'; + +/** +Create a type that strips `readonly` from all or some of an object's keys. Inverse of `Readonly`. + +This can be used to [store and mutate options within a class](https://github.com/sindresorhus/pageres/blob/4a5d05fca19a5fbd2f53842cbf3eb7b1b63bddd2/source/index.ts#L72), [edit `readonly` objects within tests](https://stackoverflow.com/questions/50703834), [construct a `readonly` object within a function](https://github.com/Microsoft/TypeScript/issues/24509), or to define a single model where the only thing that changes is whether or not some of the keys are mutable. + +@example +``` +import {Mutable} from 'type-fest'; + +type Foo = { + readonly a: number; + readonly b: readonly string[]; // To show that only the mutability status of the properties, not their values, are affected. + readonly c: boolean; +}; + +const mutableFoo: Mutable = {a: 1, b: ['2']}; +mutableFoo.a = 3; +mutableFoo.b[0] = 'new value'; // Will still fail as the value of property "b" is still a readonly type. +mutableFoo.b = ['something']; // Will work as the "b" property itself is no longer readonly. + +type SomeMutable = Mutable; +// type SomeMutable = { +// readonly a: number; +// b: readonly string[]; // It's now mutable. The type of the property remains unaffected. +// c: boolean; // It's now mutable. +// } +``` +*/ +export type Mutable = + Simplify< + // Pick just the keys that are not mutable from the base type. + Except & + // Pick the keys that should be mutable from the base type and make them mutable by removing the `readonly` modifier from the key. + {-readonly [KeyType in keyof Pick]: Pick[KeyType]} + >; diff --git a/node_modules/ansi-escapes/node_modules/type-fest/source/opaque.d.ts b/node_modules/ansi-escapes/node_modules/type-fest/source/opaque.d.ts new file mode 100644 index 0000000000000000000000000000000000000000..20ab964e236a1c4d3e63df946436630300253af9 --- /dev/null +++ b/node_modules/ansi-escapes/node_modules/type-fest/source/opaque.d.ts @@ -0,0 +1,65 @@ +/** +Create an opaque type, which hides its internal details from the public, and can only be created by being used explicitly. + +The generic type parameter can be anything. It doesn't have to be an object. + +[Read more about opaque types.](https://codemix.com/opaque-types-in-javascript/) + +There have been several discussions about adding this feature to TypeScript via the `opaque type` operator, similar to how Flow does it. Unfortunately, nothing has (yet) moved forward: + - [Microsoft/TypeScript#15408](https://github.com/Microsoft/TypeScript/issues/15408) + - [Microsoft/TypeScript#15807](https://github.com/Microsoft/TypeScript/issues/15807) + +@example +``` +import {Opaque} from 'type-fest'; + +type AccountNumber = Opaque; +type AccountBalance = Opaque; + +// The Token parameter allows the compiler to differentiate between types, whereas "unknown" will not. For example, consider the following structures: +type ThingOne = Opaque; +type ThingTwo = Opaque; + +// To the compiler, these types are allowed to be cast to each other as they have the same underlying type. They are both `string & { __opaque__: unknown }`. +// To avoid this behaviour, you would instead pass the "Token" parameter, like so. +type NewThingOne = Opaque; +type NewThingTwo = Opaque; + +// Now they're completely separate types, so the following will fail to compile. +function createNewThingOne (): NewThingOne { + // As you can see, casting from a string is still allowed. However, you may not cast NewThingOne to NewThingTwo, and vice versa. + return 'new thing one' as NewThingOne; +} + +// This will fail to compile, as they are fundamentally different types. +const thingTwo = createNewThingOne() as NewThingTwo; + +// Here's another example of opaque typing. +function createAccountNumber(): AccountNumber { + return 2 as AccountNumber; +} + +function getMoneyForAccount(accountNumber: AccountNumber): AccountBalance { + return 4 as AccountBalance; +} + +// This will compile successfully. +getMoneyForAccount(createAccountNumber()); + +// But this won't, because it has to be explicitly passed as an `AccountNumber` type. +getMoneyForAccount(2); + +// You can use opaque values like they aren't opaque too. +const accountNumber = createAccountNumber(); + +// This will not compile successfully. +const newAccountNumber = accountNumber + 2; + +// As a side note, you can (and should) use recursive types for your opaque types to make them stronger and hopefully easier to type. +type Person = { + id: Opaque; + name: string; +}; +``` +*/ +export type Opaque = Type & {readonly __opaque__: Token}; diff --git a/node_modules/ansi-escapes/node_modules/type-fest/source/package-json.d.ts b/node_modules/ansi-escapes/node_modules/type-fest/source/package-json.d.ts new file mode 100644 index 0000000000000000000000000000000000000000..cf355d03a7ac32c6bcfd7906b9682b73345d8fc4 --- /dev/null +++ b/node_modules/ansi-escapes/node_modules/type-fest/source/package-json.d.ts @@ -0,0 +1,611 @@ +import {LiteralUnion} from './literal-union'; + +declare namespace PackageJson { + /** + A person who has been involved in creating or maintaining the package. + */ + export type Person = + | string + | { + name: string; + url?: string; + email?: string; + }; + + export type BugsLocation = + | string + | { + /** + The URL to the package's issue tracker. + */ + url?: string; + + /** + The email address to which issues should be reported. + */ + email?: string; + }; + + export interface DirectoryLocations { + [directoryType: string]: unknown; + + /** + Location for executable scripts. Sugar to generate entries in the `bin` property by walking the folder. + */ + bin?: string; + + /** + Location for Markdown files. + */ + doc?: string; + + /** + Location for example scripts. + */ + example?: string; + + /** + Location for the bulk of the library. + */ + lib?: string; + + /** + Location for man pages. Sugar to generate a `man` array by walking the folder. + */ + man?: string; + + /** + Location for test files. + */ + test?: string; + } + + export type Scripts = { + /** + Run **before** the package is published (Also run on local `npm install` without any arguments). + */ + prepublish?: string; + + /** + Run both **before** the package is packed and published, and on local `npm install` without any arguments. This is run **after** `prepublish`, but **before** `prepublishOnly`. + */ + prepare?: string; + + /** + Run **before** the package is prepared and packed, **only** on `npm publish`. + */ + prepublishOnly?: string; + + /** + Run **before** a tarball is packed (on `npm pack`, `npm publish`, and when installing git dependencies). + */ + prepack?: string; + + /** + Run **after** the tarball has been generated and moved to its final destination. + */ + postpack?: string; + + /** + Run **after** the package is published. + */ + publish?: string; + + /** + Run **after** the package is published. + */ + postpublish?: string; + + /** + Run **before** the package is installed. + */ + preinstall?: string; + + /** + Run **after** the package is installed. + */ + install?: string; + + /** + Run **after** the package is installed and after `install`. + */ + postinstall?: string; + + /** + Run **before** the package is uninstalled and before `uninstall`. + */ + preuninstall?: string; + + /** + Run **before** the package is uninstalled. + */ + uninstall?: string; + + /** + Run **after** the package is uninstalled. + */ + postuninstall?: string; + + /** + Run **before** bump the package version and before `version`. + */ + preversion?: string; + + /** + Run **before** bump the package version. + */ + version?: string; + + /** + Run **after** bump the package version. + */ + postversion?: string; + + /** + Run with the `npm test` command, before `test`. + */ + pretest?: string; + + /** + Run with the `npm test` command. + */ + test?: string; + + /** + Run with the `npm test` command, after `test`. + */ + posttest?: string; + + /** + Run with the `npm stop` command, before `stop`. + */ + prestop?: string; + + /** + Run with the `npm stop` command. + */ + stop?: string; + + /** + Run with the `npm stop` command, after `stop`. + */ + poststop?: string; + + /** + Run with the `npm start` command, before `start`. + */ + prestart?: string; + + /** + Run with the `npm start` command. + */ + start?: string; + + /** + Run with the `npm start` command, after `start`. + */ + poststart?: string; + + /** + Run with the `npm restart` command, before `restart`. Note: `npm restart` will run the `stop` and `start` scripts if no `restart` script is provided. + */ + prerestart?: string; + + /** + Run with the `npm restart` command. Note: `npm restart` will run the `stop` and `start` scripts if no `restart` script is provided. + */ + restart?: string; + + /** + Run with the `npm restart` command, after `restart`. Note: `npm restart` will run the `stop` and `start` scripts if no `restart` script is provided. + */ + postrestart?: string; + } & Record; + + /** + Dependencies of the package. The version range is a string which has one or more space-separated descriptors. Dependencies can also be identified with a tarball or Git URL. + */ + export type Dependency = Record; + + /** + Conditions which provide a way to resolve a package entry point based on the environment. + */ + export type ExportCondition = LiteralUnion< + | 'import' + | 'require' + | 'node' + | 'deno' + | 'browser' + | 'electron' + | 'react-native' + | 'default', + string + >; + + /** + Entry points of a module, optionally with conditions and subpath exports. + */ + export type Exports = + | string + | {[key in ExportCondition]: Exports} + | {[key: string]: Exports}; // eslint-disable-line @typescript-eslint/consistent-indexed-object-style + + export interface NonStandardEntryPoints { + /** + An ECMAScript module ID that is the primary entry point to the program. + */ + module?: string; + + /** + A module ID with untranspiled code that is the primary entry point to the program. + */ + esnext?: + | string + | { + [moduleName: string]: string | undefined; + main?: string; + browser?: string; + }; + + /** + A hint to JavaScript bundlers or component tools when packaging modules for client side use. + */ + browser?: + | string + | Record; + + /** + Denote which files in your project are "pure" and therefore safe for Webpack to prune if unused. + + [Read more.](https://webpack.js.org/guides/tree-shaking/) + */ + sideEffects?: boolean | string[]; + } + + export interface TypeScriptConfiguration { + /** + Location of the bundled TypeScript declaration file. + */ + types?: string; + + /** + Location of the bundled TypeScript declaration file. Alias of `types`. + */ + typings?: string; + } + + /** + An alternative configuration for Yarn workspaces. + */ + export interface WorkspaceConfig { + /** + An array of workspace pattern strings which contain the workspace packages. + */ + packages?: WorkspacePattern[]; + + /** + Designed to solve the problem of packages which break when their `node_modules` are moved to the root workspace directory - a process known as hoisting. For these packages, both within your workspace, and also some that have been installed via `node_modules`, it is important to have a mechanism for preventing the default Yarn workspace behavior. By adding workspace pattern strings here, Yarn will resume non-workspace behavior for any package which matches the defined patterns. + + [Read more](https://classic.yarnpkg.com/blog/2018/02/15/nohoist/) + */ + nohoist?: WorkspacePattern[]; + } + + /** + A workspace pattern points to a directory or group of directories which contain packages that should be included in the workspace installation process. + + The patterns are handled with [minimatch](https://github.com/isaacs/minimatch). + + @example + `docs` → Include the docs directory and install its dependencies. + `packages/*` → Include all nested directories within the packages directory, like `packages/cli` and `packages/core`. + */ + type WorkspacePattern = string; + + export interface YarnConfiguration { + /** + Used to configure [Yarn workspaces](https://classic.yarnpkg.com/docs/workspaces/). + + Workspaces allow you to manage multiple packages within the same repository in such a way that you only need to run `yarn install` once to install all of them in a single pass. + + Please note that the top-level `private` property of `package.json` **must** be set to `true` in order to use workspaces. + */ + workspaces?: WorkspacePattern[] | WorkspaceConfig; + + /** + If your package only allows one version of a given dependency, and you’d like to enforce the same behavior as `yarn install --flat` on the command-line, set this to `true`. + + Note that if your `package.json` contains `"flat": true` and other packages depend on yours (e.g. you are building a library rather than an app), those other packages will also need `"flat": true` in their `package.json` or be installed with `yarn install --flat` on the command-line. + */ + flat?: boolean; + + /** + Selective version resolutions. Allows the definition of custom package versions inside dependencies without manual edits in the `yarn.lock` file. + */ + resolutions?: Dependency; + } + + export interface JSPMConfiguration { + /** + JSPM configuration. + */ + jspm?: PackageJson; + } + + /** + Type for [npm's `package.json` file](https://docs.npmjs.com/creating-a-package-json-file). Containing standard npm properties. + */ + export interface PackageJsonStandard { + /** + The name of the package. + */ + name?: string; + + /** + Package version, parseable by [`node-semver`](https://github.com/npm/node-semver). + */ + version?: string; + + /** + Package description, listed in `npm search`. + */ + description?: string; + + /** + Keywords associated with package, listed in `npm search`. + */ + keywords?: string[]; + + /** + The URL to the package's homepage. + */ + homepage?: LiteralUnion<'.', string>; + + /** + The URL to the package's issue tracker and/or the email address to which issues should be reported. + */ + bugs?: BugsLocation; + + /** + The license for the package. + */ + license?: string; + + /** + The licenses for the package. + */ + licenses?: Array<{ + type?: string; + url?: string; + }>; + + author?: Person; + + /** + A list of people who contributed to the package. + */ + contributors?: Person[]; + + /** + A list of people who maintain the package. + */ + maintainers?: Person[]; + + /** + The files included in the package. + */ + files?: string[]; + + /** + Resolution algorithm for importing ".js" files from the package's scope. + + [Read more.](https://nodejs.org/api/esm.html#esm_package_json_type_field) + */ + type?: 'module' | 'commonjs'; + + /** + The module ID that is the primary entry point to the program. + */ + main?: string; + + /** + Standard entry points of the package, with enhanced support for ECMAScript Modules. + + [Read more.](https://nodejs.org/api/esm.html#esm_package_entry_points) + */ + exports?: Exports; + + /** + The executable files that should be installed into the `PATH`. + */ + bin?: + | string + | Record; + + /** + Filenames to put in place for the `man` program to find. + */ + man?: string | string[]; + + /** + Indicates the structure of the package. + */ + directories?: DirectoryLocations; + + /** + Location for the code repository. + */ + repository?: + | string + | { + type: string; + url: string; + + /** + Relative path to package.json if it is placed in non-root directory (for example if it is part of a monorepo). + + [Read more.](https://github.com/npm/rfcs/blob/latest/implemented/0010-monorepo-subdirectory-declaration.md) + */ + directory?: string; + }; + + /** + Script commands that are run at various times in the lifecycle of the package. The key is the lifecycle event, and the value is the command to run at that point. + */ + scripts?: Scripts; + + /** + Is used to set configuration parameters used in package scripts that persist across upgrades. + */ + config?: Record; + + /** + The dependencies of the package. + */ + dependencies?: Dependency; + + /** + Additional tooling dependencies that are not required for the package to work. Usually test, build, or documentation tooling. + */ + devDependencies?: Dependency; + + /** + Dependencies that are skipped if they fail to install. + */ + optionalDependencies?: Dependency; + + /** + Dependencies that will usually be required by the package user directly or via another dependency. + */ + peerDependencies?: Dependency; + + /** + Indicate peer dependencies that are optional. + */ + peerDependenciesMeta?: Record; + + /** + Package names that are bundled when the package is published. + */ + bundledDependencies?: string[]; + + /** + Alias of `bundledDependencies`. + */ + bundleDependencies?: string[]; + + /** + Engines that this package runs on. + */ + engines?: { + [EngineName in 'npm' | 'node' | string]: string; + }; + + /** + @deprecated + */ + engineStrict?: boolean; + + /** + Operating systems the module runs on. + */ + os?: Array>; + + /** + CPU architectures the module runs on. + */ + cpu?: Array>; + + /** + If set to `true`, a warning will be shown if package is installed locally. Useful if the package is primarily a command-line application that should be installed globally. + + @deprecated + */ + preferGlobal?: boolean; + + /** + If set to `true`, then npm will refuse to publish it. + */ + private?: boolean; + + /** + A set of config values that will be used at publish-time. It's especially handy to set the tag, registry or access, to ensure that a given package is not tagged with 'latest', published to the global public registry or that a scoped module is private by default. + */ + publishConfig?: Record; + + /** + Describes and notifies consumers of a package's monetary support information. + + [Read more.](https://github.com/npm/rfcs/blob/latest/accepted/0017-add-funding-support.md) + */ + funding?: string | { + /** + The type of funding. + */ + type?: LiteralUnion< + | 'github' + | 'opencollective' + | 'patreon' + | 'individual' + | 'foundation' + | 'corporation', + string + >; + + /** + The URL to the funding page. + */ + url: string; + }; + } +} + +/** +Type for [npm's `package.json` file](https://docs.npmjs.com/creating-a-package-json-file). Also includes types for fields used by other popular projects, like TypeScript and Yarn. +*/ +export type PackageJson = +PackageJson.PackageJsonStandard & +PackageJson.NonStandardEntryPoints & +PackageJson.TypeScriptConfiguration & +PackageJson.YarnConfiguration & +PackageJson.JSPMConfiguration; diff --git a/node_modules/ansi-escapes/node_modules/type-fest/source/partial-deep.d.ts b/node_modules/ansi-escapes/node_modules/type-fest/source/partial-deep.d.ts new file mode 100644 index 0000000000000000000000000000000000000000..b962b84eb6b4cdada8190d3e10704e98de051cee --- /dev/null +++ b/node_modules/ansi-escapes/node_modules/type-fest/source/partial-deep.d.ts @@ -0,0 +1,72 @@ +import {Primitive} from './basic'; + +/** +Create a type from another type with all keys and nested keys set to optional. + +Use-cases: +- Merging a default settings/config object with another object, the second object would be a deep partial of the default object. +- Mocking and testing complex entities, where populating an entire object with its keys would be redundant in terms of the mock or test. + +@example +``` +import {PartialDeep} from 'type-fest'; + +const settings: Settings = { + textEditor: { + fontSize: 14; + fontColor: '#000000'; + fontWeight: 400; + } + autocomplete: false; + autosave: true; +}; + +const applySavedSettings = (savedSettings: PartialDeep) => { + return {...settings, ...savedSettings}; +} + +settings = applySavedSettings({textEditor: {fontWeight: 500}}); +``` +*/ +export type PartialDeep = T extends Primitive + ? Partial + : T extends Map + ? PartialMapDeep + : T extends Set + ? PartialSetDeep + : T extends ReadonlyMap + ? PartialReadonlyMapDeep + : T extends ReadonlySet + ? PartialReadonlySetDeep + : T extends ((...arguments: any[]) => unknown) + ? T | undefined + : T extends object + ? PartialObjectDeep + : unknown; + +/** +Same as `PartialDeep`, but accepts only `Map`s and as inputs. Internal helper for `PartialDeep`. +*/ +interface PartialMapDeep extends Map, PartialDeep> {} + +/** +Same as `PartialDeep`, but accepts only `Set`s as inputs. Internal helper for `PartialDeep`. +*/ +interface PartialSetDeep extends Set> {} + +/** +Same as `PartialDeep`, but accepts only `ReadonlyMap`s as inputs. Internal helper for `PartialDeep`. +*/ +interface PartialReadonlyMapDeep extends ReadonlyMap, PartialDeep> {} + +/** +Same as `PartialDeep`, but accepts only `ReadonlySet`s as inputs. Internal helper for `PartialDeep`. +*/ +interface PartialReadonlySetDeep extends ReadonlySet> {} + +/** +Same as `PartialDeep`, but accepts only `object`s as inputs. Internal helper for `PartialDeep`. +*/ +type PartialObjectDeep = { + [KeyType in keyof ObjectType]?: PartialDeep +}; diff --git a/node_modules/ansi-escapes/node_modules/type-fest/source/promisable.d.ts b/node_modules/ansi-escapes/node_modules/type-fest/source/promisable.d.ts new file mode 100644 index 0000000000000000000000000000000000000000..71242a5db269279c75c25beda59182fe48c45b2d --- /dev/null +++ b/node_modules/ansi-escapes/node_modules/type-fest/source/promisable.d.ts @@ -0,0 +1,23 @@ +/** +Create a type that represents either the value or the value wrapped in `PromiseLike`. + +Use-cases: +- A function accepts a callback that may either return a value synchronously or may return a promised value. +- This type could be the return type of `Promise#then()`, `Promise#catch()`, and `Promise#finally()` callbacks. + +Please upvote [this issue](https://github.com/microsoft/TypeScript/issues/31394) if you want to have this type as a built-in in TypeScript. + +@example +``` +import {Promisable} from 'type-fest'; + +async function logger(getLogEntry: () => Promisable): Promise { + const entry = await getLogEntry(); + console.log(entry); +} + +logger(() => 'foo'); +logger(() => Promise.resolve('bar')); +``` +*/ +export type Promisable = T | PromiseLike; diff --git a/node_modules/ansi-escapes/node_modules/type-fest/source/promise-value.d.ts b/node_modules/ansi-escapes/node_modules/type-fest/source/promise-value.d.ts new file mode 100644 index 0000000000000000000000000000000000000000..642ddebcc8f30bbfeb9d673e0611f9bcbcefe5ae --- /dev/null +++ b/node_modules/ansi-escapes/node_modules/type-fest/source/promise-value.d.ts @@ -0,0 +1,27 @@ +/** +Returns the type that is wrapped inside a `Promise` type. +If the type is a nested Promise, it is unwrapped recursively until a non-Promise type is obtained. +If the type is not a `Promise`, the type itself is returned. + +@example +``` +import {PromiseValue} from 'type-fest'; + +type AsyncData = Promise; +let asyncData: PromiseValue = Promise.resolve('ABC'); + +type Data = PromiseValue; +let data: Data = await asyncData; + +// Here's an example that shows how this type reacts to non-Promise types. +type SyncData = PromiseValue; +let syncData: SyncData = getSyncData(); + +// Here's an example that shows how this type reacts to recursive Promise types. +type RecursiveAsyncData = Promise >; +let recursiveAsyncData: PromiseValue = Promise.resolve(Promise.resolve('ABC')); +``` +*/ +export type PromiseValue = PromiseType extends Promise + ? { 0: PromiseValue; 1: Value }[PromiseType extends Promise ? 0 : 1] + : Otherwise; diff --git a/node_modules/ansi-escapes/node_modules/type-fest/source/readonly-deep.d.ts b/node_modules/ansi-escapes/node_modules/type-fest/source/readonly-deep.d.ts new file mode 100644 index 0000000000000000000000000000000000000000..b8c04de25c2837e5314d63634e5e60c50c7b1b0b --- /dev/null +++ b/node_modules/ansi-escapes/node_modules/type-fest/source/readonly-deep.d.ts @@ -0,0 +1,59 @@ +import {Primitive} from './basic'; + +/** +Convert `object`s, `Map`s, `Set`s, and `Array`s and all of their keys/elements into immutable structures recursively. + +This is useful when a deeply nested structure needs to be exposed as completely immutable, for example, an imported JSON module or when receiving an API response that is passed around. + +Please upvote [this issue](https://github.com/microsoft/TypeScript/issues/13923) if you want to have this type as a built-in in TypeScript. + +@example +``` +// data.json +{ + "foo": ["bar"] +} + +// main.ts +import {ReadonlyDeep} from 'type-fest'; +import dataJson = require('./data.json'); + +const data: ReadonlyDeep = dataJson; + +export default data; + +// test.ts +import data from './main'; + +data.foo.push('bar'); +//=> error TS2339: Property 'push' does not exist on type 'readonly string[]' +``` +*/ +export type ReadonlyDeep = T extends Primitive | ((...arguments: any[]) => unknown) + ? T + : T extends ReadonlyMap + ? ReadonlyMapDeep + : T extends ReadonlySet + ? ReadonlySetDeep + : T extends object + ? ReadonlyObjectDeep + : unknown; + +/** +Same as `ReadonlyDeep`, but accepts only `ReadonlyMap`s as inputs. Internal helper for `ReadonlyDeep`. +*/ +interface ReadonlyMapDeep + extends ReadonlyMap, ReadonlyDeep> {} + +/** +Same as `ReadonlyDeep`, but accepts only `ReadonlySet`s as inputs. Internal helper for `ReadonlyDeep`. +*/ +interface ReadonlySetDeep + extends ReadonlySet> {} + +/** +Same as `ReadonlyDeep`, but accepts only `object`s as inputs. Internal helper for `ReadonlyDeep`. +*/ +type ReadonlyObjectDeep = { + readonly [KeyType in keyof ObjectType]: ReadonlyDeep +}; diff --git a/node_modules/ansi-escapes/node_modules/type-fest/source/require-at-least-one.d.ts b/node_modules/ansi-escapes/node_modules/type-fest/source/require-at-least-one.d.ts new file mode 100644 index 0000000000000000000000000000000000000000..b3b8719170df20d4fdddcaaf5ccea9a7c86026be --- /dev/null +++ b/node_modules/ansi-escapes/node_modules/type-fest/source/require-at-least-one.d.ts @@ -0,0 +1,33 @@ +import {Except} from './except'; + +/** +Create a type that requires at least one of the given keys. The remaining keys are kept as is. + +@example +``` +import {RequireAtLeastOne} from 'type-fest'; + +type Responder = { + text?: () => string; + json?: () => string; + + secure?: boolean; +}; + +const responder: RequireAtLeastOne = { + json: () => '{"message": "ok"}', + secure: true +}; +``` +*/ +export type RequireAtLeastOne< + ObjectType, + KeysType extends keyof ObjectType = keyof ObjectType +> = { + // For each `Key` in `KeysType` make a mapped type: + [Key in KeysType]-?: Required> & // 1. Make `Key`'s type required + // 2. Make all other keys in `KeysType` optional + Partial>>; +}[KeysType] & + // 3. Add the remaining keys not in `KeysType` + Except; diff --git a/node_modules/ansi-escapes/node_modules/type-fest/source/require-exactly-one.d.ts b/node_modules/ansi-escapes/node_modules/type-fest/source/require-exactly-one.d.ts new file mode 100644 index 0000000000000000000000000000000000000000..c3e7e7eadeb5f267017ce0296d18dc56f25ad7d0 --- /dev/null +++ b/node_modules/ansi-escapes/node_modules/type-fest/source/require-exactly-one.d.ts @@ -0,0 +1,35 @@ +// TODO: Remove this when we target TypeScript >=3.5. +type _Omit = Pick>; + +/** +Create a type that requires exactly one of the given keys and disallows more. The remaining keys are kept as is. + +Use-cases: +- Creating interfaces for components that only need one of the keys to display properly. +- Declaring generic keys in a single place for a single use-case that gets narrowed down via `RequireExactlyOne`. + +The caveat with `RequireExactlyOne` is that TypeScript doesn't always know at compile time every key that will exist at runtime. Therefore `RequireExactlyOne` can't do anything to prevent extra keys it doesn't know about. + +@example +``` +import {RequireExactlyOne} from 'type-fest'; + +type Responder = { + text: () => string; + json: () => string; + secure: boolean; +}; + +const responder: RequireExactlyOne = { + // Adding a `text` key here would cause a compile error. + + json: () => '{"message": "ok"}', + secure: true +}; +``` +*/ +export type RequireExactlyOne = + {[Key in KeysType]: ( + Required> & + Partial, never>> + )}[KeysType] & _Omit; diff --git a/node_modules/ansi-escapes/node_modules/type-fest/source/set-optional.d.ts b/node_modules/ansi-escapes/node_modules/type-fest/source/set-optional.d.ts new file mode 100644 index 0000000000000000000000000000000000000000..ebaf09819b07524b0532324fdf30ec4e4042eb5b --- /dev/null +++ b/node_modules/ansi-escapes/node_modules/type-fest/source/set-optional.d.ts @@ -0,0 +1,33 @@ +import {Except} from './except'; +import {Simplify} from './simplify'; + +/** +Create a type that makes the given keys optional. The remaining keys are kept as is. The sister of the `SetRequired` type. + +Use-case: You want to define a single model where the only thing that changes is whether or not some of the keys are optional. + +@example +``` +import {SetOptional} from 'type-fest'; + +type Foo = { + a: number; + b?: string; + c: boolean; +} + +type SomeOptional = SetOptional; +// type SomeOptional = { +// a: number; +// b?: string; // Was already optional and still is. +// c?: boolean; // Is now optional. +// } +``` +*/ +export type SetOptional = + Simplify< + // Pick just the keys that are readonly from the base type. + Except & + // Pick the keys that should be mutable from the base type and make them mutable. + Partial> + >; diff --git a/node_modules/ansi-escapes/node_modules/type-fest/source/set-required.d.ts b/node_modules/ansi-escapes/node_modules/type-fest/source/set-required.d.ts new file mode 100644 index 0000000000000000000000000000000000000000..ab8593eb5aed20255c901578a4862e0dcebe4513 --- /dev/null +++ b/node_modules/ansi-escapes/node_modules/type-fest/source/set-required.d.ts @@ -0,0 +1,33 @@ +import {Except} from './except'; +import {Simplify} from './simplify'; + +/** +Create a type that makes the given keys required. The remaining keys are kept as is. The sister of the `SetOptional` type. + +Use-case: You want to define a single model where the only thing that changes is whether or not some of the keys are required. + +@example +``` +import {SetRequired} from 'type-fest'; + +type Foo = { + a?: number; + b: string; + c?: boolean; +} + +type SomeRequired = SetRequired; +// type SomeRequired = { +// a?: number; +// b: string; // Was already required and still is. +// c: boolean; // Is now required. +// } +``` +*/ +export type SetRequired = + Simplify< + // Pick just the keys that are optional from the base type. + Except & + // Pick the keys that should be required from the base type and make them required. + Required> + >; diff --git a/node_modules/ansi-escapes/node_modules/type-fest/source/set-return-type.d.ts b/node_modules/ansi-escapes/node_modules/type-fest/source/set-return-type.d.ts new file mode 100644 index 0000000000000000000000000000000000000000..98766b103e82c7daca25e40cd56b5d0ea2e6ad03 --- /dev/null +++ b/node_modules/ansi-escapes/node_modules/type-fest/source/set-return-type.d.ts @@ -0,0 +1,29 @@ +type IsAny = 0 extends (1 & T) ? true : false; // https://stackoverflow.com/a/49928360/3406963 +type IsNever = [T] extends [never] ? true : false; +type IsUnknown = IsNever extends false ? T extends unknown ? unknown extends T ? IsAny extends false ? true : false : false : false : false; + +/** +Create a function type with a return type of your choice and the same parameters as the given function type. + +Use-case: You want to define a wrapped function that returns something different while receiving the same parameters. For example, you might want to wrap a function that can throw an error into one that will return `undefined` instead. + +@example +``` +import {SetReturnType} from 'type-fest'; + +type MyFunctionThatCanThrow = (foo: SomeType, bar: unknown) => SomeOtherType; + +type MyWrappedFunction = SetReturnType; +//=> type MyWrappedFunction = (foo: SomeType, bar: unknown) => SomeOtherType | undefined; +``` +*/ +export type SetReturnType any, TypeToReturn> = + // Just using `Parameters` isn't ideal because it doesn't handle the `this` fake parameter. + Fn extends (this: infer ThisArg, ...args: infer Arguments) => any ? ( + // If a function did not specify the `this` fake parameter, it will be inferred to `unknown`. + // We want to detect this situation just to display a friendlier type upon hovering on an IntelliSense-powered IDE. + IsUnknown extends true ? (...args: Arguments) => TypeToReturn : (this: ThisArg, ...args: Arguments) => TypeToReturn + ) : ( + // This part should be unreachable, but we make it meaningful just in case… + (...args: Parameters) => TypeToReturn + ); diff --git a/node_modules/ansi-escapes/node_modules/type-fest/source/simplify.d.ts b/node_modules/ansi-escapes/node_modules/type-fest/source/simplify.d.ts new file mode 100644 index 0000000000000000000000000000000000000000..5e067c24e6084c6622a25f0d56b0aabf42f2038e --- /dev/null +++ b/node_modules/ansi-escapes/node_modules/type-fest/source/simplify.d.ts @@ -0,0 +1,4 @@ +/** +Flatten the type output to improve type hints shown in editors. +*/ +export type Simplify = {[KeyType in keyof T]: T[KeyType]}; diff --git a/node_modules/ansi-escapes/node_modules/type-fest/source/stringified.d.ts b/node_modules/ansi-escapes/node_modules/type-fest/source/stringified.d.ts new file mode 100644 index 0000000000000000000000000000000000000000..9688b6740db4c57fe733b42ad9b1443faed32862 --- /dev/null +++ b/node_modules/ansi-escapes/node_modules/type-fest/source/stringified.d.ts @@ -0,0 +1,21 @@ +/** +Create a type with the keys of the given type changed to `string` type. + +Use-case: Changing interface values to strings in order to use them in a form model. + +@example +``` +import {Stringified} from 'type-fest'; + +type Car { + model: string; + speed: number; +} + +const carForm: Stringified = { + model: 'Foo', + speed: '101' +}; +``` +*/ +export type Stringified = {[KeyType in keyof ObjectType]: string}; diff --git a/node_modules/ansi-escapes/node_modules/type-fest/source/tsconfig-json.d.ts b/node_modules/ansi-escapes/node_modules/type-fest/source/tsconfig-json.d.ts new file mode 100644 index 0000000000000000000000000000000000000000..89f6e9dd4f18e44e0528351d69eedad5ee92fd8b --- /dev/null +++ b/node_modules/ansi-escapes/node_modules/type-fest/source/tsconfig-json.d.ts @@ -0,0 +1,870 @@ +declare namespace TsConfigJson { + namespace CompilerOptions { + export type JSX = + | 'preserve' + | 'react' + | 'react-native'; + + export type Module = + | 'CommonJS' + | 'AMD' + | 'System' + | 'UMD' + | 'ES6' + | 'ES2015' + | 'ESNext' + | 'None' + // Lowercase alternatives + | 'commonjs' + | 'amd' + | 'system' + | 'umd' + | 'es6' + | 'es2015' + | 'esnext' + | 'none'; + + export type NewLine = + | 'CRLF' + | 'LF' + // Lowercase alternatives + | 'crlf' + | 'lf'; + + export type Target = + | 'ES3' + | 'ES5' + | 'ES6' + | 'ES2015' + | 'ES2016' + | 'ES2017' + | 'ES2018' + | 'ES2019' + | 'ES2020' + | 'ESNext' + // Lowercase alternatives + | 'es3' + | 'es5' + | 'es6' + | 'es2015' + | 'es2016' + | 'es2017' + | 'es2018' + | 'es2019' + | 'es2020' + | 'esnext'; + + export type Lib = + | 'ES5' + | 'ES6' + | 'ES7' + | 'ES2015' + | 'ES2015.Collection' + | 'ES2015.Core' + | 'ES2015.Generator' + | 'ES2015.Iterable' + | 'ES2015.Promise' + | 'ES2015.Proxy' + | 'ES2015.Reflect' + | 'ES2015.Symbol.WellKnown' + | 'ES2015.Symbol' + | 'ES2016' + | 'ES2016.Array.Include' + | 'ES2017' + | 'ES2017.Intl' + | 'ES2017.Object' + | 'ES2017.SharedMemory' + | 'ES2017.String' + | 'ES2017.TypedArrays' + | 'ES2018' + | 'ES2018.AsyncIterable' + | 'ES2018.Intl' + | 'ES2018.Promise' + | 'ES2018.Regexp' + | 'ES2019' + | 'ES2019.Array' + | 'ES2019.Object' + | 'ES2019.String' + | 'ES2019.Symbol' + | 'ES2020' + | 'ES2020.String' + | 'ES2020.Symbol.WellKnown' + | 'ESNext' + | 'ESNext.Array' + | 'ESNext.AsyncIterable' + | 'ESNext.BigInt' + | 'ESNext.Intl' + | 'ESNext.Symbol' + | 'DOM' + | 'DOM.Iterable' + | 'ScriptHost' + | 'WebWorker' + | 'WebWorker.ImportScripts' + // Lowercase alternatives + | 'es5' + | 'es6' + | 'es7' + | 'es2015' + | 'es2015.collection' + | 'es2015.core' + | 'es2015.generator' + | 'es2015.iterable' + | 'es2015.promise' + | 'es2015.proxy' + | 'es2015.reflect' + | 'es2015.symbol.wellknown' + | 'es2015.symbol' + | 'es2016' + | 'es2016.array.include' + | 'es2017' + | 'es2017.intl' + | 'es2017.object' + | 'es2017.sharedmemory' + | 'es2017.string' + | 'es2017.typedarrays' + | 'es2018' + | 'es2018.asynciterable' + | 'es2018.intl' + | 'es2018.promise' + | 'es2018.regexp' + | 'es2019' + | 'es2019.array' + | 'es2019.object' + | 'es2019.string' + | 'es2019.symbol' + | 'es2020' + | 'es2020.string' + | 'es2020.symbol.wellknown' + | 'esnext' + | 'esnext.array' + | 'esnext.asynciterable' + | 'esnext.bigint' + | 'esnext.intl' + | 'esnext.symbol' + | 'dom' + | 'dom.iterable' + | 'scripthost' + | 'webworker' + | 'webworker.importscripts'; + + export interface Plugin { + [key: string]: unknown; + /** + Plugin name. + */ + name?: string; + } + } + + export interface CompilerOptions { + /** + The character set of the input files. + + @default 'utf8' + */ + charset?: string; + + /** + Enables building for project references. + + @default true + */ + composite?: boolean; + + /** + Generates corresponding d.ts files. + + @default false + */ + declaration?: boolean; + + /** + Specify output directory for generated declaration files. + + Requires TypeScript version 2.0 or later. + */ + declarationDir?: string; + + /** + Show diagnostic information. + + @default false + */ + diagnostics?: boolean; + + /** + Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. + + @default false + */ + emitBOM?: boolean; + + /** + Only emit `.d.ts` declaration files. + + @default false + */ + emitDeclarationOnly?: boolean; + + /** + Enable incremental compilation. + + @default `composite` + */ + incremental?: boolean; + + /** + Specify file to store incremental compilation information. + + @default '.tsbuildinfo' + */ + tsBuildInfoFile?: string; + + /** + Emit a single file with source maps instead of having a separate file. + + @default false + */ + inlineSourceMap?: boolean; + + /** + Emit the source alongside the sourcemaps within a single file. + + Requires `--inlineSourceMap` to be set. + + @default false + */ + inlineSources?: boolean; + + /** + Specify JSX code generation: `'preserve'`, `'react'`, or `'react-native'`. + + @default 'preserve' + */ + jsx?: CompilerOptions.JSX; + + /** + Specifies the object invoked for `createElement` and `__spread` when targeting `'react'` JSX emit. + + @default 'React' + */ + reactNamespace?: string; + + /** + Print names of files part of the compilation. + + @default false + */ + listFiles?: boolean; + + /** + Specifies the location where debugger should locate map files instead of generated locations. + */ + mapRoot?: string; + + /** + Specify module code generation: 'None', 'CommonJS', 'AMD', 'System', 'UMD', 'ES6', 'ES2015' or 'ESNext'. Only 'AMD' and 'System' can be used in conjunction with `--outFile`. 'ES6' and 'ES2015' values may be used when targeting 'ES5' or lower. + + @default ['ES3', 'ES5'].includes(target) ? 'CommonJS' : 'ES6' + */ + module?: CompilerOptions.Module; + + /** + Specifies the end of line sequence to be used when emitting files: 'crlf' (Windows) or 'lf' (Unix). + + Default: Platform specific + */ + newLine?: CompilerOptions.NewLine; + + /** + Do not emit output. + + @default false + */ + noEmit?: boolean; + + /** + Do not generate custom helper functions like `__extends` in compiled output. + + @default false + */ + noEmitHelpers?: boolean; + + /** + Do not emit outputs if any type checking errors were reported. + + @default false + */ + noEmitOnError?: boolean; + + /** + Warn on expressions and declarations with an implied 'any' type. + + @default false + */ + noImplicitAny?: boolean; + + /** + Raise error on 'this' expressions with an implied any type. + + @default false + */ + noImplicitThis?: boolean; + + /** + Report errors on unused locals. + + Requires TypeScript version 2.0 or later. + + @default false + */ + noUnusedLocals?: boolean; + + /** + Report errors on unused parameters. + + Requires TypeScript version 2.0 or later. + + @default false + */ + noUnusedParameters?: boolean; + + /** + Do not include the default library file (lib.d.ts). + + @default false + */ + noLib?: boolean; + + /** + Do not add triple-slash references or module import targets to the list of compiled files. + + @default false + */ + noResolve?: boolean; + + /** + Disable strict checking of generic signatures in function types. + + @default false + */ + noStrictGenericChecks?: boolean; + + /** + @deprecated use `skipLibCheck` instead. + */ + skipDefaultLibCheck?: boolean; + + /** + Skip type checking of declaration files. + + Requires TypeScript version 2.0 or later. + + @default false + */ + skipLibCheck?: boolean; + + /** + Concatenate and emit output to single file. + */ + outFile?: string; + + /** + Redirect output structure to the directory. + */ + outDir?: string; + + /** + Do not erase const enum declarations in generated code. + + @default false + */ + preserveConstEnums?: boolean; + + /** + Do not resolve symlinks to their real path; treat a symlinked file like a real one. + + @default false + */ + preserveSymlinks?: boolean; + + /** + Keep outdated console output in watch mode instead of clearing the screen. + + @default false + */ + preserveWatchOutput?: boolean; + + /** + Stylize errors and messages using color and context (experimental). + + @default true // Unless piping to another program or redirecting output to a file. + */ + pretty?: boolean; + + /** + Do not emit comments to output. + + @default false + */ + removeComments?: boolean; + + /** + Specifies the root directory of input files. + + Use to control the output directory structure with `--outDir`. + */ + rootDir?: string; + + /** + Unconditionally emit imports for unresolved files. + + @default false + */ + isolatedModules?: boolean; + + /** + Generates corresponding '.map' file. + + @default false + */ + sourceMap?: boolean; + + /** + Specifies the location where debugger should locate TypeScript files instead of source locations. + */ + sourceRoot?: string; + + /** + Suppress excess property checks for object literals. + + @default false + */ + suppressExcessPropertyErrors?: boolean; + + /** + Suppress noImplicitAny errors for indexing objects lacking index signatures. + + @default false + */ + suppressImplicitAnyIndexErrors?: boolean; + + /** + Do not emit declarations for code that has an `@internal` annotation. + */ + stripInternal?: boolean; + + /** + Specify ECMAScript target version. + + @default 'es3' + */ + target?: CompilerOptions.Target; + + /** + Watch input files. + + @default false + */ + watch?: boolean; + + /** + Enables experimental support for ES7 decorators. + + @default false + */ + experimentalDecorators?: boolean; + + /** + Emit design-type metadata for decorated declarations in source. + + @default false + */ + emitDecoratorMetadata?: boolean; + + /** + Specifies module resolution strategy: 'node' (Node) or 'classic' (TypeScript pre 1.6). + + @default ['AMD', 'System', 'ES6'].includes(module) ? 'classic' : 'node' + */ + moduleResolution?: 'classic' | 'node'; + + /** + Do not report errors on unused labels. + + @default false + */ + allowUnusedLabels?: boolean; + + /** + Report error when not all code paths in function return a value. + + @default false + */ + noImplicitReturns?: boolean; + + /** + Report errors for fallthrough cases in switch statement. + + @default false + */ + noFallthroughCasesInSwitch?: boolean; + + /** + Do not report errors on unreachable code. + + @default false + */ + allowUnreachableCode?: boolean; + + /** + Disallow inconsistently-cased references to the same file. + + @default false + */ + forceConsistentCasingInFileNames?: boolean; + + /** + Base directory to resolve non-relative module names. + */ + baseUrl?: string; + + /** + Specify path mapping to be computed relative to baseUrl option. + */ + paths?: Record; + + /** + List of TypeScript language server plugins to load. + + Requires TypeScript version 2.3 or later. + */ + plugins?: CompilerOptions.Plugin[]; + + /** + Specify list of root directories to be used when resolving modules. + */ + rootDirs?: string[]; + + /** + Specify list of directories for type definition files to be included. + + Requires TypeScript version 2.0 or later. + */ + typeRoots?: string[]; + + /** + Type declaration files to be included in compilation. + + Requires TypeScript version 2.0 or later. + */ + types?: string[]; + + /** + Enable tracing of the name resolution process. + + @default false + */ + traceResolution?: boolean; + + /** + Allow javascript files to be compiled. + + @default false + */ + allowJs?: boolean; + + /** + Do not truncate error messages. + + @default false + */ + noErrorTruncation?: boolean; + + /** + Allow default imports from modules with no default export. This does not affect code emit, just typechecking. + + @default module === 'system' || esModuleInterop + */ + allowSyntheticDefaultImports?: boolean; + + /** + Do not emit `'use strict'` directives in module output. + + @default false + */ + noImplicitUseStrict?: boolean; + + /** + Enable to list all emitted files. + + Requires TypeScript version 2.0 or later. + + @default false + */ + listEmittedFiles?: boolean; + + /** + Disable size limit for JavaScript project. + + Requires TypeScript version 2.0 or later. + + @default false + */ + disableSizeLimit?: boolean; + + /** + List of library files to be included in the compilation. + + Requires TypeScript version 2.0 or later. + */ + lib?: CompilerOptions.Lib[]; + + /** + Enable strict null checks. + + Requires TypeScript version 2.0 or later. + + @default false + */ + strictNullChecks?: boolean; + + /** + The maximum dependency depth to search under `node_modules` and load JavaScript files. Only applicable with `--allowJs`. + + @default 0 + */ + maxNodeModuleJsDepth?: number; + + /** + Import emit helpers (e.g. `__extends`, `__rest`, etc..) from tslib. + + Requires TypeScript version 2.1 or later. + + @default false + */ + importHelpers?: boolean; + + /** + Specify the JSX factory function to use when targeting React JSX emit, e.g. `React.createElement` or `h`. + + Requires TypeScript version 2.1 or later. + + @default 'React.createElement' + */ + jsxFactory?: string; + + /** + Parse in strict mode and emit `'use strict'` for each source file. + + Requires TypeScript version 2.1 or later. + + @default false + */ + alwaysStrict?: boolean; + + /** + Enable all strict type checking options. + + Requires TypeScript version 2.3 or later. + + @default false + */ + strict?: boolean; + + /** + Enable stricter checking of of the `bind`, `call`, and `apply` methods on functions. + + @default false + */ + strictBindCallApply?: boolean; + + /** + Provide full support for iterables in `for-of`, spread, and destructuring when targeting `ES5` or `ES3`. + + Requires TypeScript version 2.3 or later. + + @default false + */ + downlevelIteration?: boolean; + + /** + Report errors in `.js` files. + + Requires TypeScript version 2.3 or later. + + @default false + */ + checkJs?: boolean; + + /** + Disable bivariant parameter checking for function types. + + Requires TypeScript version 2.6 or later. + + @default false + */ + strictFunctionTypes?: boolean; + + /** + Ensure non-undefined class properties are initialized in the constructor. + + Requires TypeScript version 2.7 or later. + + @default false + */ + strictPropertyInitialization?: boolean; + + /** + Emit `__importStar` and `__importDefault` helpers for runtime Babel ecosystem compatibility and enable `--allowSyntheticDefaultImports` for typesystem compatibility. + + Requires TypeScript version 2.7 or later. + + @default false + */ + esModuleInterop?: boolean; + + /** + Allow accessing UMD globals from modules. + + @default false + */ + allowUmdGlobalAccess?: boolean; + + /** + Resolve `keyof` to string valued property names only (no numbers or symbols). + + Requires TypeScript version 2.9 or later. + + @default false + */ + keyofStringsOnly?: boolean; + + /** + Emit ECMAScript standard class fields. + + Requires TypeScript version 3.7 or later. + + @default false + */ + useDefineForClassFields?: boolean; + + /** + Generates a sourcemap for each corresponding `.d.ts` file. + + Requires TypeScript version 2.9 or later. + + @default false + */ + declarationMap?: boolean; + + /** + Include modules imported with `.json` extension. + + Requires TypeScript version 2.9 or later. + + @default false + */ + resolveJsonModule?: boolean; + } + + /** + Auto type (.d.ts) acquisition options for this project. + + Requires TypeScript version 2.1 or later. + */ + export interface TypeAcquisition { + /** + Enable auto type acquisition. + */ + enable?: boolean; + + /** + Specifies a list of type declarations to be included in auto type acquisition. For example, `['jquery', 'lodash']`. + */ + include?: string[]; + + /** + Specifies a list of type declarations to be excluded from auto type acquisition. For example, `['jquery', 'lodash']`. + */ + exclude?: string[]; + } + + export interface References { + /** + A normalized path on disk. + */ + path: string; + + /** + The path as the user originally wrote it. + */ + originalPath?: string; + + /** + True if the output of this reference should be prepended to the output of this project. + + Only valid for `--outFile` compilations. + */ + prepend?: boolean; + + /** + True if it is intended that this reference form a circularity. + */ + circular?: boolean; + } +} + +export interface TsConfigJson { + /** + Instructs the TypeScript compiler how to compile `.ts` files. + */ + compilerOptions?: TsConfigJson.CompilerOptions; + + /** + Auto type (.d.ts) acquisition options for this project. + + Requires TypeScript version 2.1 or later. + */ + typeAcquisition?: TsConfigJson.TypeAcquisition; + + /** + Enable Compile-on-Save for this project. + */ + compileOnSave?: boolean; + + /** + Path to base configuration file to inherit from. + + Requires TypeScript version 2.1 or later. + */ + extends?: string; + + /** + If no `files` or `include` property is present in a `tsconfig.json`, the compiler defaults to including all files in the containing directory and subdirectories except those specified by `exclude`. When a `files` property is specified, only those files and those specified by `include` are included. + */ + files?: string[]; + + /** + Specifies a list of files to be excluded from compilation. The `exclude` property only affects the files included via the `include` property and not the `files` property. + + Glob patterns require TypeScript version 2.0 or later. + */ + exclude?: string[]; + + /** + Specifies a list of glob patterns that match files to be included in compilation. + + If no `files` or `include` property is present in a `tsconfig.json`, the compiler defaults to including all files in the containing directory and subdirectories except those specified by `exclude`. + + Requires TypeScript version 2.0 or later. + */ + include?: string[]; + + /** + Referenced projects. + + Requires TypeScript version 3.0 or later. + */ + references?: TsConfigJson.References[]; +} diff --git a/node_modules/ansi-escapes/node_modules/type-fest/source/typed-array.d.ts b/node_modules/ansi-escapes/node_modules/type-fest/source/typed-array.d.ts new file mode 100644 index 0000000000000000000000000000000000000000..15e22a3e505bffe08e53eea1e572727a093cc034 --- /dev/null +++ b/node_modules/ansi-escapes/node_modules/type-fest/source/typed-array.d.ts @@ -0,0 +1,15 @@ +/** +Matches any [typed array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypedArray), like `Uint8Array` or `Float64Array`. +*/ +export type TypedArray = + | Int8Array + | Uint8Array + | Uint8ClampedArray + | Int16Array + | Uint16Array + | Int32Array + | Uint32Array + | Float32Array + | Float64Array + | BigInt64Array + | BigUint64Array; diff --git a/node_modules/ansi-escapes/node_modules/type-fest/source/union-to-intersection.d.ts b/node_modules/ansi-escapes/node_modules/type-fest/source/union-to-intersection.d.ts new file mode 100644 index 0000000000000000000000000000000000000000..5f9837f3b63708973c98d1caefa51fbd0fe44522 --- /dev/null +++ b/node_modules/ansi-escapes/node_modules/type-fest/source/union-to-intersection.d.ts @@ -0,0 +1,58 @@ +/** +Convert a union type to an intersection type using [distributive conditional types](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-8.html#distributive-conditional-types). + +Inspired by [this Stack Overflow answer](https://stackoverflow.com/a/50375286/2172153). + +@example +``` +import {UnionToIntersection} from 'type-fest'; + +type Union = {the(): void} | {great(arg: string): void} | {escape: boolean}; + +type Intersection = UnionToIntersection; +//=> {the(): void; great(arg: string): void; escape: boolean}; +``` + +A more applicable example which could make its way into your library code follows. + +@example +``` +import {UnionToIntersection} from 'type-fest'; + +class CommandOne { + commands: { + a1: () => undefined, + b1: () => undefined, + } +} + +class CommandTwo { + commands: { + a2: (argA: string) => undefined, + b2: (argB: string) => undefined, + } +} + +const union = [new CommandOne(), new CommandTwo()].map(instance => instance.commands); +type Union = typeof union; +//=> {a1(): void; b1(): void} | {a2(argA: string): void; b2(argB: string): void} + +type Intersection = UnionToIntersection; +//=> {a1(): void; b1(): void; a2(argA: string): void; b2(argB: string): void} +``` +*/ +export type UnionToIntersection = ( + // `extends unknown` is always going to be the case and is used to convert the + // `Union` into a [distributive conditional + // type](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-8.html#distributive-conditional-types). + Union extends unknown + // The union type is used as the only argument to a function since the union + // of function arguments is an intersection. + ? (distributedUnion: Union) => void + // This won't happen. + : never + // Infer the `Intersection` type since TypeScript represents the positional + // arguments of unions of functions as an intersection of the union. + ) extends ((mergedIntersection: infer Intersection) => void) + ? Intersection + : never; diff --git a/node_modules/ansi-escapes/node_modules/type-fest/source/utilities.d.ts b/node_modules/ansi-escapes/node_modules/type-fest/source/utilities.d.ts new file mode 100644 index 0000000000000000000000000000000000000000..8d60ccde09cc6180e44f8dc2595447b961ba1a16 --- /dev/null +++ b/node_modules/ansi-escapes/node_modules/type-fest/source/utilities.d.ts @@ -0,0 +1,5 @@ +export type UpperCaseCharacters = 'A' | 'B' | 'C' | 'D' | 'E' | 'F' | 'G' | 'H' | 'I' | 'J' | 'K' | 'L' | 'M' | 'N' | 'O' | 'P' | 'Q' | 'R' | 'S' | 'T' | 'U' | 'V' | 'W' | 'X' | 'Y' | 'Z'; + +export type WordSeparators = '-' | '_' | ' '; + +export type StringDigit = '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9'; diff --git a/node_modules/ansi-escapes/node_modules/type-fest/source/value-of.d.ts b/node_modules/ansi-escapes/node_modules/type-fest/source/value-of.d.ts new file mode 100644 index 0000000000000000000000000000000000000000..12793733b4784de7232cb224f9a068f2a8fd3bef --- /dev/null +++ b/node_modules/ansi-escapes/node_modules/type-fest/source/value-of.d.ts @@ -0,0 +1,40 @@ +/** +Create a union of the given object's values, and optionally specify which keys to get the values from. + +Please upvote [this issue](https://github.com/microsoft/TypeScript/issues/31438) if you want to have this type as a built-in in TypeScript. + +@example +``` +// data.json +{ + 'foo': 1, + 'bar': 2, + 'biz': 3 +} + +// main.ts +import {ValueOf} from 'type-fest'; +import data = require('./data.json'); + +export function getData(name: string): ValueOf { + return data[name]; +} + +export function onlyBar(name: string): ValueOf { + return data[name]; +} + +// file.ts +import {getData, onlyBar} from './main'; + +getData('foo'); +//=> 1 + +onlyBar('foo'); +//=> TypeError ... + +onlyBar('bar'); +//=> 2 +``` +*/ +export type ValueOf = ObjectType[ValueType]; diff --git a/node_modules/ansi-escapes/node_modules/type-fest/ts41/camel-case.d.ts b/node_modules/ansi-escapes/node_modules/type-fest/ts41/camel-case.d.ts new file mode 100644 index 0000000000000000000000000000000000000000..4f9a67bc4daf5995457975199484c4d01e0db0d6 --- /dev/null +++ b/node_modules/ansi-escapes/node_modules/type-fest/ts41/camel-case.d.ts @@ -0,0 +1,64 @@ +import {WordSeparators} from '../source/utilities'; +import {Split} from './utilities'; + +/** +Step by step takes the first item in an array literal, formats it and adds it to a string literal, and then recursively appends the remainder. + +Only to be used by `CamelCaseStringArray<>`. + +@see CamelCaseStringArray +*/ +type InnerCamelCaseStringArray = + Parts extends [`${infer FirstPart}`, ...infer RemainingParts] + ? FirstPart extends undefined + ? '' + : FirstPart extends '' + ? InnerCamelCaseStringArray + : `${PreviousPart extends '' ? FirstPart : Capitalize}${InnerCamelCaseStringArray}` + : ''; + +/** +Starts fusing the output of `Split<>`, an array literal of strings, into a camel-cased string literal. + +It's separate from `InnerCamelCaseStringArray<>` to keep a clean API outwards to the rest of the code. + +@see Split +*/ +type CamelCaseStringArray = + Parts extends [`${infer FirstPart}`, ...infer RemainingParts] + ? Uncapitalize<`${FirstPart}${InnerCamelCaseStringArray}`> + : never; + +/** +Convert a string literal to camel-case. + +This can be useful when, for example, converting some kebab-cased command-line flags or a snake-cased database result. + +@example +``` +import {CamelCase} from 'type-fest'; + +// Simple + +const someVariable: CamelCase<'foo-bar'> = 'fooBar'; + +// Advanced + +type CamelCasedProps = { + [K in keyof T as CamelCase]: T[K] +}; + +interface RawOptions { + 'dry-run': boolean; + 'full_family_name': string; + foo: number; +} + +const dbResult: CamelCasedProps = { + dryRun: true, + fullFamilyName: 'bar.js', + foo: 123 +}; +``` +*/ +export type CamelCase = K extends string ? CamelCaseStringArray> : K; diff --git a/node_modules/ansi-escapes/node_modules/type-fest/ts41/delimiter-case.d.ts b/node_modules/ansi-escapes/node_modules/type-fest/ts41/delimiter-case.d.ts new file mode 100644 index 0000000000000000000000000000000000000000..52f4eb992cf649c0eaa7f1967c6a725742fc02b1 --- /dev/null +++ b/node_modules/ansi-escapes/node_modules/type-fest/ts41/delimiter-case.d.ts @@ -0,0 +1,85 @@ +import {UpperCaseCharacters, WordSeparators} from '../source/utilities'; + +/** +Unlike a simpler split, this one includes the delimiter splitted on in the resulting array literal. This is to enable splitting on, for example, upper-case characters. +*/ +export type SplitIncludingDelimiters = + Source extends '' ? [] : + Source extends `${infer FirstPart}${Delimiter}${infer SecondPart}` ? + ( + Source extends `${FirstPart}${infer UsedDelimiter}${SecondPart}` + ? UsedDelimiter extends Delimiter + ? Source extends `${infer FirstPart}${UsedDelimiter}${infer SecondPart}` + ? [...SplitIncludingDelimiters, UsedDelimiter, ...SplitIncludingDelimiters] + : never + : never + : never + ) : + [Source]; + +/** +Format a specific part of the splitted string literal that `StringArrayToDelimiterCase<>` fuses together, ensuring desired casing. + +@see StringArrayToDelimiterCase +*/ +type StringPartToDelimiterCase = + StringPart extends UsedWordSeparators ? Delimiter : + StringPart extends UsedUpperCaseCharacters ? `${Delimiter}${Lowercase}` : + StringPart; + +/** +Takes the result of a splitted string literal and recursively concatenates it together into the desired casing. + +It receives `UsedWordSeparators` and `UsedUpperCaseCharacters` as input to ensure it's fully encapsulated. + +@see SplitIncludingDelimiters +*/ +type StringArrayToDelimiterCase = + Parts extends [`${infer FirstPart}`, ...infer RemainingParts] + ? `${StringPartToDelimiterCase}${StringArrayToDelimiterCase}` + : ''; + +/** +Convert a string literal to a custom string delimiter casing. + +This can be useful when, for example, converting a camel-cased object property to an oddly cased one. + +@see KebabCase +@see SnakeCase + +@example +``` +import {DelimiterCase} from 'type-fest'; + +// Simple + +const someVariable: DelimiterCase<'fooBar', '#'> = 'foo#bar'; + +// Advanced + +type OddlyCasedProps = { + [K in keyof T as DelimiterCase]: T[K] +}; + +interface SomeOptions { + dryRun: boolean; + includeFile: string; + foo: number; +} + +const rawCliOptions: OddlyCasedProps = { + 'dry#run': true, + 'include#file': 'bar.js', + foo: 123 +}; +``` +*/ + +export type DelimiterCase = Value extends string + ? StringArrayToDelimiterCase< + SplitIncludingDelimiters, + WordSeparators, + UpperCaseCharacters, + Delimiter + > + : Value; diff --git a/node_modules/ansi-escapes/node_modules/type-fest/ts41/get.d.ts b/node_modules/ansi-escapes/node_modules/type-fest/ts41/get.d.ts new file mode 100644 index 0000000000000000000000000000000000000000..9103e9aa37864aedf2526631f68300f7cef75f7a --- /dev/null +++ b/node_modules/ansi-escapes/node_modules/type-fest/ts41/get.d.ts @@ -0,0 +1,131 @@ +import {Split} from './utilities'; +import {StringDigit} from '../source/utilities'; + +/** +Like the `Get` type but receives an array of strings as a path parameter. +*/ +type GetWithPath = + Keys extends [] + ? BaseType + : Keys extends [infer Head, ...infer Tail] + ? GetWithPath>, Extract> + : never; + +/** +Splits a dot-prop style path into a tuple comprised of the properties in the path. Handles square-bracket notation. + +@example +``` +ToPath<'foo.bar.baz'> +//=> ['foo', 'bar', 'baz'] + +ToPath<'foo[0].bar.baz'> +//=> ['foo', '0', 'bar', 'baz'] +``` +*/ +type ToPath = Split, '.'>; + +/** +Replaces square-bracketed dot notation with dots, for example, `foo[0].bar` -> `foo.0.bar`. +*/ +type FixPathSquareBrackets = + Path extends `${infer Head}[${infer Middle}]${infer Tail}` + ? `${Head}.${Middle}${FixPathSquareBrackets}` + : Path; + +/** +Returns true if `LongString` is made up out of `Substring` repeated 0 or more times. + +@example +``` +ConsistsOnlyOf<'aaa', 'a'> //=> true +ConsistsOnlyOf<'ababab', 'ab'> //=> true +ConsistsOnlyOf<'aBa', 'a'> //=> false +ConsistsOnlyOf<'', 'a'> //=> true +``` +*/ +type ConsistsOnlyOf = + LongString extends '' + ? true + : LongString extends `${Substring}${infer Tail}` + ? ConsistsOnlyOf + : false; + +/** +Convert a type which may have number keys to one with string keys, making it possible to index using strings retrieved from template types. + +@example +``` +type WithNumbers = {foo: string; 0: boolean}; +type WithStrings = WithStringKeys; + +type WithNumbersKeys = keyof WithNumbers; +//=> 'foo' | 0 +type WithStringsKeys = keyof WithStrings; +//=> 'foo' | '0' +``` +*/ +type WithStringKeys> = { + [Key in `${Extract}`]: BaseType[Key] +}; + +/** +Get a property of an object or array. Works when indexing arrays using number-literal-strings, for example, `PropertyOf = number`, and when indexing objects with number keys. + +Note: +- Returns `unknown` if `Key` is not a property of `BaseType`, since TypeScript uses structural typing, and it cannot be guaranteed that extra properties unknown to the type system will exist at runtime. +- Returns `undefined` from nullish values, to match the behaviour of most deep-key libraries like `lodash`, `dot-prop`, etc. +*/ +type PropertyOf = + BaseType extends null | undefined + ? undefined + : Key extends keyof BaseType + ? BaseType[Key] + : BaseType extends { + [n: number]: infer Item; + length: number; // Note: This is needed to avoid being too lax with records types using number keys like `{0: string; 1: boolean}`. + } + ? ( + ConsistsOnlyOf extends true + ? Item + : unknown + ) + : Key extends keyof WithStringKeys + ? WithStringKeys[Key] + : unknown; + +// This works by first splitting the path based on `.` and `[...]` characters into a tuple of string keys. Then it recursively uses the head key to get the next property of the current object, until there are no keys left. Number keys extract the item type from arrays, or are converted to strings to extract types from tuples and dictionaries with number keys. +/** +Get a deeply-nested property from an object using a key path, like Lodash's `.get()` function. + +Use-case: Retrieve a property from deep inside an API response or some other complex object. + +@example +``` +import {Get} from 'type-fest'; +import * as lodash from 'lodash'; + +const get = (object: BaseType, path: Path): Get => + lodash.get(object, path); + +interface ApiResponse { + hits: { + hits: Array<{ + _id: string + _source: { + name: Array<{ + given: string[] + family: string + }> + birthDate: string + } + }> + } +} + +const getName = (apiResponse: ApiResponse) => + get(apiResponse, 'hits.hits[0]._source.name'); + //=> Array<{given: string[]; family: string}> +``` +*/ +export type Get = GetWithPath>; diff --git a/node_modules/ansi-escapes/node_modules/type-fest/ts41/index.d.ts b/node_modules/ansi-escapes/node_modules/type-fest/ts41/index.d.ts new file mode 100644 index 0000000000000000000000000000000000000000..e49504c15a7fe4e530d908bc90f0474c06dc8149 --- /dev/null +++ b/node_modules/ansi-escapes/node_modules/type-fest/ts41/index.d.ts @@ -0,0 +1,10 @@ +// These are all the basic types that's compatible with all supported TypeScript versions. +export * from '../base'; + +// These are special types that require at least TypeScript 4.1. +export {CamelCase} from './camel-case'; +export {KebabCase} from './kebab-case'; +export {PascalCase} from './pascal-case'; +export {SnakeCase} from './snake-case'; +export {DelimiterCase} from './delimiter-case'; +export {Get} from './get'; diff --git a/node_modules/ansi-escapes/node_modules/type-fest/ts41/kebab-case.d.ts b/node_modules/ansi-escapes/node_modules/type-fest/ts41/kebab-case.d.ts new file mode 100644 index 0000000000000000000000000000000000000000..ba6a99d1fc94e134d587d4b5725d9da31f4b7f24 --- /dev/null +++ b/node_modules/ansi-escapes/node_modules/type-fest/ts41/kebab-case.d.ts @@ -0,0 +1,36 @@ +import {DelimiterCase} from './delimiter-case'; + +/** +Convert a string literal to kebab-case. + +This can be useful when, for example, converting a camel-cased object property to a kebab-cased CSS class name or a command-line flag. + +@example +``` +import {KebabCase} from 'type-fest'; + +// Simple + +const someVariable: KebabCase<'fooBar'> = 'foo-bar'; + +// Advanced + +type KebabCasedProps = { + [K in keyof T as KebabCase]: T[K] +}; + +interface CliOptions { + dryRun: boolean; + includeFile: string; + foo: number; +} + +const rawCliOptions: KebabCasedProps = { + 'dry-run': true, + 'include-file': 'bar.js', + foo: 123 +}; +``` +*/ + +export type KebabCase = DelimiterCase; diff --git a/node_modules/ansi-escapes/node_modules/type-fest/ts41/pascal-case.d.ts b/node_modules/ansi-escapes/node_modules/type-fest/ts41/pascal-case.d.ts new file mode 100644 index 0000000000000000000000000000000000000000..bfb2a3627e011cbb89817a7802f0b1b27d37be96 --- /dev/null +++ b/node_modules/ansi-escapes/node_modules/type-fest/ts41/pascal-case.d.ts @@ -0,0 +1,36 @@ +import {CamelCase} from './camel-case'; + +/** +Converts a string literal to pascal-case. + +@example +``` +import {PascalCase} from 'type-fest'; + +// Simple + +const someVariable: PascalCase<'foo-bar'> = 'FooBar'; + +// Advanced + +type PascalCaseProps = { + [K in keyof T as PascalCase]: T[K] +}; + +interface RawOptions { + 'dry-run': boolean; + 'full_family_name': string; + foo: number; +} + +const dbResult: CamelCasedProps = { + DryRun: true, + FullFamilyName: 'bar.js', + Foo: 123 +}; +``` +*/ + +export type PascalCase = CamelCase extends string + ? Capitalize> + : CamelCase; diff --git a/node_modules/ansi-escapes/node_modules/type-fest/ts41/snake-case.d.ts b/node_modules/ansi-escapes/node_modules/type-fest/ts41/snake-case.d.ts new file mode 100644 index 0000000000000000000000000000000000000000..272b3d359ea9232b0b54bb65d45b52d5bbcccea7 --- /dev/null +++ b/node_modules/ansi-escapes/node_modules/type-fest/ts41/snake-case.d.ts @@ -0,0 +1,35 @@ +import {DelimiterCase} from './delimiter-case'; + +/** +Convert a string literal to snake-case. + +This can be useful when, for example, converting a camel-cased object property to a snake-cased SQL column name. + +@example +``` +import {SnakeCase} from 'type-fest'; + +// Simple + +const someVariable: SnakeCase<'fooBar'> = 'foo_bar'; + +// Advanced + +type SnakeCasedProps = { + [K in keyof T as SnakeCase]: T[K] +}; + +interface ModelProps { + isHappy: boolean; + fullFamilyName: string; + foo: number; +} + +const dbResult: SnakeCasedProps = { + 'is_happy': true, + 'full_family_name': 'Carla Smith', + foo: 123 +}; +``` +*/ +export type SnakeCase = DelimiterCase; diff --git a/node_modules/ansi-escapes/node_modules/type-fest/ts41/utilities.d.ts b/node_modules/ansi-escapes/node_modules/type-fest/ts41/utilities.d.ts new file mode 100644 index 0000000000000000000000000000000000000000..f82e362fb936ddcbdc098b1179332984f8481e92 --- /dev/null +++ b/node_modules/ansi-escapes/node_modules/type-fest/ts41/utilities.d.ts @@ -0,0 +1,8 @@ +/** +Recursively split a string literal into two parts on the first occurence of the given string, returning an array literal of all the separate parts. +*/ +export type Split = + string extends S ? string[] : + S extends '' ? [] : + S extends `${infer T}${D}${infer U}` ? [T, ...Split] : + [S]; diff --git a/node_modules/ansi-escapes/package.json b/node_modules/ansi-escapes/package.json new file mode 100644 index 0000000000000000000000000000000000000000..88a9356c4192b084ae0614cd93650354c3852352 --- /dev/null +++ b/node_modules/ansi-escapes/package.json @@ -0,0 +1,57 @@ +{ + "name": "ansi-escapes", + "version": "4.3.2", + "description": "ANSI escape codes for manipulating the terminal", + "license": "MIT", + "repository": "sindresorhus/ansi-escapes", + "funding": "https://github.com/sponsors/sindresorhus", + "author": { + "name": "Sindre Sorhus", + "email": "sindresorhus@gmail.com", + "url": "https://sindresorhus.com" + }, + "engines": { + "node": ">=8" + }, + "scripts": { + "test": "xo && ava && tsd" + }, + "files": [ + "index.js", + "index.d.ts" + ], + "keywords": [ + "ansi", + "terminal", + "console", + "cli", + "string", + "tty", + "escape", + "escapes", + "formatting", + "shell", + "xterm", + "log", + "logging", + "command-line", + "text", + "vt100", + "sequence", + "control", + "code", + "codes", + "cursor", + "iterm", + "iterm2" + ], + "dependencies": { + "type-fest": "^0.21.3" + }, + "devDependencies": { + "@types/node": "^13.7.7", + "ava": "^2.1.0", + "tsd": "^0.14.0", + "xo": "^0.25.3" + } +} diff --git a/node_modules/ansi-escapes/readme.md b/node_modules/ansi-escapes/readme.md new file mode 100644 index 0000000000000000000000000000000000000000..9fbfec9923d0e6e6340c55aae79133dc0ebb9b8e --- /dev/null +++ b/node_modules/ansi-escapes/readme.md @@ -0,0 +1,245 @@ +# ansi-escapes + +> [ANSI escape codes](http://www.termsys.demon.co.uk/vtansi.htm) for manipulating the terminal + +## Install + +``` +$ npm install ansi-escapes +``` + +## Usage + +```js +const ansiEscapes = require('ansi-escapes'); + +// Moves the cursor two rows up and to the left +process.stdout.write(ansiEscapes.cursorUp(2) + ansiEscapes.cursorLeft); +//=> '\u001B[2A\u001B[1000D' +``` + +## API + +### cursorTo(x, y?) + +Set the absolute position of the cursor. `x0` `y0` is the top left of the screen. + +### cursorMove(x, y?) + +Set the position of the cursor relative to its current position. + +### cursorUp(count) + +Move cursor up a specific amount of rows. Default is `1`. + +### cursorDown(count) + +Move cursor down a specific amount of rows. Default is `1`. + +### cursorForward(count) + +Move cursor forward a specific amount of columns. Default is `1`. + +### cursorBackward(count) + +Move cursor backward a specific amount of columns. Default is `1`. + +### cursorLeft + +Move cursor to the left side. + +### cursorSavePosition + +Save cursor position. + +### cursorRestorePosition + +Restore saved cursor position. + +### cursorGetPosition + +Get cursor position. + +### cursorNextLine + +Move cursor to the next line. + +### cursorPrevLine + +Move cursor to the previous line. + +### cursorHide + +Hide cursor. + +### cursorShow + +Show cursor. + +### eraseLines(count) + +Erase from the current cursor position up the specified amount of rows. + +### eraseEndLine + +Erase from the current cursor position to the end of the current line. + +### eraseStartLine + +Erase from the current cursor position to the start of the current line. + +### eraseLine + +Erase the entire current line. + +### eraseDown + +Erase the screen from the current line down to the bottom of the screen. + +### eraseUp + +Erase the screen from the current line up to the top of the screen. + +### eraseScreen + +Erase the screen and move the cursor the top left position. + +### scrollUp + +Scroll display up one line. + +### scrollDown + +Scroll display down one line. + +### clearScreen + +Clear the terminal screen. (Viewport) + +### clearTerminal + +Clear the whole terminal, including scrollback buffer. (Not just the visible part of it) + +### beep + +Output a beeping sound. + +### link(text, url) + +Create a clickable link. + +[Supported terminals.](https://gist.github.com/egmontkob/eb114294efbcd5adb1944c9f3cb5feda) Use [`supports-hyperlinks`](https://github.com/jamestalmage/supports-hyperlinks) to detect link support. + +### image(filePath, options?) + +Display an image. + +*Currently only supported on iTerm2 >=3* + +See [term-img](https://github.com/sindresorhus/term-img) for a higher-level module. + +#### input + +Type: `Buffer` + +Buffer of an image. Usually read in with `fs.readFile()`. + +#### options + +Type: `object` + +##### width +##### height + +Type: `string | number` + +The width and height are given as a number followed by a unit, or the word "auto". + +- `N`: N character cells. +- `Npx`: N pixels. +- `N%`: N percent of the session's width or height. +- `auto`: The image's inherent size will be used to determine an appropriate dimension. + +##### preserveAspectRatio + +Type: `boolean`\ +Default: `true` + +### iTerm.setCwd(path?) + +Type: `string`\ +Default: `process.cwd()` + +[Inform iTerm2](https://www.iterm2.com/documentation-escape-codes.html) of the current directory to help semantic history and enable [Cmd-clicking relative paths](https://coderwall.com/p/b7e82q/quickly-open-files-in-iterm-with-cmd-click). + +### iTerm.annotation(message, options?) + +Creates an escape code to display an "annotation" in iTerm2. + +An annotation looks like this when shown: + + + +See the [iTerm Proprietary Escape Codes documentation](https://iterm2.com/documentation-escape-codes.html) for more information. + +#### message + +Type: `string` + +The message to display within the annotation. + +The `|` character is disallowed and will be stripped. + +#### options + +Type: `object` + +##### length + +Type: `number`\ +Default: The remainder of the line + +Nonzero number of columns to annotate. + +##### x + +Type: `number`\ +Default: Cursor position + +Starting X coordinate. + +Must be used with `y` and `length`. + +##### y + +Type: `number`\ +Default: Cursor position + +Starting Y coordinate. + +Must be used with `x` and `length`. + +##### isHidden + +Type: `boolean`\ +Default: `false` + +Create a "hidden" annotation. + +Annotations created this way can be shown using the "Show Annotations" iTerm command. + +## Related + +- [ansi-styles](https://github.com/chalk/ansi-styles) - ANSI escape codes for styling strings in the terminal + +--- + +
+ + Get professional support for this package with a Tidelift subscription + +
+ + Tidelift helps make open source sustainable for maintainers while giving companies
assurances about security, maintenance, and licensing for their dependencies. +
+
diff --git a/node_modules/ansi-regex/index.d.ts b/node_modules/ansi-regex/index.d.ts new file mode 100644 index 0000000000000000000000000000000000000000..2dbf6af2b6f3b5701c83caaea7ed2210192023a8 --- /dev/null +++ b/node_modules/ansi-regex/index.d.ts @@ -0,0 +1,37 @@ +declare namespace ansiRegex { + interface Options { + /** + Match only the first ANSI escape. + + @default false + */ + onlyFirst: boolean; + } +} + +/** +Regular expression for matching ANSI escape codes. + +@example +``` +import ansiRegex = require('ansi-regex'); + +ansiRegex().test('\u001B[4mcake\u001B[0m'); +//=> true + +ansiRegex().test('cake'); +//=> false + +'\u001B[4mcake\u001B[0m'.match(ansiRegex()); +//=> ['\u001B[4m', '\u001B[0m'] + +'\u001B[4mcake\u001B[0m'.match(ansiRegex({onlyFirst: true})); +//=> ['\u001B[4m'] + +'\u001B]8;;https://github.com\u0007click\u001B]8;;\u0007'.match(ansiRegex()); +//=> ['\u001B]8;;https://github.com\u0007', '\u001B]8;;\u0007'] +``` +*/ +declare function ansiRegex(options?: ansiRegex.Options): RegExp; + +export = ansiRegex; diff --git a/node_modules/ansi-regex/index.js b/node_modules/ansi-regex/index.js new file mode 100644 index 0000000000000000000000000000000000000000..616ff837d3ff01e028c208062fc699c7f1c8d418 --- /dev/null +++ b/node_modules/ansi-regex/index.js @@ -0,0 +1,10 @@ +'use strict'; + +module.exports = ({onlyFirst = false} = {}) => { + const pattern = [ + '[\\u001B\\u009B][[\\]()#;?]*(?:(?:(?:(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]+)*|[a-zA-Z\\d]+(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]*)*)?\\u0007)', + '(?:(?:\\d{1,4}(?:;\\d{0,4})*)?[\\dA-PR-TZcf-ntqry=><~]))' + ].join('|'); + + return new RegExp(pattern, onlyFirst ? undefined : 'g'); +}; diff --git a/node_modules/ansi-regex/license b/node_modules/ansi-regex/license new file mode 100644 index 0000000000000000000000000000000000000000..e7af2f77107d73046421ef56c4684cbfdd3c1e89 --- /dev/null +++ b/node_modules/ansi-regex/license @@ -0,0 +1,9 @@ +MIT License + +Copyright (c) Sindre Sorhus (sindresorhus.com) + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/node_modules/ansi-regex/package.json b/node_modules/ansi-regex/package.json new file mode 100644 index 0000000000000000000000000000000000000000..017f53116a9e2805ccb12efc3c7fcd7e4384735d --- /dev/null +++ b/node_modules/ansi-regex/package.json @@ -0,0 +1,55 @@ +{ + "name": "ansi-regex", + "version": "5.0.1", + "description": "Regular expression for matching ANSI escape codes", + "license": "MIT", + "repository": "chalk/ansi-regex", + "author": { + "name": "Sindre Sorhus", + "email": "sindresorhus@gmail.com", + "url": "sindresorhus.com" + }, + "engines": { + "node": ">=8" + }, + "scripts": { + "test": "xo && ava && tsd", + "view-supported": "node fixtures/view-codes.js" + }, + "files": [ + "index.js", + "index.d.ts" + ], + "keywords": [ + "ansi", + "styles", + "color", + "colour", + "colors", + "terminal", + "console", + "cli", + "string", + "tty", + "escape", + "formatting", + "rgb", + "256", + "shell", + "xterm", + "command-line", + "text", + "regex", + "regexp", + "re", + "match", + "test", + "find", + "pattern" + ], + "devDependencies": { + "ava": "^2.4.0", + "tsd": "^0.9.0", + "xo": "^0.25.3" + } +} diff --git a/node_modules/ansi-regex/readme.md b/node_modules/ansi-regex/readme.md new file mode 100644 index 0000000000000000000000000000000000000000..4d848bc36f6b862e5db3effa59ebed515730284e --- /dev/null +++ b/node_modules/ansi-regex/readme.md @@ -0,0 +1,78 @@ +# ansi-regex + +> Regular expression for matching [ANSI escape codes](https://en.wikipedia.org/wiki/ANSI_escape_code) + + +## Install + +``` +$ npm install ansi-regex +``` + + +## Usage + +```js +const ansiRegex = require('ansi-regex'); + +ansiRegex().test('\u001B[4mcake\u001B[0m'); +//=> true + +ansiRegex().test('cake'); +//=> false + +'\u001B[4mcake\u001B[0m'.match(ansiRegex()); +//=> ['\u001B[4m', '\u001B[0m'] + +'\u001B[4mcake\u001B[0m'.match(ansiRegex({onlyFirst: true})); +//=> ['\u001B[4m'] + +'\u001B]8;;https://github.com\u0007click\u001B]8;;\u0007'.match(ansiRegex()); +//=> ['\u001B]8;;https://github.com\u0007', '\u001B]8;;\u0007'] +``` + + +## API + +### ansiRegex(options?) + +Returns a regex for matching ANSI escape codes. + +#### options + +Type: `object` + +##### onlyFirst + +Type: `boolean`
+Default: `false` *(Matches any ANSI escape codes in a string)* + +Match only the first ANSI escape. + + +## FAQ + +### Why do you test for codes not in the ECMA 48 standard? + +Some of the codes we run as a test are codes that we acquired finding various lists of non-standard or manufacturer specific codes. We test for both standard and non-standard codes, as most of them follow the same or similar format and can be safely matched in strings without the risk of removing actual string content. There are a few non-standard control codes that do not follow the traditional format (i.e. they end in numbers) thus forcing us to exclude them from the test because we cannot reliably match them. + +On the historical side, those ECMA standards were established in the early 90's whereas the VT100, for example, was designed in the mid/late 70's. At that point in time, control codes were still pretty ungoverned and engineers used them for a multitude of things, namely to activate hardware ports that may have been proprietary. Somewhere else you see a similar 'anarchy' of codes is in the x86 architecture for processors; there are a ton of "interrupts" that can mean different things on certain brands of processors, most of which have been phased out. + + +## Maintainers + +- [Sindre Sorhus](https://github.com/sindresorhus) +- [Josh Junon](https://github.com/qix-) + + +--- + +
+ + Get professional support for this package with a Tidelift subscription + +
+ + Tidelift helps make open source sustainable for maintainers while giving companies
assurances about security, maintenance, and licensing for their dependencies. +
+
diff --git a/node_modules/ansi-styles/index.d.ts b/node_modules/ansi-styles/index.d.ts new file mode 100644 index 0000000000000000000000000000000000000000..44a907e580f1055a36d44111fda9463ed1cd2d26 --- /dev/null +++ b/node_modules/ansi-styles/index.d.ts @@ -0,0 +1,345 @@ +declare type CSSColor = + | 'aliceblue' + | 'antiquewhite' + | 'aqua' + | 'aquamarine' + | 'azure' + | 'beige' + | 'bisque' + | 'black' + | 'blanchedalmond' + | 'blue' + | 'blueviolet' + | 'brown' + | 'burlywood' + | 'cadetblue' + | 'chartreuse' + | 'chocolate' + | 'coral' + | 'cornflowerblue' + | 'cornsilk' + | 'crimson' + | 'cyan' + | 'darkblue' + | 'darkcyan' + | 'darkgoldenrod' + | 'darkgray' + | 'darkgreen' + | 'darkgrey' + | 'darkkhaki' + | 'darkmagenta' + | 'darkolivegreen' + | 'darkorange' + | 'darkorchid' + | 'darkred' + | 'darksalmon' + | 'darkseagreen' + | 'darkslateblue' + | 'darkslategray' + | 'darkslategrey' + | 'darkturquoise' + | 'darkviolet' + | 'deeppink' + | 'deepskyblue' + | 'dimgray' + | 'dimgrey' + | 'dodgerblue' + | 'firebrick' + | 'floralwhite' + | 'forestgreen' + | 'fuchsia' + | 'gainsboro' + | 'ghostwhite' + | 'gold' + | 'goldenrod' + | 'gray' + | 'green' + | 'greenyellow' + | 'grey' + | 'honeydew' + | 'hotpink' + | 'indianred' + | 'indigo' + | 'ivory' + | 'khaki' + | 'lavender' + | 'lavenderblush' + | 'lawngreen' + | 'lemonchiffon' + | 'lightblue' + | 'lightcoral' + | 'lightcyan' + | 'lightgoldenrodyellow' + | 'lightgray' + | 'lightgreen' + | 'lightgrey' + | 'lightpink' + | 'lightsalmon' + | 'lightseagreen' + | 'lightskyblue' + | 'lightslategray' + | 'lightslategrey' + | 'lightsteelblue' + | 'lightyellow' + | 'lime' + | 'limegreen' + | 'linen' + | 'magenta' + | 'maroon' + | 'mediumaquamarine' + | 'mediumblue' + | 'mediumorchid' + | 'mediumpurple' + | 'mediumseagreen' + | 'mediumslateblue' + | 'mediumspringgreen' + | 'mediumturquoise' + | 'mediumvioletred' + | 'midnightblue' + | 'mintcream' + | 'mistyrose' + | 'moccasin' + | 'navajowhite' + | 'navy' + | 'oldlace' + | 'olive' + | 'olivedrab' + | 'orange' + | 'orangered' + | 'orchid' + | 'palegoldenrod' + | 'palegreen' + | 'paleturquoise' + | 'palevioletred' + | 'papayawhip' + | 'peachpuff' + | 'peru' + | 'pink' + | 'plum' + | 'powderblue' + | 'purple' + | 'rebeccapurple' + | 'red' + | 'rosybrown' + | 'royalblue' + | 'saddlebrown' + | 'salmon' + | 'sandybrown' + | 'seagreen' + | 'seashell' + | 'sienna' + | 'silver' + | 'skyblue' + | 'slateblue' + | 'slategray' + | 'slategrey' + | 'snow' + | 'springgreen' + | 'steelblue' + | 'tan' + | 'teal' + | 'thistle' + | 'tomato' + | 'turquoise' + | 'violet' + | 'wheat' + | 'white' + | 'whitesmoke' + | 'yellow' + | 'yellowgreen'; + +declare namespace ansiStyles { + interface ColorConvert { + /** + The RGB color space. + + @param red - (`0`-`255`) + @param green - (`0`-`255`) + @param blue - (`0`-`255`) + */ + rgb(red: number, green: number, blue: number): string; + + /** + The RGB HEX color space. + + @param hex - A hexadecimal string containing RGB data. + */ + hex(hex: string): string; + + /** + @param keyword - A CSS color name. + */ + keyword(keyword: CSSColor): string; + + /** + The HSL color space. + + @param hue - (`0`-`360`) + @param saturation - (`0`-`100`) + @param lightness - (`0`-`100`) + */ + hsl(hue: number, saturation: number, lightness: number): string; + + /** + The HSV color space. + + @param hue - (`0`-`360`) + @param saturation - (`0`-`100`) + @param value - (`0`-`100`) + */ + hsv(hue: number, saturation: number, value: number): string; + + /** + The HSV color space. + + @param hue - (`0`-`360`) + @param whiteness - (`0`-`100`) + @param blackness - (`0`-`100`) + */ + hwb(hue: number, whiteness: number, blackness: number): string; + + /** + Use a [4-bit unsigned number](https://en.wikipedia.org/wiki/ANSI_escape_code#3/4-bit) to set text color. + */ + ansi(ansi: number): string; + + /** + Use an [8-bit unsigned number](https://en.wikipedia.org/wiki/ANSI_escape_code#8-bit) to set text color. + */ + ansi256(ansi: number): string; + } + + interface CSPair { + /** + The ANSI terminal control sequence for starting this style. + */ + readonly open: string; + + /** + The ANSI terminal control sequence for ending this style. + */ + readonly close: string; + } + + interface ColorBase { + readonly ansi: ColorConvert; + readonly ansi256: ColorConvert; + readonly ansi16m: ColorConvert; + + /** + The ANSI terminal control sequence for ending this color. + */ + readonly close: string; + } + + interface Modifier { + /** + Resets the current color chain. + */ + readonly reset: CSPair; + + /** + Make text bold. + */ + readonly bold: CSPair; + + /** + Emitting only a small amount of light. + */ + readonly dim: CSPair; + + /** + Make text italic. (Not widely supported) + */ + readonly italic: CSPair; + + /** + Make text underline. (Not widely supported) + */ + readonly underline: CSPair; + + /** + Inverse background and foreground colors. + */ + readonly inverse: CSPair; + + /** + Prints the text, but makes it invisible. + */ + readonly hidden: CSPair; + + /** + Puts a horizontal line through the center of the text. (Not widely supported) + */ + readonly strikethrough: CSPair; + } + + interface ForegroundColor { + readonly black: CSPair; + readonly red: CSPair; + readonly green: CSPair; + readonly yellow: CSPair; + readonly blue: CSPair; + readonly cyan: CSPair; + readonly magenta: CSPair; + readonly white: CSPair; + + /** + Alias for `blackBright`. + */ + readonly gray: CSPair; + + /** + Alias for `blackBright`. + */ + readonly grey: CSPair; + + readonly blackBright: CSPair; + readonly redBright: CSPair; + readonly greenBright: CSPair; + readonly yellowBright: CSPair; + readonly blueBright: CSPair; + readonly cyanBright: CSPair; + readonly magentaBright: CSPair; + readonly whiteBright: CSPair; + } + + interface BackgroundColor { + readonly bgBlack: CSPair; + readonly bgRed: CSPair; + readonly bgGreen: CSPair; + readonly bgYellow: CSPair; + readonly bgBlue: CSPair; + readonly bgCyan: CSPair; + readonly bgMagenta: CSPair; + readonly bgWhite: CSPair; + + /** + Alias for `bgBlackBright`. + */ + readonly bgGray: CSPair; + + /** + Alias for `bgBlackBright`. + */ + readonly bgGrey: CSPair; + + readonly bgBlackBright: CSPair; + readonly bgRedBright: CSPair; + readonly bgGreenBright: CSPair; + readonly bgYellowBright: CSPair; + readonly bgBlueBright: CSPair; + readonly bgCyanBright: CSPair; + readonly bgMagentaBright: CSPair; + readonly bgWhiteBright: CSPair; + } +} + +declare const ansiStyles: { + readonly modifier: ansiStyles.Modifier; + readonly color: ansiStyles.ForegroundColor & ansiStyles.ColorBase; + readonly bgColor: ansiStyles.BackgroundColor & ansiStyles.ColorBase; + readonly codes: ReadonlyMap; +} & ansiStyles.BackgroundColor & ansiStyles.ForegroundColor & ansiStyles.Modifier; + +export = ansiStyles; diff --git a/node_modules/ansi-styles/index.js b/node_modules/ansi-styles/index.js new file mode 100644 index 0000000000000000000000000000000000000000..5d82581a13f9900f9dc653b2df9f0027ee8bdda1 --- /dev/null +++ b/node_modules/ansi-styles/index.js @@ -0,0 +1,163 @@ +'use strict'; + +const wrapAnsi16 = (fn, offset) => (...args) => { + const code = fn(...args); + return `\u001B[${code + offset}m`; +}; + +const wrapAnsi256 = (fn, offset) => (...args) => { + const code = fn(...args); + return `\u001B[${38 + offset};5;${code}m`; +}; + +const wrapAnsi16m = (fn, offset) => (...args) => { + const rgb = fn(...args); + return `\u001B[${38 + offset};2;${rgb[0]};${rgb[1]};${rgb[2]}m`; +}; + +const ansi2ansi = n => n; +const rgb2rgb = (r, g, b) => [r, g, b]; + +const setLazyProperty = (object, property, get) => { + Object.defineProperty(object, property, { + get: () => { + const value = get(); + + Object.defineProperty(object, property, { + value, + enumerable: true, + configurable: true + }); + + return value; + }, + enumerable: true, + configurable: true + }); +}; + +/** @type {typeof import('color-convert')} */ +let colorConvert; +const makeDynamicStyles = (wrap, targetSpace, identity, isBackground) => { + if (colorConvert === undefined) { + colorConvert = require('color-convert'); + } + + const offset = isBackground ? 10 : 0; + const styles = {}; + + for (const [sourceSpace, suite] of Object.entries(colorConvert)) { + const name = sourceSpace === 'ansi16' ? 'ansi' : sourceSpace; + if (sourceSpace === targetSpace) { + styles[name] = wrap(identity, offset); + } else if (typeof suite === 'object') { + styles[name] = wrap(suite[targetSpace], offset); + } + } + + return styles; +}; + +function assembleStyles() { + const codes = new Map(); + const styles = { + modifier: { + reset: [0, 0], + // 21 isn't widely supported and 22 does the same thing + bold: [1, 22], + dim: [2, 22], + italic: [3, 23], + underline: [4, 24], + inverse: [7, 27], + hidden: [8, 28], + strikethrough: [9, 29] + }, + color: { + black: [30, 39], + red: [31, 39], + green: [32, 39], + yellow: [33, 39], + blue: [34, 39], + magenta: [35, 39], + cyan: [36, 39], + white: [37, 39], + + // Bright color + blackBright: [90, 39], + redBright: [91, 39], + greenBright: [92, 39], + yellowBright: [93, 39], + blueBright: [94, 39], + magentaBright: [95, 39], + cyanBright: [96, 39], + whiteBright: [97, 39] + }, + bgColor: { + bgBlack: [40, 49], + bgRed: [41, 49], + bgGreen: [42, 49], + bgYellow: [43, 49], + bgBlue: [44, 49], + bgMagenta: [45, 49], + bgCyan: [46, 49], + bgWhite: [47, 49], + + // Bright color + bgBlackBright: [100, 49], + bgRedBright: [101, 49], + bgGreenBright: [102, 49], + bgYellowBright: [103, 49], + bgBlueBright: [104, 49], + bgMagentaBright: [105, 49], + bgCyanBright: [106, 49], + bgWhiteBright: [107, 49] + } + }; + + // Alias bright black as gray (and grey) + styles.color.gray = styles.color.blackBright; + styles.bgColor.bgGray = styles.bgColor.bgBlackBright; + styles.color.grey = styles.color.blackBright; + styles.bgColor.bgGrey = styles.bgColor.bgBlackBright; + + for (const [groupName, group] of Object.entries(styles)) { + for (const [styleName, style] of Object.entries(group)) { + styles[styleName] = { + open: `\u001B[${style[0]}m`, + close: `\u001B[${style[1]}m` + }; + + group[styleName] = styles[styleName]; + + codes.set(style[0], style[1]); + } + + Object.defineProperty(styles, groupName, { + value: group, + enumerable: false + }); + } + + Object.defineProperty(styles, 'codes', { + value: codes, + enumerable: false + }); + + styles.color.close = '\u001B[39m'; + styles.bgColor.close = '\u001B[49m'; + + setLazyProperty(styles.color, 'ansi', () => makeDynamicStyles(wrapAnsi16, 'ansi16', ansi2ansi, false)); + setLazyProperty(styles.color, 'ansi256', () => makeDynamicStyles(wrapAnsi256, 'ansi256', ansi2ansi, false)); + setLazyProperty(styles.color, 'ansi16m', () => makeDynamicStyles(wrapAnsi16m, 'rgb', rgb2rgb, false)); + setLazyProperty(styles.bgColor, 'ansi', () => makeDynamicStyles(wrapAnsi16, 'ansi16', ansi2ansi, true)); + setLazyProperty(styles.bgColor, 'ansi256', () => makeDynamicStyles(wrapAnsi256, 'ansi256', ansi2ansi, true)); + setLazyProperty(styles.bgColor, 'ansi16m', () => makeDynamicStyles(wrapAnsi16m, 'rgb', rgb2rgb, true)); + + return styles; +} + +// Make the export immutable +Object.defineProperty(module, 'exports', { + enumerable: true, + get: assembleStyles +}); diff --git a/node_modules/ansi-styles/license b/node_modules/ansi-styles/license new file mode 100644 index 0000000000000000000000000000000000000000..e7af2f77107d73046421ef56c4684cbfdd3c1e89 --- /dev/null +++ b/node_modules/ansi-styles/license @@ -0,0 +1,9 @@ +MIT License + +Copyright (c) Sindre Sorhus (sindresorhus.com) + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/node_modules/ansi-styles/package.json b/node_modules/ansi-styles/package.json new file mode 100644 index 0000000000000000000000000000000000000000..75393284d7e474de2c7fb1ee7d09169a6790c7da --- /dev/null +++ b/node_modules/ansi-styles/package.json @@ -0,0 +1,56 @@ +{ + "name": "ansi-styles", + "version": "4.3.0", + "description": "ANSI escape codes for styling strings in the terminal", + "license": "MIT", + "repository": "chalk/ansi-styles", + "funding": "https://github.com/chalk/ansi-styles?sponsor=1", + "author": { + "name": "Sindre Sorhus", + "email": "sindresorhus@gmail.com", + "url": "sindresorhus.com" + }, + "engines": { + "node": ">=8" + }, + "scripts": { + "test": "xo && ava && tsd", + "screenshot": "svg-term --command='node screenshot' --out=screenshot.svg --padding=3 --width=55 --height=3 --at=1000 --no-cursor" + }, + "files": [ + "index.js", + "index.d.ts" + ], + "keywords": [ + "ansi", + "styles", + "color", + "colour", + "colors", + "terminal", + "console", + "cli", + "string", + "tty", + "escape", + "formatting", + "rgb", + "256", + "shell", + "xterm", + "log", + "logging", + "command-line", + "text" + ], + "dependencies": { + "color-convert": "^2.0.1" + }, + "devDependencies": { + "@types/color-convert": "^1.9.0", + "ava": "^2.3.0", + "svg-term-cli": "^2.1.1", + "tsd": "^0.11.0", + "xo": "^0.25.3" + } +} diff --git a/node_modules/ansi-styles/readme.md b/node_modules/ansi-styles/readme.md new file mode 100644 index 0000000000000000000000000000000000000000..24883de808be6a7480542114a86034312c026dec --- /dev/null +++ b/node_modules/ansi-styles/readme.md @@ -0,0 +1,152 @@ +# ansi-styles [![Build Status](https://travis-ci.org/chalk/ansi-styles.svg?branch=master)](https://travis-ci.org/chalk/ansi-styles) + +> [ANSI escape codes](https://en.wikipedia.org/wiki/ANSI_escape_code#Colors_and_Styles) for styling strings in the terminal + +You probably want the higher-level [chalk](https://github.com/chalk/chalk) module for styling your strings. + + + +## Install + +``` +$ npm install ansi-styles +``` + +## Usage + +```js +const style = require('ansi-styles'); + +console.log(`${style.green.open}Hello world!${style.green.close}`); + + +// Color conversion between 16/256/truecolor +// NOTE: If conversion goes to 16 colors or 256 colors, the original color +// may be degraded to fit that color palette. This means terminals +// that do not support 16 million colors will best-match the +// original color. +console.log(style.bgColor.ansi.hsl(120, 80, 72) + 'Hello world!' + style.bgColor.close); +console.log(style.color.ansi256.rgb(199, 20, 250) + 'Hello world!' + style.color.close); +console.log(style.color.ansi16m.hex('#abcdef') + 'Hello world!' + style.color.close); +``` + +## API + +Each style has an `open` and `close` property. + +## Styles + +### Modifiers + +- `reset` +- `bold` +- `dim` +- `italic` *(Not widely supported)* +- `underline` +- `inverse` +- `hidden` +- `strikethrough` *(Not widely supported)* + +### Colors + +- `black` +- `red` +- `green` +- `yellow` +- `blue` +- `magenta` +- `cyan` +- `white` +- `blackBright` (alias: `gray`, `grey`) +- `redBright` +- `greenBright` +- `yellowBright` +- `blueBright` +- `magentaBright` +- `cyanBright` +- `whiteBright` + +### Background colors + +- `bgBlack` +- `bgRed` +- `bgGreen` +- `bgYellow` +- `bgBlue` +- `bgMagenta` +- `bgCyan` +- `bgWhite` +- `bgBlackBright` (alias: `bgGray`, `bgGrey`) +- `bgRedBright` +- `bgGreenBright` +- `bgYellowBright` +- `bgBlueBright` +- `bgMagentaBright` +- `bgCyanBright` +- `bgWhiteBright` + +## Advanced usage + +By default, you get a map of styles, but the styles are also available as groups. They are non-enumerable so they don't show up unless you access them explicitly. This makes it easier to expose only a subset in a higher-level module. + +- `style.modifier` +- `style.color` +- `style.bgColor` + +###### Example + +```js +console.log(style.color.green.open); +``` + +Raw escape codes (i.e. without the CSI escape prefix `\u001B[` and render mode postfix `m`) are available under `style.codes`, which returns a `Map` with the open codes as keys and close codes as values. + +###### Example + +```js +console.log(style.codes.get(36)); +//=> 39 +``` + +## [256 / 16 million (TrueColor) support](https://gist.github.com/XVilka/8346728) + +`ansi-styles` uses the [`color-convert`](https://github.com/Qix-/color-convert) package to allow for converting between various colors and ANSI escapes, with support for 256 and 16 million colors. + +The following color spaces from `color-convert` are supported: + +- `rgb` +- `hex` +- `keyword` +- `hsl` +- `hsv` +- `hwb` +- `ansi` +- `ansi256` + +To use these, call the associated conversion function with the intended output, for example: + +```js +style.color.ansi.rgb(100, 200, 15); // RGB to 16 color ansi foreground code +style.bgColor.ansi.rgb(100, 200, 15); // RGB to 16 color ansi background code + +style.color.ansi256.hsl(120, 100, 60); // HSL to 256 color ansi foreground code +style.bgColor.ansi256.hsl(120, 100, 60); // HSL to 256 color ansi foreground code + +style.color.ansi16m.hex('#C0FFEE'); // Hex (RGB) to 16 million color foreground code +style.bgColor.ansi16m.hex('#C0FFEE'); // Hex (RGB) to 16 million color background code +``` + +## Related + +- [ansi-escapes](https://github.com/sindresorhus/ansi-escapes) - ANSI escape codes for manipulating the terminal + +## Maintainers + +- [Sindre Sorhus](https://github.com/sindresorhus) +- [Josh Junon](https://github.com/qix-) + +## For enterprise + +Available as part of the Tidelift Subscription. + +The maintainers of `ansi-styles` and thousands of other packages are working with Tidelift to deliver commercial support and maintenance for the open source dependencies you use to build your applications. Save time, reduce risk, and improve code health, while paying the maintainers of the exact dependencies you use. [Learn more.](https://tidelift.com/subscription/pkg/npm-ansi-styles?utm_source=npm-ansi-styles&utm_medium=referral&utm_campaign=enterprise&utm_term=repo) diff --git a/node_modules/bufferutil/LICENSE b/node_modules/bufferutil/LICENSE new file mode 100644 index 0000000000000000000000000000000000000000..1da5b96a11ac2c83160e3085188f04eba7e3dd7d --- /dev/null +++ b/node_modules/bufferutil/LICENSE @@ -0,0 +1,20 @@ +Copyright (c) 2011 Einar Otto Stangvik +Copyright (c) 2013 Arnout Kazemier and contributors +Copyright (c) 2016 Luigi Pinca and contributors + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/node_modules/bufferutil/README.md b/node_modules/bufferutil/README.md new file mode 100644 index 0000000000000000000000000000000000000000..feb6318a4322e4fee20125f5266721ba15cbacc9 --- /dev/null +++ b/node_modules/bufferutil/README.md @@ -0,0 +1,79 @@ +# bufferutil + +[![Version npm](https://img.shields.io/npm/v/bufferutil.svg?logo=npm)](https://www.npmjs.com/package/bufferutil) +[![Linux/macOS/Windows Build](https://img.shields.io/github/actions/workflow/status/websockets/bufferutil/ci.yml?branch=master&label=build&logo=github)](https://github.com/websockets/bufferutil/actions?query=workflow%3ACI+branch%3Amaster) + +`bufferutil` is what makes `ws` fast. It provides some utilities to efficiently +perform some operations such as masking and unmasking the data payload of +WebSocket frames. + +## Installation + +``` +npm install bufferutil --save-optional +``` + +The `--save-optional` flag tells npm to save the package in your package.json +under the +[`optionalDependencies`](https://docs.npmjs.com/files/package.json#optionaldependencies) +key. + +## API + +The module exports two functions. To maximize performance, parameters are not +validated. It is the caller's responsibility to ensure that they are correct. + +### `bufferUtil.mask(source, mask, output, offset, length)` + +Masks a buffer using the given masking-key as specified by the WebSocket +protocol. + +#### Arguments + +- `source` - The buffer to mask. +- `mask` - A buffer representing the masking-key. +- `output` - The buffer where to store the result. +- `offset` - The offset at which to start writing. +- `length` - The number of bytes to mask. + +#### Example + +```js +'use strict'; + +const bufferUtil = require('bufferutil'); +const crypto = require('crypto'); + +const source = crypto.randomBytes(10); +const mask = crypto.randomBytes(4); + +bufferUtil.mask(source, mask, source, 0, source.length); +``` + +### `bufferUtil.unmask(buffer, mask)` + +Unmasks a buffer using the given masking-key as specified by the WebSocket +protocol. + +#### Arguments + +- `buffer` - The buffer to unmask. +- `mask` - A buffer representing the masking-key. + +#### Example + +```js +'use strict'; + +const bufferUtil = require('bufferutil'); +const crypto = require('crypto'); + +const buffer = crypto.randomBytes(10); +const mask = crypto.randomBytes(4); + +bufferUtil.unmask(buffer, mask); +``` + +## License + +[MIT](LICENSE) diff --git a/node_modules/bufferutil/binding.gyp b/node_modules/bufferutil/binding.gyp new file mode 100644 index 0000000000000000000000000000000000000000..cb8bb9929fd559ca4e44c1d47623ea513f9c6c95 --- /dev/null +++ b/node_modules/bufferutil/binding.gyp @@ -0,0 +1,32 @@ +{ + 'variables': { + 'openssl_fips': '' + }, + 'targets': [ + { + 'target_name': 'bufferutil', + 'sources': ['src/bufferutil.c'], + 'cflags': ['-std=c99'], + 'conditions': [ + ["OS=='mac'", { + 'variables': { + 'clang_version': + '&1 | perl -ne \'print $1 if /clang version ([0-9]+(\\.[0-9]+){2,})/\')' + }, + 'xcode_settings': { + 'MACOSX_DEPLOYMENT_TARGET': '10.7' + }, + 'conditions': [ + # Use Perl v-strings to compare versions. + ['clang_version and { + for (var i = 0; i < length; i++) { + output[offset + i] = source[i] ^ mask[i & 3]; + } +}; + +/** + * Unmasks a buffer using the given mask. + * + * @param {Buffer} buffer The buffer to unmask + * @param {Buffer} mask The mask to use + * @public + */ +const unmask = (buffer, mask) => { + // Required until https://github.com/nodejs/node/issues/9006 is resolved. + const length = buffer.length; + for (var i = 0; i < length; i++) { + buffer[i] ^= mask[i & 3]; + } +}; + +module.exports = { mask, unmask }; diff --git a/node_modules/bufferutil/index.js b/node_modules/bufferutil/index.js new file mode 100644 index 0000000000000000000000000000000000000000..8c30561aeac3f5b453f715b38af850c45a69095f --- /dev/null +++ b/node_modules/bufferutil/index.js @@ -0,0 +1,7 @@ +'use strict'; + +try { + module.exports = require('node-gyp-build')(__dirname); +} catch (e) { + module.exports = require('./fallback'); +} diff --git a/node_modules/bufferutil/package.json b/node_modules/bufferutil/package.json new file mode 100644 index 0000000000000000000000000000000000000000..0d77b90714666213bdbc31433d7b7c75a71cd0dd --- /dev/null +++ b/node_modules/bufferutil/package.json @@ -0,0 +1,36 @@ +{ + "name": "bufferutil", + "version": "4.0.9", + "description": "WebSocket buffer utils", + "main": "index.js", + "engines": { + "node": ">=6.14.2" + }, + "scripts": { + "install": "node-gyp-build", + "prebuild": "prebuildify --napi --strip --target=8.11.2", + "prebuild-darwin-x64+arm64": "prebuildify --arch x64+arm64 --napi --strip --target=8.11.2", + "test": "mocha" + }, + "repository": { + "type": "git", + "url": "https://github.com/websockets/bufferutil" + }, + "keywords": [ + "bufferutil" + ], + "author": "Einar Otto Stangvik (http://2x.io)", + "license": "MIT", + "bugs": { + "url": "https://github.com/websockets/bufferutil/issues" + }, + "homepage": "https://github.com/websockets/bufferutil", + "dependencies": { + "node-gyp-build": "^4.3.0" + }, + "devDependencies": { + "mocha": "^11.0.1", + "node-gyp": "^11.0.0", + "prebuildify": "^6.0.0" + } +} diff --git a/node_modules/bufferutil/prebuilds/darwin-x64+arm64/bufferutil.node b/node_modules/bufferutil/prebuilds/darwin-x64+arm64/bufferutil.node new file mode 100644 index 0000000000000000000000000000000000000000..f95fe28876951f67539cec876e40f8490b9d7fee --- /dev/null +++ b/node_modules/bufferutil/prebuilds/darwin-x64+arm64/bufferutil.node @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:ec4a2f3ee4b260eec19354e364ecd6aaf927009983523ec92a4a76e1e67097e6 +size 66976 diff --git a/node_modules/bufferutil/prebuilds/linux-x64/bufferutil.node b/node_modules/bufferutil/prebuilds/linux-x64/bufferutil.node new file mode 100644 index 0000000000000000000000000000000000000000..c412437e5f11ab7de00a53af35516b40f7a08595 --- /dev/null +++ b/node_modules/bufferutil/prebuilds/linux-x64/bufferutil.node @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:2efb202a47d8baa6887b8df67729469eae0017d4f893885c42402eee74bd60b2 +size 14576 diff --git a/node_modules/bufferutil/prebuilds/win32-ia32/bufferutil.node b/node_modules/bufferutil/prebuilds/win32-ia32/bufferutil.node new file mode 100644 index 0000000000000000000000000000000000000000..69bc2eca60d077eaa1b547c7bdee67100b5f9758 --- /dev/null +++ b/node_modules/bufferutil/prebuilds/win32-ia32/bufferutil.node @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:4a175aaff948f99767fb490598cd01ca43223e30a18bd27a66ce8db88fe18247 +size 126976 diff --git a/node_modules/bufferutil/prebuilds/win32-x64/bufferutil.node b/node_modules/bufferutil/prebuilds/win32-x64/bufferutil.node new file mode 100644 index 0000000000000000000000000000000000000000..803393dca32c76154363dc4093e5ff6a59b455f4 --- /dev/null +++ b/node_modules/bufferutil/prebuilds/win32-x64/bufferutil.node @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:4a6ebefbb829dad1496b3104957d56d4282a7b25240d9f84f11d9c718a01d8d3 +size 153600 diff --git a/node_modules/bufferutil/src/bufferutil.c b/node_modules/bufferutil/src/bufferutil.c new file mode 100644 index 0000000000000000000000000000000000000000..b89f8dd17edb3687c442e6e3708ec13afa2fc9d9 --- /dev/null +++ b/node_modules/bufferutil/src/bufferutil.c @@ -0,0 +1,171 @@ +#define NAPI_VERSION 1 +#include +#include + +napi_value Mask(napi_env env, napi_callback_info info) { + napi_status status; + size_t argc = 5; + napi_value argv[5]; + + status = napi_get_cb_info(env, info, &argc, argv, NULL, NULL); + assert(status == napi_ok); + + uint8_t *source; + uint8_t *mask; + uint8_t *destination; + uint32_t offset; + uint32_t length; + + status = napi_get_buffer_info(env, argv[0], (void **)&source, NULL); + assert(status == napi_ok); + + status = napi_get_buffer_info(env, argv[1], (void **)&mask, NULL); + assert(status == napi_ok); + + status = napi_get_buffer_info(env, argv[2], (void **)&destination, NULL); + assert(status == napi_ok); + + status = napi_get_value_uint32(env, argv[3], &offset); + assert(status == napi_ok); + + status = napi_get_value_uint32(env, argv[4], &length); + assert(status == napi_ok); + + destination += offset; + uint32_t index = 0; + + // + // Alignment preamble. + // + while (index < length && ((size_t)source % 8)) { + *destination++ = *source++ ^ mask[index % 4]; + index++; + } + + length -= index; + if (!length) + return NULL; + + // + // Realign mask and convert to 64 bit. + // + uint8_t maskAlignedArray[8]; + + for (uint8_t i = 0; i < 8; i++, index++) { + maskAlignedArray[i] = mask[index % 4]; + } + + // + // Apply 64 bit mask in 8 byte chunks. + // + uint32_t loop = length / 8; + uint64_t *pMask8 = (uint64_t *)maskAlignedArray; + + while (loop--) { + uint64_t *pFrom8 = (uint64_t *)source; + uint64_t *pTo8 = (uint64_t *)destination; + *pTo8 = *pFrom8 ^ *pMask8; + source += 8; + destination += 8; + } + + // + // Apply mask to remaining data. + // + uint8_t *pmaskAlignedArray = maskAlignedArray; + + length %= 8; + while (length--) { + *destination++ = *source++ ^ *pmaskAlignedArray++; + } + + return NULL; +} + +napi_value Unmask(napi_env env, napi_callback_info info) { + napi_status status; + size_t argc = 2; + napi_value argv[2]; + + status = napi_get_cb_info(env, info, &argc, argv, NULL, NULL); + assert(status == napi_ok); + + uint8_t *source; + size_t length; + uint8_t *mask; + + status = napi_get_buffer_info(env, argv[0], (void **)&source, &length); + assert(status == napi_ok); + + status = napi_get_buffer_info(env, argv[1], (void **)&mask, NULL); + assert(status == napi_ok); + + uint32_t index = 0; + + // + // Alignment preamble. + // + while (index < length && ((size_t)source % 8)) { + *source++ ^= mask[index % 4]; + index++; + } + + length -= index; + if (!length) + return NULL; + + // + // Realign mask and convert to 64 bit. + // + uint8_t maskAlignedArray[8]; + + for (uint8_t i = 0; i < 8; i++, index++) { + maskAlignedArray[i] = mask[index % 4]; + } + + // + // Apply 64 bit mask in 8 byte chunks. + // + uint32_t loop = length / 8; + uint64_t *pMask8 = (uint64_t *)maskAlignedArray; + + while (loop--) { + uint64_t *pSource8 = (uint64_t *)source; + *pSource8 ^= *pMask8; + source += 8; + } + + // + // Apply mask to remaining data. + // + uint8_t *pmaskAlignedArray = maskAlignedArray; + + length %= 8; + while (length--) { + *source++ ^= *pmaskAlignedArray++; + } + + return NULL; +} + +napi_value Init(napi_env env, napi_value exports) { + napi_status status; + napi_value mask; + napi_value unmask; + + status = napi_create_function(env, NULL, 0, Mask, NULL, &mask); + assert(status == napi_ok); + + status = napi_create_function(env, NULL, 0, Unmask, NULL, &unmask); + assert(status == napi_ok); + + status = napi_set_named_property(env, exports, "mask", mask); + assert(status == napi_ok); + + status = napi_set_named_property(env, exports, "unmask", unmask); + assert(status == napi_ok); + + return exports; +} + +NAPI_MODULE(NODE_GYP_MODULE_NAME, Init) diff --git a/node_modules/cli-width/LICENSE b/node_modules/cli-width/LICENSE new file mode 100644 index 0000000000000000000000000000000000000000..6a937f06e7a006ccea1aa0aadb6d567b6771cdd0 --- /dev/null +++ b/node_modules/cli-width/LICENSE @@ -0,0 +1,13 @@ +Copyright (c) 2015, Ilya Radchenko + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. diff --git a/node_modules/cli-width/README.md b/node_modules/cli-width/README.md new file mode 100644 index 0000000000000000000000000000000000000000..2714934dce7180e82bb890dcc8e67591542f05d8 --- /dev/null +++ b/node_modules/cli-width/README.md @@ -0,0 +1,71 @@ +# cli-width + +Get stdout window width, with four fallbacks, `tty`, `output.columns`, a custom environment variable and then a default. + +[![npm version](https://badge.fury.io/js/cli-width.svg)](http://badge.fury.io/js/cli-width) +[![Build Status](https://travis-ci.org/knownasilya/cli-width.svg)](https://travis-ci.org/knownasilya/cli-width) +[![Coverage Status](https://coveralls.io/repos/knownasilya/cli-width/badge.svg?branch=master&service=github)](https://coveralls.io/github/knownasilya/cli-width?branch=master) + +Tested against Node v12 to v20. +Includes TypeScript types. + +## Usage + +``` +npm install --save cli-width +``` + +```js +const cliWidth = require('cli-width'); + +cliWidth(); // maybe 204 :) +``` + +You can also set the `CLI_WIDTH` environment variable. + +If none of the methods are supported, and the environment variable isn't set, +the default width value is going to be `0`, that can be changed using the configurable `options`. + +## API + +### cliWidth([options]) + +`cliWidth` can be configured using an `options` parameter, the possible properties are: + +- **defaultWidth**\ Defines a default value to be used if none of the methods are available, defaults to `0` +- **output**\ A stream to be used to read width values from, defaults to `process.stdout` +- **tty**\ TTY module to try to read width from as a fallback, defaults to `require('tty')` + +### Examples + +Defining both a default width value and a stream output to try to read from: + +```js +const cliWidth = require('cli-width'); +const ttys = require('ttys'); + +cliWidth({ + defaultWidth: 80, + output: ttys.output, +}); +``` + +Defines a different tty module to read width from: + +```js +const cliWidth = require('cli-width'); +const ttys = require('ttys'); + +cliWidth({ + tty: ttys, +}); +``` + +## Tests + +```bash +npm install +npm test +``` + +Coverage can be generated with `npm run coverage`. diff --git a/node_modules/cli-width/index.d.ts b/node_modules/cli-width/index.d.ts new file mode 100644 index 0000000000000000000000000000000000000000..4dfa444197db14667ee150fb3380358bce8c6630 --- /dev/null +++ b/node_modules/cli-width/index.d.ts @@ -0,0 +1,13 @@ +// Type definitions for cli-width 4.0 +/// + +import { Stream } from 'stream'; +import tty = require('tty'); + +declare function cliWidth(options?: { + defaultWidth?: number; + output?: Stream; + tty?: typeof tty; +}): number; + +export = cliWidth; diff --git a/node_modules/cli-width/index.js b/node_modules/cli-width/index.js new file mode 100644 index 0000000000000000000000000000000000000000..c7803381c0e0d927a11cfb262b083b99fbd2ec83 --- /dev/null +++ b/node_modules/cli-width/index.js @@ -0,0 +1,49 @@ +'use strict'; + +module.exports = cliWidth; + +function normalizeOpts(options) { + const defaultOpts = { + defaultWidth: 0, + output: process.stdout, + tty: require('tty'), + }; + + if (!options) { + return defaultOpts; + } + + Object.keys(defaultOpts).forEach(function (key) { + if (!options[key]) { + options[key] = defaultOpts[key]; + } + }); + + return options; +} + +function cliWidth(options) { + const opts = normalizeOpts(options); + + if (opts.output.getWindowSize) { + return opts.output.getWindowSize()[0] || opts.defaultWidth; + } + + if (opts.tty.getWindowSize) { + return opts.tty.getWindowSize()[1] || opts.defaultWidth; + } + + if (opts.output.columns) { + return opts.output.columns; + } + + if (process.env.CLI_WIDTH) { + const width = parseInt(process.env.CLI_WIDTH, 10); + + if (!isNaN(width) && width !== 0) { + return width; + } + } + + return opts.defaultWidth; +} diff --git a/node_modules/cli-width/package.json b/node_modules/cli-width/package.json new file mode 100644 index 0000000000000000000000000000000000000000..cbd69e5ee9efecade76faeca848a86fdb4892fee --- /dev/null +++ b/node_modules/cli-width/package.json @@ -0,0 +1,40 @@ +{ + "name": "cli-width", + "version": "4.1.0", + "description": "Get stdout window width, with two fallbacks, tty and then a default.", + "main": "index.js", + "scripts": { + "test": "node test | tspec", + "coverage": "nyc node test | tspec", + "coveralls": "npm run coverage -s && coveralls < coverage/lcov.info", + "release": "standard-version" + }, + "repository": { + "type": "git", + "url": "git@github.com:knownasilya/cli-width.git" + }, + "author": "Ilya Radchenko ", + "license": "ISC", + "bugs": { + "url": "https://github.com/knownasilya/cli-width/issues" + }, + "homepage": "https://github.com/knownasilya/cli-width", + "engines": { + "node": ">= 12" + }, + "devDependencies": { + "coveralls": "^3.1.1", + "nyc": "^15.1.0", + "standard-version": "^9.3.2", + "tap-spec": "^5.0.0", + "tape": "^5.5.2" + }, + "volta": { + "node": "12.22.11", + "npm": "8.5.5" + }, + "files": [ + "index.js", + "index.d.ts" + ] +} diff --git a/node_modules/cliui/CHANGELOG.md b/node_modules/cliui/CHANGELOG.md new file mode 100644 index 0000000000000000000000000000000000000000..61f06c3fc27201fb43c43fe25701288e3be9332d --- /dev/null +++ b/node_modules/cliui/CHANGELOG.md @@ -0,0 +1,139 @@ +# Change Log + +All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. + +## [8.0.1](https://github.com/yargs/cliui/compare/v8.0.0...v8.0.1) (2022-10-01) + + +### Bug Fixes + +* **deps:** move rollup-plugin-ts to dev deps ([#124](https://github.com/yargs/cliui/issues/124)) ([7c8bd6b](https://github.com/yargs/cliui/commit/7c8bd6ba024d61e4eeae310c7959ab8ab6829081)) + +## [8.0.0](https://github.com/yargs/cliui/compare/v7.0.4...v8.0.0) (2022-09-30) + + +### ⚠ BREAKING CHANGES + +* **deps:** drop Node 10 to release CVE-2021-3807 patch (#122) + +### Bug Fixes + +* **deps:** drop Node 10 to release CVE-2021-3807 patch ([#122](https://github.com/yargs/cliui/issues/122)) ([f156571](https://github.com/yargs/cliui/commit/f156571ce4f2ebf313335e3a53ad905589da5a30)) + +### [7.0.4](https://www.github.com/yargs/cliui/compare/v7.0.3...v7.0.4) (2020-11-08) + + +### Bug Fixes + +* **deno:** import UIOptions from definitions ([#97](https://www.github.com/yargs/cliui/issues/97)) ([f04f343](https://www.github.com/yargs/cliui/commit/f04f3439bc78114c7e90f82ff56f5acf16268ea8)) + +### [7.0.3](https://www.github.com/yargs/cliui/compare/v7.0.2...v7.0.3) (2020-10-16) + + +### Bug Fixes + +* **exports:** node 13.0 and 13.1 require the dotted object form _with_ a string fallback ([#93](https://www.github.com/yargs/cliui/issues/93)) ([eca16fc](https://www.github.com/yargs/cliui/commit/eca16fc05d26255df3280906c36d7f0e5b05c6e9)) + +### [7.0.2](https://www.github.com/yargs/cliui/compare/v7.0.1...v7.0.2) (2020-10-14) + + +### Bug Fixes + +* **exports:** node 13.0-13.6 require a string fallback ([#91](https://www.github.com/yargs/cliui/issues/91)) ([b529d7e](https://www.github.com/yargs/cliui/commit/b529d7e432901af1af7848b23ed6cf634497d961)) + +### [7.0.1](https://www.github.com/yargs/cliui/compare/v7.0.0...v7.0.1) (2020-08-16) + + +### Bug Fixes + +* **build:** main should be build/index.cjs ([dc29a3c](https://www.github.com/yargs/cliui/commit/dc29a3cc617a410aa850e06337b5954b04f2cb4d)) + +## [7.0.0](https://www.github.com/yargs/cliui/compare/v6.0.0...v7.0.0) (2020-08-16) + + +### ⚠ BREAKING CHANGES + +* tsc/ESM/Deno support (#82) +* modernize deps and build (#80) + +### Build System + +* modernize deps and build ([#80](https://www.github.com/yargs/cliui/issues/80)) ([339d08d](https://www.github.com/yargs/cliui/commit/339d08dc71b15a3928aeab09042af94db2f43743)) + + +### Code Refactoring + +* tsc/ESM/Deno support ([#82](https://www.github.com/yargs/cliui/issues/82)) ([4b777a5](https://www.github.com/yargs/cliui/commit/4b777a5fe01c5d8958c6708695d6aab7dbe5706c)) + +## [6.0.0](https://www.github.com/yargs/cliui/compare/v5.0.0...v6.0.0) (2019-11-10) + + +### ⚠ BREAKING CHANGES + +* update deps, drop Node 6 + +### Code Refactoring + +* update deps, drop Node 6 ([62056df](https://www.github.com/yargs/cliui/commit/62056df)) + +## [5.0.0](https://github.com/yargs/cliui/compare/v4.1.0...v5.0.0) (2019-04-10) + + +### Bug Fixes + +* Update wrap-ansi to fix compatibility with latest versions of chalk. ([#60](https://github.com/yargs/cliui/issues/60)) ([7bf79ae](https://github.com/yargs/cliui/commit/7bf79ae)) + + +### BREAKING CHANGES + +* Drop support for node < 6. + + + + +## [4.1.0](https://github.com/yargs/cliui/compare/v4.0.0...v4.1.0) (2018-04-23) + + +### Features + +* add resetOutput method ([#57](https://github.com/yargs/cliui/issues/57)) ([7246902](https://github.com/yargs/cliui/commit/7246902)) + + + + +## [4.0.0](https://github.com/yargs/cliui/compare/v3.2.0...v4.0.0) (2017-12-18) + + +### Bug Fixes + +* downgrades strip-ansi to version 3.0.1 ([#54](https://github.com/yargs/cliui/issues/54)) ([5764c46](https://github.com/yargs/cliui/commit/5764c46)) +* set env variable FORCE_COLOR. ([#56](https://github.com/yargs/cliui/issues/56)) ([7350e36](https://github.com/yargs/cliui/commit/7350e36)) + + +### Chores + +* drop support for node < 4 ([#53](https://github.com/yargs/cliui/issues/53)) ([b105376](https://github.com/yargs/cliui/commit/b105376)) + + +### Features + +* add fallback for window width ([#45](https://github.com/yargs/cliui/issues/45)) ([d064922](https://github.com/yargs/cliui/commit/d064922)) + + +### BREAKING CHANGES + +* officially drop support for Node < 4 + + + + +## [3.2.0](https://github.com/yargs/cliui/compare/v3.1.2...v3.2.0) (2016-04-11) + + +### Bug Fixes + +* reduces tarball size ([acc6c33](https://github.com/yargs/cliui/commit/acc6c33)) + +### Features + +* adds standard-version for release management ([ff84e32](https://github.com/yargs/cliui/commit/ff84e32)) diff --git a/node_modules/cliui/LICENSE.txt b/node_modules/cliui/LICENSE.txt new file mode 100644 index 0000000000000000000000000000000000000000..c7e27478a3eff8862ca150f10d1b93a5ac866af2 --- /dev/null +++ b/node_modules/cliui/LICENSE.txt @@ -0,0 +1,14 @@ +Copyright (c) 2015, Contributors + +Permission to use, copy, modify, and/or distribute this software +for any purpose with or without fee is hereby granted, provided +that the above copyright notice and this permission notice +appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES +OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE +LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES +OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. diff --git a/node_modules/cliui/README.md b/node_modules/cliui/README.md new file mode 100644 index 0000000000000000000000000000000000000000..65b5672235e8209a2cbd5983684bd68424845550 --- /dev/null +++ b/node_modules/cliui/README.md @@ -0,0 +1,141 @@ +# cliui + +![ci](https://github.com/yargs/cliui/workflows/ci/badge.svg) +[![NPM version](https://img.shields.io/npm/v/cliui.svg)](https://www.npmjs.com/package/cliui) +[![Conventional Commits](https://img.shields.io/badge/Conventional%20Commits-1.0.0-yellow.svg)](https://conventionalcommits.org) +![nycrc config on GitHub](https://img.shields.io/nycrc/yargs/cliui) + +easily create complex multi-column command-line-interfaces. + +## Example + +```js +const ui = require('cliui')() + +ui.div('Usage: $0 [command] [options]') + +ui.div({ + text: 'Options:', + padding: [2, 0, 1, 0] +}) + +ui.div( + { + text: "-f, --file", + width: 20, + padding: [0, 4, 0, 4] + }, + { + text: "the file to load." + + chalk.green("(if this description is long it wraps).") + , + width: 20 + }, + { + text: chalk.red("[required]"), + align: 'right' + } +) + +console.log(ui.toString()) +``` + +## Deno/ESM Support + +As of `v7` `cliui` supports [Deno](https://github.com/denoland/deno) and +[ESM](https://nodejs.org/api/esm.html#esm_ecmascript_modules): + +```typescript +import cliui from "https://deno.land/x/cliui/deno.ts"; + +const ui = cliui({}) + +ui.div('Usage: $0 [command] [options]') + +ui.div({ + text: 'Options:', + padding: [2, 0, 1, 0] +}) + +ui.div({ + text: "-f, --file", + width: 20, + padding: [0, 4, 0, 4] +}) + +console.log(ui.toString()) +``` + + + +## Layout DSL + +cliui exposes a simple layout DSL: + +If you create a single `ui.div`, passing a string rather than an +object: + +* `\n`: characters will be interpreted as new rows. +* `\t`: characters will be interpreted as new columns. +* `\s`: characters will be interpreted as padding. + +**as an example...** + +```js +var ui = require('./')({ + width: 60 +}) + +ui.div( + 'Usage: node ./bin/foo.js\n' + + ' \t provide a regex\n' + + ' \t provide a glob\t [required]' +) + +console.log(ui.toString()) +``` + +**will output:** + +```shell +Usage: node ./bin/foo.js + provide a regex + provide a glob [required] +``` + +## Methods + +```js +cliui = require('cliui') +``` + +### cliui({width: integer}) + +Specify the maximum width of the UI being generated. +If no width is provided, cliui will try to get the current window's width and use it, and if that doesn't work, width will be set to `80`. + +### cliui({wrap: boolean}) + +Enable or disable the wrapping of text in a column. + +### cliui.div(column, column, column) + +Create a row with any number of columns, a column +can either be a string, or an object with the following +options: + +* **text:** some text to place in the column. +* **width:** the width of a column. +* **align:** alignment, `right` or `center`. +* **padding:** `[top, right, bottom, left]`. +* **border:** should a border be placed around the div? + +### cliui.span(column, column, column) + +Similar to `div`, except the next row will be appended without +a new line being created. + +### cliui.resetOutput() + +Resets the UI elements of the current cliui instance, maintaining the values +set for `width` and `wrap`. diff --git a/node_modules/cliui/build/index.cjs b/node_modules/cliui/build/index.cjs new file mode 100644 index 0000000000000000000000000000000000000000..82126b6b98cf2e0c05a18431b4f135ad9b85d3f3 --- /dev/null +++ b/node_modules/cliui/build/index.cjs @@ -0,0 +1,302 @@ +'use strict'; + +const align = { + right: alignRight, + center: alignCenter +}; +const top = 0; +const right = 1; +const bottom = 2; +const left = 3; +class UI { + constructor(opts) { + var _a; + this.width = opts.width; + this.wrap = (_a = opts.wrap) !== null && _a !== void 0 ? _a : true; + this.rows = []; + } + span(...args) { + const cols = this.div(...args); + cols.span = true; + } + resetOutput() { + this.rows = []; + } + div(...args) { + if (args.length === 0) { + this.div(''); + } + if (this.wrap && this.shouldApplyLayoutDSL(...args) && typeof args[0] === 'string') { + return this.applyLayoutDSL(args[0]); + } + const cols = args.map(arg => { + if (typeof arg === 'string') { + return this.colFromString(arg); + } + return arg; + }); + this.rows.push(cols); + return cols; + } + shouldApplyLayoutDSL(...args) { + return args.length === 1 && typeof args[0] === 'string' && + /[\t\n]/.test(args[0]); + } + applyLayoutDSL(str) { + const rows = str.split('\n').map(row => row.split('\t')); + let leftColumnWidth = 0; + // simple heuristic for layout, make sure the + // second column lines up along the left-hand. + // don't allow the first column to take up more + // than 50% of the screen. + rows.forEach(columns => { + if (columns.length > 1 && mixin.stringWidth(columns[0]) > leftColumnWidth) { + leftColumnWidth = Math.min(Math.floor(this.width * 0.5), mixin.stringWidth(columns[0])); + } + }); + // generate a table: + // replacing ' ' with padding calculations. + // using the algorithmically generated width. + rows.forEach(columns => { + this.div(...columns.map((r, i) => { + return { + text: r.trim(), + padding: this.measurePadding(r), + width: (i === 0 && columns.length > 1) ? leftColumnWidth : undefined + }; + })); + }); + return this.rows[this.rows.length - 1]; + } + colFromString(text) { + return { + text, + padding: this.measurePadding(text) + }; + } + measurePadding(str) { + // measure padding without ansi escape codes + const noAnsi = mixin.stripAnsi(str); + return [0, noAnsi.match(/\s*$/)[0].length, 0, noAnsi.match(/^\s*/)[0].length]; + } + toString() { + const lines = []; + this.rows.forEach(row => { + this.rowToString(row, lines); + }); + // don't display any lines with the + // hidden flag set. + return lines + .filter(line => !line.hidden) + .map(line => line.text) + .join('\n'); + } + rowToString(row, lines) { + this.rasterize(row).forEach((rrow, r) => { + let str = ''; + rrow.forEach((col, c) => { + const { width } = row[c]; // the width with padding. + const wrapWidth = this.negatePadding(row[c]); // the width without padding. + let ts = col; // temporary string used during alignment/padding. + if (wrapWidth > mixin.stringWidth(col)) { + ts += ' '.repeat(wrapWidth - mixin.stringWidth(col)); + } + // align the string within its column. + if (row[c].align && row[c].align !== 'left' && this.wrap) { + const fn = align[row[c].align]; + ts = fn(ts, wrapWidth); + if (mixin.stringWidth(ts) < wrapWidth) { + ts += ' '.repeat((width || 0) - mixin.stringWidth(ts) - 1); + } + } + // apply border and padding to string. + const padding = row[c].padding || [0, 0, 0, 0]; + if (padding[left]) { + str += ' '.repeat(padding[left]); + } + str += addBorder(row[c], ts, '| '); + str += ts; + str += addBorder(row[c], ts, ' |'); + if (padding[right]) { + str += ' '.repeat(padding[right]); + } + // if prior row is span, try to render the + // current row on the prior line. + if (r === 0 && lines.length > 0) { + str = this.renderInline(str, lines[lines.length - 1]); + } + }); + // remove trailing whitespace. + lines.push({ + text: str.replace(/ +$/, ''), + span: row.span + }); + }); + return lines; + } + // if the full 'source' can render in + // the target line, do so. + renderInline(source, previousLine) { + const match = source.match(/^ */); + const leadingWhitespace = match ? match[0].length : 0; + const target = previousLine.text; + const targetTextWidth = mixin.stringWidth(target.trimRight()); + if (!previousLine.span) { + return source; + } + // if we're not applying wrapping logic, + // just always append to the span. + if (!this.wrap) { + previousLine.hidden = true; + return target + source; + } + if (leadingWhitespace < targetTextWidth) { + return source; + } + previousLine.hidden = true; + return target.trimRight() + ' '.repeat(leadingWhitespace - targetTextWidth) + source.trimLeft(); + } + rasterize(row) { + const rrows = []; + const widths = this.columnWidths(row); + let wrapped; + // word wrap all columns, and create + // a data-structure that is easy to rasterize. + row.forEach((col, c) => { + // leave room for left and right padding. + col.width = widths[c]; + if (this.wrap) { + wrapped = mixin.wrap(col.text, this.negatePadding(col), { hard: true }).split('\n'); + } + else { + wrapped = col.text.split('\n'); + } + if (col.border) { + wrapped.unshift('.' + '-'.repeat(this.negatePadding(col) + 2) + '.'); + wrapped.push("'" + '-'.repeat(this.negatePadding(col) + 2) + "'"); + } + // add top and bottom padding. + if (col.padding) { + wrapped.unshift(...new Array(col.padding[top] || 0).fill('')); + wrapped.push(...new Array(col.padding[bottom] || 0).fill('')); + } + wrapped.forEach((str, r) => { + if (!rrows[r]) { + rrows.push([]); + } + const rrow = rrows[r]; + for (let i = 0; i < c; i++) { + if (rrow[i] === undefined) { + rrow.push(''); + } + } + rrow.push(str); + }); + }); + return rrows; + } + negatePadding(col) { + let wrapWidth = col.width || 0; + if (col.padding) { + wrapWidth -= (col.padding[left] || 0) + (col.padding[right] || 0); + } + if (col.border) { + wrapWidth -= 4; + } + return wrapWidth; + } + columnWidths(row) { + if (!this.wrap) { + return row.map(col => { + return col.width || mixin.stringWidth(col.text); + }); + } + let unset = row.length; + let remainingWidth = this.width; + // column widths can be set in config. + const widths = row.map(col => { + if (col.width) { + unset--; + remainingWidth -= col.width; + return col.width; + } + return undefined; + }); + // any unset widths should be calculated. + const unsetWidth = unset ? Math.floor(remainingWidth / unset) : 0; + return widths.map((w, i) => { + if (w === undefined) { + return Math.max(unsetWidth, _minWidth(row[i])); + } + return w; + }); + } +} +function addBorder(col, ts, style) { + if (col.border) { + if (/[.']-+[.']/.test(ts)) { + return ''; + } + if (ts.trim().length !== 0) { + return style; + } + return ' '; + } + return ''; +} +// calculates the minimum width of +// a column, based on padding preferences. +function _minWidth(col) { + const padding = col.padding || []; + const minWidth = 1 + (padding[left] || 0) + (padding[right] || 0); + if (col.border) { + return minWidth + 4; + } + return minWidth; +} +function getWindowWidth() { + /* istanbul ignore next: depends on terminal */ + if (typeof process === 'object' && process.stdout && process.stdout.columns) { + return process.stdout.columns; + } + return 80; +} +function alignRight(str, width) { + str = str.trim(); + const strWidth = mixin.stringWidth(str); + if (strWidth < width) { + return ' '.repeat(width - strWidth) + str; + } + return str; +} +function alignCenter(str, width) { + str = str.trim(); + const strWidth = mixin.stringWidth(str); + /* istanbul ignore next */ + if (strWidth >= width) { + return str; + } + return ' '.repeat((width - strWidth) >> 1) + str; +} +let mixin; +function cliui(opts, _mixin) { + mixin = _mixin; + return new UI({ + width: (opts === null || opts === void 0 ? void 0 : opts.width) || getWindowWidth(), + wrap: opts === null || opts === void 0 ? void 0 : opts.wrap + }); +} + +// Bootstrap cliui with CommonJS dependencies: +const stringWidth = require('string-width'); +const stripAnsi = require('strip-ansi'); +const wrap = require('wrap-ansi'); +function ui(opts) { + return cliui(opts, { + stringWidth, + stripAnsi, + wrap + }); +} + +module.exports = ui; diff --git a/node_modules/cliui/build/index.d.cts b/node_modules/cliui/build/index.d.cts new file mode 100644 index 0000000000000000000000000000000000000000..4567f945e81a73dc2e589f153913910fa2f5fea9 --- /dev/null +++ b/node_modules/cliui/build/index.d.cts @@ -0,0 +1,43 @@ +interface UIOptions { + width: number; + wrap?: boolean; + rows?: string[]; +} +interface Column { + text: string; + width?: number; + align?: "right" | "left" | "center"; + padding: number[]; + border?: boolean; +} +interface ColumnArray extends Array { + span: boolean; +} +interface Line { + hidden?: boolean; + text: string; + span?: boolean; +} +declare class UI { + width: number; + wrap: boolean; + rows: ColumnArray[]; + constructor(opts: UIOptions); + span(...args: ColumnArray): void; + resetOutput(): void; + div(...args: (Column | string)[]): ColumnArray; + private shouldApplyLayoutDSL; + private applyLayoutDSL; + private colFromString; + private measurePadding; + toString(): string; + rowToString(row: ColumnArray, lines: Line[]): Line[]; + // if the full 'source' can render in + // the target line, do so. + private renderInline; + private rasterize; + private negatePadding; + private columnWidths; +} +declare function ui(opts: UIOptions): UI; +export { ui as default }; diff --git a/node_modules/cliui/build/lib/index.js b/node_modules/cliui/build/lib/index.js new file mode 100644 index 0000000000000000000000000000000000000000..b6eb0544222e61d14d3dc37b62982e369bff8d0b --- /dev/null +++ b/node_modules/cliui/build/lib/index.js @@ -0,0 +1,287 @@ +'use strict'; +const align = { + right: alignRight, + center: alignCenter +}; +const top = 0; +const right = 1; +const bottom = 2; +const left = 3; +export class UI { + constructor(opts) { + var _a; + this.width = opts.width; + this.wrap = (_a = opts.wrap) !== null && _a !== void 0 ? _a : true; + this.rows = []; + } + span(...args) { + const cols = this.div(...args); + cols.span = true; + } + resetOutput() { + this.rows = []; + } + div(...args) { + if (args.length === 0) { + this.div(''); + } + if (this.wrap && this.shouldApplyLayoutDSL(...args) && typeof args[0] === 'string') { + return this.applyLayoutDSL(args[0]); + } + const cols = args.map(arg => { + if (typeof arg === 'string') { + return this.colFromString(arg); + } + return arg; + }); + this.rows.push(cols); + return cols; + } + shouldApplyLayoutDSL(...args) { + return args.length === 1 && typeof args[0] === 'string' && + /[\t\n]/.test(args[0]); + } + applyLayoutDSL(str) { + const rows = str.split('\n').map(row => row.split('\t')); + let leftColumnWidth = 0; + // simple heuristic for layout, make sure the + // second column lines up along the left-hand. + // don't allow the first column to take up more + // than 50% of the screen. + rows.forEach(columns => { + if (columns.length > 1 && mixin.stringWidth(columns[0]) > leftColumnWidth) { + leftColumnWidth = Math.min(Math.floor(this.width * 0.5), mixin.stringWidth(columns[0])); + } + }); + // generate a table: + // replacing ' ' with padding calculations. + // using the algorithmically generated width. + rows.forEach(columns => { + this.div(...columns.map((r, i) => { + return { + text: r.trim(), + padding: this.measurePadding(r), + width: (i === 0 && columns.length > 1) ? leftColumnWidth : undefined + }; + })); + }); + return this.rows[this.rows.length - 1]; + } + colFromString(text) { + return { + text, + padding: this.measurePadding(text) + }; + } + measurePadding(str) { + // measure padding without ansi escape codes + const noAnsi = mixin.stripAnsi(str); + return [0, noAnsi.match(/\s*$/)[0].length, 0, noAnsi.match(/^\s*/)[0].length]; + } + toString() { + const lines = []; + this.rows.forEach(row => { + this.rowToString(row, lines); + }); + // don't display any lines with the + // hidden flag set. + return lines + .filter(line => !line.hidden) + .map(line => line.text) + .join('\n'); + } + rowToString(row, lines) { + this.rasterize(row).forEach((rrow, r) => { + let str = ''; + rrow.forEach((col, c) => { + const { width } = row[c]; // the width with padding. + const wrapWidth = this.negatePadding(row[c]); // the width without padding. + let ts = col; // temporary string used during alignment/padding. + if (wrapWidth > mixin.stringWidth(col)) { + ts += ' '.repeat(wrapWidth - mixin.stringWidth(col)); + } + // align the string within its column. + if (row[c].align && row[c].align !== 'left' && this.wrap) { + const fn = align[row[c].align]; + ts = fn(ts, wrapWidth); + if (mixin.stringWidth(ts) < wrapWidth) { + ts += ' '.repeat((width || 0) - mixin.stringWidth(ts) - 1); + } + } + // apply border and padding to string. + const padding = row[c].padding || [0, 0, 0, 0]; + if (padding[left]) { + str += ' '.repeat(padding[left]); + } + str += addBorder(row[c], ts, '| '); + str += ts; + str += addBorder(row[c], ts, ' |'); + if (padding[right]) { + str += ' '.repeat(padding[right]); + } + // if prior row is span, try to render the + // current row on the prior line. + if (r === 0 && lines.length > 0) { + str = this.renderInline(str, lines[lines.length - 1]); + } + }); + // remove trailing whitespace. + lines.push({ + text: str.replace(/ +$/, ''), + span: row.span + }); + }); + return lines; + } + // if the full 'source' can render in + // the target line, do so. + renderInline(source, previousLine) { + const match = source.match(/^ */); + const leadingWhitespace = match ? match[0].length : 0; + const target = previousLine.text; + const targetTextWidth = mixin.stringWidth(target.trimRight()); + if (!previousLine.span) { + return source; + } + // if we're not applying wrapping logic, + // just always append to the span. + if (!this.wrap) { + previousLine.hidden = true; + return target + source; + } + if (leadingWhitespace < targetTextWidth) { + return source; + } + previousLine.hidden = true; + return target.trimRight() + ' '.repeat(leadingWhitespace - targetTextWidth) + source.trimLeft(); + } + rasterize(row) { + const rrows = []; + const widths = this.columnWidths(row); + let wrapped; + // word wrap all columns, and create + // a data-structure that is easy to rasterize. + row.forEach((col, c) => { + // leave room for left and right padding. + col.width = widths[c]; + if (this.wrap) { + wrapped = mixin.wrap(col.text, this.negatePadding(col), { hard: true }).split('\n'); + } + else { + wrapped = col.text.split('\n'); + } + if (col.border) { + wrapped.unshift('.' + '-'.repeat(this.negatePadding(col) + 2) + '.'); + wrapped.push("'" + '-'.repeat(this.negatePadding(col) + 2) + "'"); + } + // add top and bottom padding. + if (col.padding) { + wrapped.unshift(...new Array(col.padding[top] || 0).fill('')); + wrapped.push(...new Array(col.padding[bottom] || 0).fill('')); + } + wrapped.forEach((str, r) => { + if (!rrows[r]) { + rrows.push([]); + } + const rrow = rrows[r]; + for (let i = 0; i < c; i++) { + if (rrow[i] === undefined) { + rrow.push(''); + } + } + rrow.push(str); + }); + }); + return rrows; + } + negatePadding(col) { + let wrapWidth = col.width || 0; + if (col.padding) { + wrapWidth -= (col.padding[left] || 0) + (col.padding[right] || 0); + } + if (col.border) { + wrapWidth -= 4; + } + return wrapWidth; + } + columnWidths(row) { + if (!this.wrap) { + return row.map(col => { + return col.width || mixin.stringWidth(col.text); + }); + } + let unset = row.length; + let remainingWidth = this.width; + // column widths can be set in config. + const widths = row.map(col => { + if (col.width) { + unset--; + remainingWidth -= col.width; + return col.width; + } + return undefined; + }); + // any unset widths should be calculated. + const unsetWidth = unset ? Math.floor(remainingWidth / unset) : 0; + return widths.map((w, i) => { + if (w === undefined) { + return Math.max(unsetWidth, _minWidth(row[i])); + } + return w; + }); + } +} +function addBorder(col, ts, style) { + if (col.border) { + if (/[.']-+[.']/.test(ts)) { + return ''; + } + if (ts.trim().length !== 0) { + return style; + } + return ' '; + } + return ''; +} +// calculates the minimum width of +// a column, based on padding preferences. +function _minWidth(col) { + const padding = col.padding || []; + const minWidth = 1 + (padding[left] || 0) + (padding[right] || 0); + if (col.border) { + return minWidth + 4; + } + return minWidth; +} +function getWindowWidth() { + /* istanbul ignore next: depends on terminal */ + if (typeof process === 'object' && process.stdout && process.stdout.columns) { + return process.stdout.columns; + } + return 80; +} +function alignRight(str, width) { + str = str.trim(); + const strWidth = mixin.stringWidth(str); + if (strWidth < width) { + return ' '.repeat(width - strWidth) + str; + } + return str; +} +function alignCenter(str, width) { + str = str.trim(); + const strWidth = mixin.stringWidth(str); + /* istanbul ignore next */ + if (strWidth >= width) { + return str; + } + return ' '.repeat((width - strWidth) >> 1) + str; +} +let mixin; +export function cliui(opts, _mixin) { + mixin = _mixin; + return new UI({ + width: (opts === null || opts === void 0 ? void 0 : opts.width) || getWindowWidth(), + wrap: opts === null || opts === void 0 ? void 0 : opts.wrap + }); +} diff --git a/node_modules/cliui/build/lib/string-utils.js b/node_modules/cliui/build/lib/string-utils.js new file mode 100644 index 0000000000000000000000000000000000000000..4b87453a66f717e934e6af1147efb53e347868e2 --- /dev/null +++ b/node_modules/cliui/build/lib/string-utils.js @@ -0,0 +1,27 @@ +// Minimal replacement for ansi string helpers "wrap-ansi" and "strip-ansi". +// to facilitate ESM and Deno modules. +// TODO: look at porting https://www.npmjs.com/package/wrap-ansi to ESM. +// The npm application +// Copyright (c) npm, Inc. and Contributors +// Licensed on the terms of The Artistic License 2.0 +// See: https://github.com/npm/cli/blob/4c65cd952bc8627811735bea76b9b110cc4fc80e/lib/utils/ansi-trim.js +const ansi = new RegExp('\x1b(?:\\[(?:\\d+[ABCDEFGJKSTm]|\\d+;\\d+[Hfm]|' + + '\\d+;\\d+;\\d+m|6n|s|u|\\?25[lh])|\\w)', 'g'); +export function stripAnsi(str) { + return str.replace(ansi, ''); +} +export function wrap(str, width) { + const [start, end] = str.match(ansi) || ['', '']; + str = stripAnsi(str); + let wrapped = ''; + for (let i = 0; i < str.length; i++) { + if (i !== 0 && (i % width) === 0) { + wrapped += '\n'; + } + wrapped += str.charAt(i); + } + if (start && end) { + wrapped = `${start}${wrapped}${end}`; + } + return wrapped; +} diff --git a/node_modules/cliui/index.mjs b/node_modules/cliui/index.mjs new file mode 100644 index 0000000000000000000000000000000000000000..bc7a022b8df912458d259e14fc7aff3fd4c8e874 --- /dev/null +++ b/node_modules/cliui/index.mjs @@ -0,0 +1,13 @@ +// Bootstrap cliui with CommonJS dependencies: +import { cliui } from './build/lib/index.js' +import { wrap, stripAnsi } from './build/lib/string-utils.js' + +export default function ui (opts) { + return cliui(opts, { + stringWidth: (str) => { + return [...str].length + }, + stripAnsi, + wrap + }) +} diff --git a/node_modules/cliui/node_modules/wrap-ansi/index.js b/node_modules/cliui/node_modules/wrap-ansi/index.js new file mode 100755 index 0000000000000000000000000000000000000000..d502255bd15c85cabbba259f178e706c0f3a9a7c --- /dev/null +++ b/node_modules/cliui/node_modules/wrap-ansi/index.js @@ -0,0 +1,216 @@ +'use strict'; +const stringWidth = require('string-width'); +const stripAnsi = require('strip-ansi'); +const ansiStyles = require('ansi-styles'); + +const ESCAPES = new Set([ + '\u001B', + '\u009B' +]); + +const END_CODE = 39; + +const ANSI_ESCAPE_BELL = '\u0007'; +const ANSI_CSI = '['; +const ANSI_OSC = ']'; +const ANSI_SGR_TERMINATOR = 'm'; +const ANSI_ESCAPE_LINK = `${ANSI_OSC}8;;`; + +const wrapAnsi = code => `${ESCAPES.values().next().value}${ANSI_CSI}${code}${ANSI_SGR_TERMINATOR}`; +const wrapAnsiHyperlink = uri => `${ESCAPES.values().next().value}${ANSI_ESCAPE_LINK}${uri}${ANSI_ESCAPE_BELL}`; + +// Calculate the length of words split on ' ', ignoring +// the extra characters added by ansi escape codes +const wordLengths = string => string.split(' ').map(character => stringWidth(character)); + +// Wrap a long word across multiple rows +// Ansi escape codes do not count towards length +const wrapWord = (rows, word, columns) => { + const characters = [...word]; + + let isInsideEscape = false; + let isInsideLinkEscape = false; + let visible = stringWidth(stripAnsi(rows[rows.length - 1])); + + for (const [index, character] of characters.entries()) { + const characterLength = stringWidth(character); + + if (visible + characterLength <= columns) { + rows[rows.length - 1] += character; + } else { + rows.push(character); + visible = 0; + } + + if (ESCAPES.has(character)) { + isInsideEscape = true; + isInsideLinkEscape = characters.slice(index + 1).join('').startsWith(ANSI_ESCAPE_LINK); + } + + if (isInsideEscape) { + if (isInsideLinkEscape) { + if (character === ANSI_ESCAPE_BELL) { + isInsideEscape = false; + isInsideLinkEscape = false; + } + } else if (character === ANSI_SGR_TERMINATOR) { + isInsideEscape = false; + } + + continue; + } + + visible += characterLength; + + if (visible === columns && index < characters.length - 1) { + rows.push(''); + visible = 0; + } + } + + // It's possible that the last row we copy over is only + // ansi escape characters, handle this edge-case + if (!visible && rows[rows.length - 1].length > 0 && rows.length > 1) { + rows[rows.length - 2] += rows.pop(); + } +}; + +// Trims spaces from a string ignoring invisible sequences +const stringVisibleTrimSpacesRight = string => { + const words = string.split(' '); + let last = words.length; + + while (last > 0) { + if (stringWidth(words[last - 1]) > 0) { + break; + } + + last--; + } + + if (last === words.length) { + return string; + } + + return words.slice(0, last).join(' ') + words.slice(last).join(''); +}; + +// The wrap-ansi module can be invoked in either 'hard' or 'soft' wrap mode +// +// 'hard' will never allow a string to take up more than columns characters +// +// 'soft' allows long words to expand past the column length +const exec = (string, columns, options = {}) => { + if (options.trim !== false && string.trim() === '') { + return ''; + } + + let returnValue = ''; + let escapeCode; + let escapeUrl; + + const lengths = wordLengths(string); + let rows = ['']; + + for (const [index, word] of string.split(' ').entries()) { + if (options.trim !== false) { + rows[rows.length - 1] = rows[rows.length - 1].trimStart(); + } + + let rowLength = stringWidth(rows[rows.length - 1]); + + if (index !== 0) { + if (rowLength >= columns && (options.wordWrap === false || options.trim === false)) { + // If we start with a new word but the current row length equals the length of the columns, add a new row + rows.push(''); + rowLength = 0; + } + + if (rowLength > 0 || options.trim === false) { + rows[rows.length - 1] += ' '; + rowLength++; + } + } + + // In 'hard' wrap mode, the length of a line is never allowed to extend past 'columns' + if (options.hard && lengths[index] > columns) { + const remainingColumns = (columns - rowLength); + const breaksStartingThisLine = 1 + Math.floor((lengths[index] - remainingColumns - 1) / columns); + const breaksStartingNextLine = Math.floor((lengths[index] - 1) / columns); + if (breaksStartingNextLine < breaksStartingThisLine) { + rows.push(''); + } + + wrapWord(rows, word, columns); + continue; + } + + if (rowLength + lengths[index] > columns && rowLength > 0 && lengths[index] > 0) { + if (options.wordWrap === false && rowLength < columns) { + wrapWord(rows, word, columns); + continue; + } + + rows.push(''); + } + + if (rowLength + lengths[index] > columns && options.wordWrap === false) { + wrapWord(rows, word, columns); + continue; + } + + rows[rows.length - 1] += word; + } + + if (options.trim !== false) { + rows = rows.map(stringVisibleTrimSpacesRight); + } + + const pre = [...rows.join('\n')]; + + for (const [index, character] of pre.entries()) { + returnValue += character; + + if (ESCAPES.has(character)) { + const {groups} = new RegExp(`(?:\\${ANSI_CSI}(?\\d+)m|\\${ANSI_ESCAPE_LINK}(?.*)${ANSI_ESCAPE_BELL})`).exec(pre.slice(index).join('')) || {groups: {}}; + if (groups.code !== undefined) { + const code = Number.parseFloat(groups.code); + escapeCode = code === END_CODE ? undefined : code; + } else if (groups.uri !== undefined) { + escapeUrl = groups.uri.length === 0 ? undefined : groups.uri; + } + } + + const code = ansiStyles.codes.get(Number(escapeCode)); + + if (pre[index + 1] === '\n') { + if (escapeUrl) { + returnValue += wrapAnsiHyperlink(''); + } + + if (escapeCode && code) { + returnValue += wrapAnsi(code); + } + } else if (character === '\n') { + if (escapeCode && code) { + returnValue += wrapAnsi(escapeCode); + } + + if (escapeUrl) { + returnValue += wrapAnsiHyperlink(escapeUrl); + } + } + } + + return returnValue; +}; + +// For each newline, invoke the method separately +module.exports = (string, columns, options) => { + return String(string) + .normalize() + .replace(/\r\n/g, '\n') + .split('\n') + .map(line => exec(line, columns, options)) + .join('\n'); +}; diff --git a/node_modules/cliui/node_modules/wrap-ansi/license b/node_modules/cliui/node_modules/wrap-ansi/license new file mode 100644 index 0000000000000000000000000000000000000000..fa7ceba3eb4a9657a9db7f3ffca4e4e97a9019de --- /dev/null +++ b/node_modules/cliui/node_modules/wrap-ansi/license @@ -0,0 +1,9 @@ +MIT License + +Copyright (c) Sindre Sorhus (https://sindresorhus.com) + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/node_modules/cliui/node_modules/wrap-ansi/package.json b/node_modules/cliui/node_modules/wrap-ansi/package.json new file mode 100644 index 0000000000000000000000000000000000000000..dfb2f4f108cfb65bb377194c4114df1ef321fa21 --- /dev/null +++ b/node_modules/cliui/node_modules/wrap-ansi/package.json @@ -0,0 +1,62 @@ +{ + "name": "wrap-ansi", + "version": "7.0.0", + "description": "Wordwrap a string with ANSI escape codes", + "license": "MIT", + "repository": "chalk/wrap-ansi", + "funding": "https://github.com/chalk/wrap-ansi?sponsor=1", + "author": { + "name": "Sindre Sorhus", + "email": "sindresorhus@gmail.com", + "url": "https://sindresorhus.com" + }, + "engines": { + "node": ">=10" + }, + "scripts": { + "test": "xo && nyc ava" + }, + "files": [ + "index.js" + ], + "keywords": [ + "wrap", + "break", + "wordwrap", + "wordbreak", + "linewrap", + "ansi", + "styles", + "color", + "colour", + "colors", + "terminal", + "console", + "cli", + "string", + "tty", + "escape", + "formatting", + "rgb", + "256", + "shell", + "xterm", + "log", + "logging", + "command-line", + "text" + ], + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "devDependencies": { + "ava": "^2.1.0", + "chalk": "^4.0.0", + "coveralls": "^3.0.3", + "has-ansi": "^4.0.0", + "nyc": "^15.0.1", + "xo": "^0.29.1" + } +} diff --git a/node_modules/cliui/node_modules/wrap-ansi/readme.md b/node_modules/cliui/node_modules/wrap-ansi/readme.md new file mode 100644 index 0000000000000000000000000000000000000000..68779ba5f4e63fb310ff499b4f518bced4b9d056 --- /dev/null +++ b/node_modules/cliui/node_modules/wrap-ansi/readme.md @@ -0,0 +1,91 @@ +# wrap-ansi [![Build Status](https://travis-ci.com/chalk/wrap-ansi.svg?branch=master)](https://travis-ci.com/chalk/wrap-ansi) [![Coverage Status](https://coveralls.io/repos/github/chalk/wrap-ansi/badge.svg?branch=master)](https://coveralls.io/github/chalk/wrap-ansi?branch=master) + +> Wordwrap a string with [ANSI escape codes](https://en.wikipedia.org/wiki/ANSI_escape_code#Colors_and_Styles) + +## Install + +``` +$ npm install wrap-ansi +``` + +## Usage + +```js +const chalk = require('chalk'); +const wrapAnsi = require('wrap-ansi'); + +const input = 'The quick brown ' + chalk.red('fox jumped over ') + + 'the lazy ' + chalk.green('dog and then ran away with the unicorn.'); + +console.log(wrapAnsi(input, 20)); +``` + + + +## API + +### wrapAnsi(string, columns, options?) + +Wrap words to the specified column width. + +#### string + +Type: `string` + +String with ANSI escape codes. Like one styled by [`chalk`](https://github.com/chalk/chalk). Newline characters will be normalized to `\n`. + +#### columns + +Type: `number` + +Number of columns to wrap the text to. + +#### options + +Type: `object` + +##### hard + +Type: `boolean`\ +Default: `false` + +By default the wrap is soft, meaning long words may extend past the column width. Setting this to `true` will make it hard wrap at the column width. + +##### wordWrap + +Type: `boolean`\ +Default: `true` + +By default, an attempt is made to split words at spaces, ensuring that they don't extend past the configured columns. If wordWrap is `false`, each column will instead be completely filled splitting words as necessary. + +##### trim + +Type: `boolean`\ +Default: `true` + +Whitespace on all lines is removed by default. Set this option to `false` if you don't want to trim. + +## Related + +- [slice-ansi](https://github.com/chalk/slice-ansi) - Slice a string with ANSI escape codes +- [cli-truncate](https://github.com/sindresorhus/cli-truncate) - Truncate a string to a specific width in the terminal +- [chalk](https://github.com/chalk/chalk) - Terminal string styling done right +- [jsesc](https://github.com/mathiasbynens/jsesc) - Generate ASCII-only output from Unicode strings. Useful for creating test fixtures. + +## Maintainers + +- [Sindre Sorhus](https://github.com/sindresorhus) +- [Josh Junon](https://github.com/qix-) +- [Benjamin Coe](https://github.com/bcoe) + +--- + +
+ + Get professional support for this package with a Tidelift subscription + +
+ + Tidelift helps make open source sustainable for maintainers while giving companies
assurances about security, maintenance, and licensing for their dependencies. +
+
diff --git a/node_modules/cliui/package.json b/node_modules/cliui/package.json new file mode 100644 index 0000000000000000000000000000000000000000..eab6bf47c11ea5df6e600d420e790cd09b850736 --- /dev/null +++ b/node_modules/cliui/package.json @@ -0,0 +1,83 @@ +{ + "name": "cliui", + "version": "8.0.1", + "description": "easily create complex multi-column command-line-interfaces", + "main": "build/index.cjs", + "exports": { + ".": [ + { + "import": "./index.mjs", + "require": "./build/index.cjs" + }, + "./build/index.cjs" + ] + }, + "type": "module", + "module": "./index.mjs", + "scripts": { + "check": "standardx '**/*.ts' && standardx '**/*.js' && standardx '**/*.cjs'", + "fix": "standardx --fix '**/*.ts' && standardx --fix '**/*.js' && standardx --fix '**/*.cjs'", + "pretest": "rimraf build && tsc -p tsconfig.test.json && cross-env NODE_ENV=test npm run build:cjs", + "test": "c8 mocha ./test/*.cjs", + "test:esm": "c8 mocha ./test/esm/cliui-test.mjs", + "postest": "check", + "coverage": "c8 report --check-coverage", + "precompile": "rimraf build", + "compile": "tsc", + "postcompile": "npm run build:cjs", + "build:cjs": "rollup -c", + "prepare": "npm run compile" + }, + "repository": "yargs/cliui", + "standard": { + "ignore": [ + "**/example/**" + ], + "globals": [ + "it" + ] + }, + "keywords": [ + "cli", + "command-line", + "layout", + "design", + "console", + "wrap", + "table" + ], + "author": "Ben Coe ", + "license": "ISC", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "devDependencies": { + "@types/node": "^14.0.27", + "@typescript-eslint/eslint-plugin": "^4.0.0", + "@typescript-eslint/parser": "^4.0.0", + "c8": "^7.3.0", + "chai": "^4.2.0", + "chalk": "^4.1.0", + "cross-env": "^7.0.2", + "eslint": "^7.6.0", + "eslint-plugin-import": "^2.22.0", + "eslint-plugin-node": "^11.1.0", + "gts": "^3.0.0", + "mocha": "^10.0.0", + "rimraf": "^3.0.2", + "rollup": "^2.23.1", + "rollup-plugin-ts": "^3.0.2", + "standardx": "^7.0.0", + "typescript": "^4.0.0" + }, + "files": [ + "build", + "index.mjs", + "!*.d.ts" + ], + "engines": { + "node": ">=12" + } +} diff --git a/node_modules/color-convert/CHANGELOG.md b/node_modules/color-convert/CHANGELOG.md new file mode 100644 index 0000000000000000000000000000000000000000..0a7bce4fd570ab5f2f7ad89f8456ee0ad26de1f5 --- /dev/null +++ b/node_modules/color-convert/CHANGELOG.md @@ -0,0 +1,54 @@ +# 1.0.0 - 2016-01-07 + +- Removed: unused speed test +- Added: Automatic routing between previously unsupported conversions +([#27](https://github.com/Qix-/color-convert/pull/27)) +- Removed: `xxx2xxx()` and `xxx2xxxRaw()` functions +([#27](https://github.com/Qix-/color-convert/pull/27)) +- Removed: `convert()` class +([#27](https://github.com/Qix-/color-convert/pull/27)) +- Changed: all functions to lookup dictionary +([#27](https://github.com/Qix-/color-convert/pull/27)) +- Changed: `ansi` to `ansi256` +([#27](https://github.com/Qix-/color-convert/pull/27)) +- Fixed: argument grouping for functions requiring only one argument +([#27](https://github.com/Qix-/color-convert/pull/27)) + +# 0.6.0 - 2015-07-23 + +- Added: methods to handle +[ANSI](https://en.wikipedia.org/wiki/ANSI_escape_code#Colors) 16/256 colors: + - rgb2ansi16 + - rgb2ansi + - hsl2ansi16 + - hsl2ansi + - hsv2ansi16 + - hsv2ansi + - hwb2ansi16 + - hwb2ansi + - cmyk2ansi16 + - cmyk2ansi + - keyword2ansi16 + - keyword2ansi + - ansi162rgb + - ansi162hsl + - ansi162hsv + - ansi162hwb + - ansi162cmyk + - ansi162keyword + - ansi2rgb + - ansi2hsl + - ansi2hsv + - ansi2hwb + - ansi2cmyk + - ansi2keyword +([#18](https://github.com/harthur/color-convert/pull/18)) + +# 0.5.3 - 2015-06-02 + +- Fixed: hsl2hsv does not return `NaN` anymore when using `[0,0,0]` +([#15](https://github.com/harthur/color-convert/issues/15)) + +--- + +Check out commit logs for older releases diff --git a/node_modules/color-convert/LICENSE b/node_modules/color-convert/LICENSE new file mode 100644 index 0000000000000000000000000000000000000000..5b4c386f9269b30a21f15145cd966c50017c2a3f --- /dev/null +++ b/node_modules/color-convert/LICENSE @@ -0,0 +1,21 @@ +Copyright (c) 2011-2016 Heather Arthur + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + diff --git a/node_modules/color-convert/README.md b/node_modules/color-convert/README.md new file mode 100644 index 0000000000000000000000000000000000000000..d4b08fc369948daacc146dcde0f63c3a79039852 --- /dev/null +++ b/node_modules/color-convert/README.md @@ -0,0 +1,68 @@ +# color-convert + +[![Build Status](https://travis-ci.org/Qix-/color-convert.svg?branch=master)](https://travis-ci.org/Qix-/color-convert) + +Color-convert is a color conversion library for JavaScript and node. +It converts all ways between `rgb`, `hsl`, `hsv`, `hwb`, `cmyk`, `ansi`, `ansi16`, `hex` strings, and CSS `keyword`s (will round to closest): + +```js +var convert = require('color-convert'); + +convert.rgb.hsl(140, 200, 100); // [96, 48, 59] +convert.keyword.rgb('blue'); // [0, 0, 255] + +var rgbChannels = convert.rgb.channels; // 3 +var cmykChannels = convert.cmyk.channels; // 4 +var ansiChannels = convert.ansi16.channels; // 1 +``` + +# Install + +```console +$ npm install color-convert +``` + +# API + +Simply get the property of the _from_ and _to_ conversion that you're looking for. + +All functions have a rounded and unrounded variant. By default, return values are rounded. To get the unrounded (raw) results, simply tack on `.raw` to the function. + +All 'from' functions have a hidden property called `.channels` that indicates the number of channels the function expects (not including alpha). + +```js +var convert = require('color-convert'); + +// Hex to LAB +convert.hex.lab('DEADBF'); // [ 76, 21, -2 ] +convert.hex.lab.raw('DEADBF'); // [ 75.56213190997677, 20.653827952644754, -2.290532499330533 ] + +// RGB to CMYK +convert.rgb.cmyk(167, 255, 4); // [ 35, 0, 98, 0 ] +convert.rgb.cmyk.raw(167, 255, 4); // [ 34.509803921568626, 0, 98.43137254901961, 0 ] +``` + +### Arrays +All functions that accept multiple arguments also support passing an array. + +Note that this does **not** apply to functions that convert from a color that only requires one value (e.g. `keyword`, `ansi256`, `hex`, etc.) + +```js +var convert = require('color-convert'); + +convert.rgb.hex(123, 45, 67); // '7B2D43' +convert.rgb.hex([123, 45, 67]); // '7B2D43' +``` + +## Routing + +Conversions that don't have an _explicitly_ defined conversion (in [conversions.js](conversions.js)), but can be converted by means of sub-conversions (e.g. XYZ -> **RGB** -> CMYK), are automatically routed together. This allows just about any color model supported by `color-convert` to be converted to any other model, so long as a sub-conversion path exists. This is also true for conversions requiring more than one step in between (e.g. LCH -> **LAB** -> **XYZ** -> **RGB** -> Hex). + +Keep in mind that extensive conversions _may_ result in a loss of precision, and exist only to be complete. For a list of "direct" (single-step) conversions, see [conversions.js](conversions.js). + +# Contribute + +If there is a new model you would like to support, or want to add a direct conversion between two existing models, please send us a pull request. + +# License +Copyright © 2011-2016, Heather Arthur and Josh Junon. Licensed under the [MIT License](LICENSE). diff --git a/node_modules/color-convert/conversions.js b/node_modules/color-convert/conversions.js new file mode 100644 index 0000000000000000000000000000000000000000..2657f265c9e1022ed06a232f4da4db578d3d3fb0 --- /dev/null +++ b/node_modules/color-convert/conversions.js @@ -0,0 +1,839 @@ +/* MIT license */ +/* eslint-disable no-mixed-operators */ +const cssKeywords = require('color-name'); + +// NOTE: conversions should only return primitive values (i.e. arrays, or +// values that give correct `typeof` results). +// do not use box values types (i.e. Number(), String(), etc.) + +const reverseKeywords = {}; +for (const key of Object.keys(cssKeywords)) { + reverseKeywords[cssKeywords[key]] = key; +} + +const convert = { + rgb: {channels: 3, labels: 'rgb'}, + hsl: {channels: 3, labels: 'hsl'}, + hsv: {channels: 3, labels: 'hsv'}, + hwb: {channels: 3, labels: 'hwb'}, + cmyk: {channels: 4, labels: 'cmyk'}, + xyz: {channels: 3, labels: 'xyz'}, + lab: {channels: 3, labels: 'lab'}, + lch: {channels: 3, labels: 'lch'}, + hex: {channels: 1, labels: ['hex']}, + keyword: {channels: 1, labels: ['keyword']}, + ansi16: {channels: 1, labels: ['ansi16']}, + ansi256: {channels: 1, labels: ['ansi256']}, + hcg: {channels: 3, labels: ['h', 'c', 'g']}, + apple: {channels: 3, labels: ['r16', 'g16', 'b16']}, + gray: {channels: 1, labels: ['gray']} +}; + +module.exports = convert; + +// Hide .channels and .labels properties +for (const model of Object.keys(convert)) { + if (!('channels' in convert[model])) { + throw new Error('missing channels property: ' + model); + } + + if (!('labels' in convert[model])) { + throw new Error('missing channel labels property: ' + model); + } + + if (convert[model].labels.length !== convert[model].channels) { + throw new Error('channel and label counts mismatch: ' + model); + } + + const {channels, labels} = convert[model]; + delete convert[model].channels; + delete convert[model].labels; + Object.defineProperty(convert[model], 'channels', {value: channels}); + Object.defineProperty(convert[model], 'labels', {value: labels}); +} + +convert.rgb.hsl = function (rgb) { + const r = rgb[0] / 255; + const g = rgb[1] / 255; + const b = rgb[2] / 255; + const min = Math.min(r, g, b); + const max = Math.max(r, g, b); + const delta = max - min; + let h; + let s; + + if (max === min) { + h = 0; + } else if (r === max) { + h = (g - b) / delta; + } else if (g === max) { + h = 2 + (b - r) / delta; + } else if (b === max) { + h = 4 + (r - g) / delta; + } + + h = Math.min(h * 60, 360); + + if (h < 0) { + h += 360; + } + + const l = (min + max) / 2; + + if (max === min) { + s = 0; + } else if (l <= 0.5) { + s = delta / (max + min); + } else { + s = delta / (2 - max - min); + } + + return [h, s * 100, l * 100]; +}; + +convert.rgb.hsv = function (rgb) { + let rdif; + let gdif; + let bdif; + let h; + let s; + + const r = rgb[0] / 255; + const g = rgb[1] / 255; + const b = rgb[2] / 255; + const v = Math.max(r, g, b); + const diff = v - Math.min(r, g, b); + const diffc = function (c) { + return (v - c) / 6 / diff + 1 / 2; + }; + + if (diff === 0) { + h = 0; + s = 0; + } else { + s = diff / v; + rdif = diffc(r); + gdif = diffc(g); + bdif = diffc(b); + + if (r === v) { + h = bdif - gdif; + } else if (g === v) { + h = (1 / 3) + rdif - bdif; + } else if (b === v) { + h = (2 / 3) + gdif - rdif; + } + + if (h < 0) { + h += 1; + } else if (h > 1) { + h -= 1; + } + } + + return [ + h * 360, + s * 100, + v * 100 + ]; +}; + +convert.rgb.hwb = function (rgb) { + const r = rgb[0]; + const g = rgb[1]; + let b = rgb[2]; + const h = convert.rgb.hsl(rgb)[0]; + const w = 1 / 255 * Math.min(r, Math.min(g, b)); + + b = 1 - 1 / 255 * Math.max(r, Math.max(g, b)); + + return [h, w * 100, b * 100]; +}; + +convert.rgb.cmyk = function (rgb) { + const r = rgb[0] / 255; + const g = rgb[1] / 255; + const b = rgb[2] / 255; + + const k = Math.min(1 - r, 1 - g, 1 - b); + const c = (1 - r - k) / (1 - k) || 0; + const m = (1 - g - k) / (1 - k) || 0; + const y = (1 - b - k) / (1 - k) || 0; + + return [c * 100, m * 100, y * 100, k * 100]; +}; + +function comparativeDistance(x, y) { + /* + See https://en.m.wikipedia.org/wiki/Euclidean_distance#Squared_Euclidean_distance + */ + return ( + ((x[0] - y[0]) ** 2) + + ((x[1] - y[1]) ** 2) + + ((x[2] - y[2]) ** 2) + ); +} + +convert.rgb.keyword = function (rgb) { + const reversed = reverseKeywords[rgb]; + if (reversed) { + return reversed; + } + + let currentClosestDistance = Infinity; + let currentClosestKeyword; + + for (const keyword of Object.keys(cssKeywords)) { + const value = cssKeywords[keyword]; + + // Compute comparative distance + const distance = comparativeDistance(rgb, value); + + // Check if its less, if so set as closest + if (distance < currentClosestDistance) { + currentClosestDistance = distance; + currentClosestKeyword = keyword; + } + } + + return currentClosestKeyword; +}; + +convert.keyword.rgb = function (keyword) { + return cssKeywords[keyword]; +}; + +convert.rgb.xyz = function (rgb) { + let r = rgb[0] / 255; + let g = rgb[1] / 255; + let b = rgb[2] / 255; + + // Assume sRGB + r = r > 0.04045 ? (((r + 0.055) / 1.055) ** 2.4) : (r / 12.92); + g = g > 0.04045 ? (((g + 0.055) / 1.055) ** 2.4) : (g / 12.92); + b = b > 0.04045 ? (((b + 0.055) / 1.055) ** 2.4) : (b / 12.92); + + const x = (r * 0.4124) + (g * 0.3576) + (b * 0.1805); + const y = (r * 0.2126) + (g * 0.7152) + (b * 0.0722); + const z = (r * 0.0193) + (g * 0.1192) + (b * 0.9505); + + return [x * 100, y * 100, z * 100]; +}; + +convert.rgb.lab = function (rgb) { + const xyz = convert.rgb.xyz(rgb); + let x = xyz[0]; + let y = xyz[1]; + let z = xyz[2]; + + x /= 95.047; + y /= 100; + z /= 108.883; + + x = x > 0.008856 ? (x ** (1 / 3)) : (7.787 * x) + (16 / 116); + y = y > 0.008856 ? (y ** (1 / 3)) : (7.787 * y) + (16 / 116); + z = z > 0.008856 ? (z ** (1 / 3)) : (7.787 * z) + (16 / 116); + + const l = (116 * y) - 16; + const a = 500 * (x - y); + const b = 200 * (y - z); + + return [l, a, b]; +}; + +convert.hsl.rgb = function (hsl) { + const h = hsl[0] / 360; + const s = hsl[1] / 100; + const l = hsl[2] / 100; + let t2; + let t3; + let val; + + if (s === 0) { + val = l * 255; + return [val, val, val]; + } + + if (l < 0.5) { + t2 = l * (1 + s); + } else { + t2 = l + s - l * s; + } + + const t1 = 2 * l - t2; + + const rgb = [0, 0, 0]; + for (let i = 0; i < 3; i++) { + t3 = h + 1 / 3 * -(i - 1); + if (t3 < 0) { + t3++; + } + + if (t3 > 1) { + t3--; + } + + if (6 * t3 < 1) { + val = t1 + (t2 - t1) * 6 * t3; + } else if (2 * t3 < 1) { + val = t2; + } else if (3 * t3 < 2) { + val = t1 + (t2 - t1) * (2 / 3 - t3) * 6; + } else { + val = t1; + } + + rgb[i] = val * 255; + } + + return rgb; +}; + +convert.hsl.hsv = function (hsl) { + const h = hsl[0]; + let s = hsl[1] / 100; + let l = hsl[2] / 100; + let smin = s; + const lmin = Math.max(l, 0.01); + + l *= 2; + s *= (l <= 1) ? l : 2 - l; + smin *= lmin <= 1 ? lmin : 2 - lmin; + const v = (l + s) / 2; + const sv = l === 0 ? (2 * smin) / (lmin + smin) : (2 * s) / (l + s); + + return [h, sv * 100, v * 100]; +}; + +convert.hsv.rgb = function (hsv) { + const h = hsv[0] / 60; + const s = hsv[1] / 100; + let v = hsv[2] / 100; + const hi = Math.floor(h) % 6; + + const f = h - Math.floor(h); + const p = 255 * v * (1 - s); + const q = 255 * v * (1 - (s * f)); + const t = 255 * v * (1 - (s * (1 - f))); + v *= 255; + + switch (hi) { + case 0: + return [v, t, p]; + case 1: + return [q, v, p]; + case 2: + return [p, v, t]; + case 3: + return [p, q, v]; + case 4: + return [t, p, v]; + case 5: + return [v, p, q]; + } +}; + +convert.hsv.hsl = function (hsv) { + const h = hsv[0]; + const s = hsv[1] / 100; + const v = hsv[2] / 100; + const vmin = Math.max(v, 0.01); + let sl; + let l; + + l = (2 - s) * v; + const lmin = (2 - s) * vmin; + sl = s * vmin; + sl /= (lmin <= 1) ? lmin : 2 - lmin; + sl = sl || 0; + l /= 2; + + return [h, sl * 100, l * 100]; +}; + +// http://dev.w3.org/csswg/css-color/#hwb-to-rgb +convert.hwb.rgb = function (hwb) { + const h = hwb[0] / 360; + let wh = hwb[1] / 100; + let bl = hwb[2] / 100; + const ratio = wh + bl; + let f; + + // Wh + bl cant be > 1 + if (ratio > 1) { + wh /= ratio; + bl /= ratio; + } + + const i = Math.floor(6 * h); + const v = 1 - bl; + f = 6 * h - i; + + if ((i & 0x01) !== 0) { + f = 1 - f; + } + + const n = wh + f * (v - wh); // Linear interpolation + + let r; + let g; + let b; + /* eslint-disable max-statements-per-line,no-multi-spaces */ + switch (i) { + default: + case 6: + case 0: r = v; g = n; b = wh; break; + case 1: r = n; g = v; b = wh; break; + case 2: r = wh; g = v; b = n; break; + case 3: r = wh; g = n; b = v; break; + case 4: r = n; g = wh; b = v; break; + case 5: r = v; g = wh; b = n; break; + } + /* eslint-enable max-statements-per-line,no-multi-spaces */ + + return [r * 255, g * 255, b * 255]; +}; + +convert.cmyk.rgb = function (cmyk) { + const c = cmyk[0] / 100; + const m = cmyk[1] / 100; + const y = cmyk[2] / 100; + const k = cmyk[3] / 100; + + const r = 1 - Math.min(1, c * (1 - k) + k); + const g = 1 - Math.min(1, m * (1 - k) + k); + const b = 1 - Math.min(1, y * (1 - k) + k); + + return [r * 255, g * 255, b * 255]; +}; + +convert.xyz.rgb = function (xyz) { + const x = xyz[0] / 100; + const y = xyz[1] / 100; + const z = xyz[2] / 100; + let r; + let g; + let b; + + r = (x * 3.2406) + (y * -1.5372) + (z * -0.4986); + g = (x * -0.9689) + (y * 1.8758) + (z * 0.0415); + b = (x * 0.0557) + (y * -0.2040) + (z * 1.0570); + + // Assume sRGB + r = r > 0.0031308 + ? ((1.055 * (r ** (1.0 / 2.4))) - 0.055) + : r * 12.92; + + g = g > 0.0031308 + ? ((1.055 * (g ** (1.0 / 2.4))) - 0.055) + : g * 12.92; + + b = b > 0.0031308 + ? ((1.055 * (b ** (1.0 / 2.4))) - 0.055) + : b * 12.92; + + r = Math.min(Math.max(0, r), 1); + g = Math.min(Math.max(0, g), 1); + b = Math.min(Math.max(0, b), 1); + + return [r * 255, g * 255, b * 255]; +}; + +convert.xyz.lab = function (xyz) { + let x = xyz[0]; + let y = xyz[1]; + let z = xyz[2]; + + x /= 95.047; + y /= 100; + z /= 108.883; + + x = x > 0.008856 ? (x ** (1 / 3)) : (7.787 * x) + (16 / 116); + y = y > 0.008856 ? (y ** (1 / 3)) : (7.787 * y) + (16 / 116); + z = z > 0.008856 ? (z ** (1 / 3)) : (7.787 * z) + (16 / 116); + + const l = (116 * y) - 16; + const a = 500 * (x - y); + const b = 200 * (y - z); + + return [l, a, b]; +}; + +convert.lab.xyz = function (lab) { + const l = lab[0]; + const a = lab[1]; + const b = lab[2]; + let x; + let y; + let z; + + y = (l + 16) / 116; + x = a / 500 + y; + z = y - b / 200; + + const y2 = y ** 3; + const x2 = x ** 3; + const z2 = z ** 3; + y = y2 > 0.008856 ? y2 : (y - 16 / 116) / 7.787; + x = x2 > 0.008856 ? x2 : (x - 16 / 116) / 7.787; + z = z2 > 0.008856 ? z2 : (z - 16 / 116) / 7.787; + + x *= 95.047; + y *= 100; + z *= 108.883; + + return [x, y, z]; +}; + +convert.lab.lch = function (lab) { + const l = lab[0]; + const a = lab[1]; + const b = lab[2]; + let h; + + const hr = Math.atan2(b, a); + h = hr * 360 / 2 / Math.PI; + + if (h < 0) { + h += 360; + } + + const c = Math.sqrt(a * a + b * b); + + return [l, c, h]; +}; + +convert.lch.lab = function (lch) { + const l = lch[0]; + const c = lch[1]; + const h = lch[2]; + + const hr = h / 360 * 2 * Math.PI; + const a = c * Math.cos(hr); + const b = c * Math.sin(hr); + + return [l, a, b]; +}; + +convert.rgb.ansi16 = function (args, saturation = null) { + const [r, g, b] = args; + let value = saturation === null ? convert.rgb.hsv(args)[2] : saturation; // Hsv -> ansi16 optimization + + value = Math.round(value / 50); + + if (value === 0) { + return 30; + } + + let ansi = 30 + + ((Math.round(b / 255) << 2) + | (Math.round(g / 255) << 1) + | Math.round(r / 255)); + + if (value === 2) { + ansi += 60; + } + + return ansi; +}; + +convert.hsv.ansi16 = function (args) { + // Optimization here; we already know the value and don't need to get + // it converted for us. + return convert.rgb.ansi16(convert.hsv.rgb(args), args[2]); +}; + +convert.rgb.ansi256 = function (args) { + const r = args[0]; + const g = args[1]; + const b = args[2]; + + // We use the extended greyscale palette here, with the exception of + // black and white. normal palette only has 4 greyscale shades. + if (r === g && g === b) { + if (r < 8) { + return 16; + } + + if (r > 248) { + return 231; + } + + return Math.round(((r - 8) / 247) * 24) + 232; + } + + const ansi = 16 + + (36 * Math.round(r / 255 * 5)) + + (6 * Math.round(g / 255 * 5)) + + Math.round(b / 255 * 5); + + return ansi; +}; + +convert.ansi16.rgb = function (args) { + let color = args % 10; + + // Handle greyscale + if (color === 0 || color === 7) { + if (args > 50) { + color += 3.5; + } + + color = color / 10.5 * 255; + + return [color, color, color]; + } + + const mult = (~~(args > 50) + 1) * 0.5; + const r = ((color & 1) * mult) * 255; + const g = (((color >> 1) & 1) * mult) * 255; + const b = (((color >> 2) & 1) * mult) * 255; + + return [r, g, b]; +}; + +convert.ansi256.rgb = function (args) { + // Handle greyscale + if (args >= 232) { + const c = (args - 232) * 10 + 8; + return [c, c, c]; + } + + args -= 16; + + let rem; + const r = Math.floor(args / 36) / 5 * 255; + const g = Math.floor((rem = args % 36) / 6) / 5 * 255; + const b = (rem % 6) / 5 * 255; + + return [r, g, b]; +}; + +convert.rgb.hex = function (args) { + const integer = ((Math.round(args[0]) & 0xFF) << 16) + + ((Math.round(args[1]) & 0xFF) << 8) + + (Math.round(args[2]) & 0xFF); + + const string = integer.toString(16).toUpperCase(); + return '000000'.substring(string.length) + string; +}; + +convert.hex.rgb = function (args) { + const match = args.toString(16).match(/[a-f0-9]{6}|[a-f0-9]{3}/i); + if (!match) { + return [0, 0, 0]; + } + + let colorString = match[0]; + + if (match[0].length === 3) { + colorString = colorString.split('').map(char => { + return char + char; + }).join(''); + } + + const integer = parseInt(colorString, 16); + const r = (integer >> 16) & 0xFF; + const g = (integer >> 8) & 0xFF; + const b = integer & 0xFF; + + return [r, g, b]; +}; + +convert.rgb.hcg = function (rgb) { + const r = rgb[0] / 255; + const g = rgb[1] / 255; + const b = rgb[2] / 255; + const max = Math.max(Math.max(r, g), b); + const min = Math.min(Math.min(r, g), b); + const chroma = (max - min); + let grayscale; + let hue; + + if (chroma < 1) { + grayscale = min / (1 - chroma); + } else { + grayscale = 0; + } + + if (chroma <= 0) { + hue = 0; + } else + if (max === r) { + hue = ((g - b) / chroma) % 6; + } else + if (max === g) { + hue = 2 + (b - r) / chroma; + } else { + hue = 4 + (r - g) / chroma; + } + + hue /= 6; + hue %= 1; + + return [hue * 360, chroma * 100, grayscale * 100]; +}; + +convert.hsl.hcg = function (hsl) { + const s = hsl[1] / 100; + const l = hsl[2] / 100; + + const c = l < 0.5 ? (2.0 * s * l) : (2.0 * s * (1.0 - l)); + + let f = 0; + if (c < 1.0) { + f = (l - 0.5 * c) / (1.0 - c); + } + + return [hsl[0], c * 100, f * 100]; +}; + +convert.hsv.hcg = function (hsv) { + const s = hsv[1] / 100; + const v = hsv[2] / 100; + + const c = s * v; + let f = 0; + + if (c < 1.0) { + f = (v - c) / (1 - c); + } + + return [hsv[0], c * 100, f * 100]; +}; + +convert.hcg.rgb = function (hcg) { + const h = hcg[0] / 360; + const c = hcg[1] / 100; + const g = hcg[2] / 100; + + if (c === 0.0) { + return [g * 255, g * 255, g * 255]; + } + + const pure = [0, 0, 0]; + const hi = (h % 1) * 6; + const v = hi % 1; + const w = 1 - v; + let mg = 0; + + /* eslint-disable max-statements-per-line */ + switch (Math.floor(hi)) { + case 0: + pure[0] = 1; pure[1] = v; pure[2] = 0; break; + case 1: + pure[0] = w; pure[1] = 1; pure[2] = 0; break; + case 2: + pure[0] = 0; pure[1] = 1; pure[2] = v; break; + case 3: + pure[0] = 0; pure[1] = w; pure[2] = 1; break; + case 4: + pure[0] = v; pure[1] = 0; pure[2] = 1; break; + default: + pure[0] = 1; pure[1] = 0; pure[2] = w; + } + /* eslint-enable max-statements-per-line */ + + mg = (1.0 - c) * g; + + return [ + (c * pure[0] + mg) * 255, + (c * pure[1] + mg) * 255, + (c * pure[2] + mg) * 255 + ]; +}; + +convert.hcg.hsv = function (hcg) { + const c = hcg[1] / 100; + const g = hcg[2] / 100; + + const v = c + g * (1.0 - c); + let f = 0; + + if (v > 0.0) { + f = c / v; + } + + return [hcg[0], f * 100, v * 100]; +}; + +convert.hcg.hsl = function (hcg) { + const c = hcg[1] / 100; + const g = hcg[2] / 100; + + const l = g * (1.0 - c) + 0.5 * c; + let s = 0; + + if (l > 0.0 && l < 0.5) { + s = c / (2 * l); + } else + if (l >= 0.5 && l < 1.0) { + s = c / (2 * (1 - l)); + } + + return [hcg[0], s * 100, l * 100]; +}; + +convert.hcg.hwb = function (hcg) { + const c = hcg[1] / 100; + const g = hcg[2] / 100; + const v = c + g * (1.0 - c); + return [hcg[0], (v - c) * 100, (1 - v) * 100]; +}; + +convert.hwb.hcg = function (hwb) { + const w = hwb[1] / 100; + const b = hwb[2] / 100; + const v = 1 - b; + const c = v - w; + let g = 0; + + if (c < 1) { + g = (v - c) / (1 - c); + } + + return [hwb[0], c * 100, g * 100]; +}; + +convert.apple.rgb = function (apple) { + return [(apple[0] / 65535) * 255, (apple[1] / 65535) * 255, (apple[2] / 65535) * 255]; +}; + +convert.rgb.apple = function (rgb) { + return [(rgb[0] / 255) * 65535, (rgb[1] / 255) * 65535, (rgb[2] / 255) * 65535]; +}; + +convert.gray.rgb = function (args) { + return [args[0] / 100 * 255, args[0] / 100 * 255, args[0] / 100 * 255]; +}; + +convert.gray.hsl = function (args) { + return [0, 0, args[0]]; +}; + +convert.gray.hsv = convert.gray.hsl; + +convert.gray.hwb = function (gray) { + return [0, 100, gray[0]]; +}; + +convert.gray.cmyk = function (gray) { + return [0, 0, 0, gray[0]]; +}; + +convert.gray.lab = function (gray) { + return [gray[0], 0, 0]; +}; + +convert.gray.hex = function (gray) { + const val = Math.round(gray[0] / 100 * 255) & 0xFF; + const integer = (val << 16) + (val << 8) + val; + + const string = integer.toString(16).toUpperCase(); + return '000000'.substring(string.length) + string; +}; + +convert.rgb.gray = function (rgb) { + const val = (rgb[0] + rgb[1] + rgb[2]) / 3; + return [val / 255 * 100]; +}; diff --git a/node_modules/color-convert/index.js b/node_modules/color-convert/index.js new file mode 100644 index 0000000000000000000000000000000000000000..b648e5737be6168bff5137cb1a5a897e55ce193d --- /dev/null +++ b/node_modules/color-convert/index.js @@ -0,0 +1,81 @@ +const conversions = require('./conversions'); +const route = require('./route'); + +const convert = {}; + +const models = Object.keys(conversions); + +function wrapRaw(fn) { + const wrappedFn = function (...args) { + const arg0 = args[0]; + if (arg0 === undefined || arg0 === null) { + return arg0; + } + + if (arg0.length > 1) { + args = arg0; + } + + return fn(args); + }; + + // Preserve .conversion property if there is one + if ('conversion' in fn) { + wrappedFn.conversion = fn.conversion; + } + + return wrappedFn; +} + +function wrapRounded(fn) { + const wrappedFn = function (...args) { + const arg0 = args[0]; + + if (arg0 === undefined || arg0 === null) { + return arg0; + } + + if (arg0.length > 1) { + args = arg0; + } + + const result = fn(args); + + // We're assuming the result is an array here. + // see notice in conversions.js; don't use box types + // in conversion functions. + if (typeof result === 'object') { + for (let len = result.length, i = 0; i < len; i++) { + result[i] = Math.round(result[i]); + } + } + + return result; + }; + + // Preserve .conversion property if there is one + if ('conversion' in fn) { + wrappedFn.conversion = fn.conversion; + } + + return wrappedFn; +} + +models.forEach(fromModel => { + convert[fromModel] = {}; + + Object.defineProperty(convert[fromModel], 'channels', {value: conversions[fromModel].channels}); + Object.defineProperty(convert[fromModel], 'labels', {value: conversions[fromModel].labels}); + + const routes = route(fromModel); + const routeModels = Object.keys(routes); + + routeModels.forEach(toModel => { + const fn = routes[toModel]; + + convert[fromModel][toModel] = wrapRounded(fn); + convert[fromModel][toModel].raw = wrapRaw(fn); + }); +}); + +module.exports = convert; diff --git a/node_modules/color-convert/package.json b/node_modules/color-convert/package.json new file mode 100644 index 0000000000000000000000000000000000000000..6e48000c7c98fd844af784fb2fdf7060f13ed0b1 --- /dev/null +++ b/node_modules/color-convert/package.json @@ -0,0 +1,48 @@ +{ + "name": "color-convert", + "description": "Plain color conversion functions", + "version": "2.0.1", + "author": "Heather Arthur ", + "license": "MIT", + "repository": "Qix-/color-convert", + "scripts": { + "pretest": "xo", + "test": "node test/basic.js" + }, + "engines": { + "node": ">=7.0.0" + }, + "keywords": [ + "color", + "colour", + "convert", + "converter", + "conversion", + "rgb", + "hsl", + "hsv", + "hwb", + "cmyk", + "ansi", + "ansi16" + ], + "files": [ + "index.js", + "conversions.js", + "route.js" + ], + "xo": { + "rules": { + "default-case": 0, + "no-inline-comments": 0, + "operator-linebreak": 0 + } + }, + "devDependencies": { + "chalk": "^2.4.2", + "xo": "^0.24.0" + }, + "dependencies": { + "color-name": "~1.1.4" + } +} diff --git a/node_modules/color-convert/route.js b/node_modules/color-convert/route.js new file mode 100644 index 0000000000000000000000000000000000000000..1a08521b5a001793a0a2c705d442a29949b1f051 --- /dev/null +++ b/node_modules/color-convert/route.js @@ -0,0 +1,97 @@ +const conversions = require('./conversions'); + +/* + This function routes a model to all other models. + + all functions that are routed have a property `.conversion` attached + to the returned synthetic function. This property is an array + of strings, each with the steps in between the 'from' and 'to' + color models (inclusive). + + conversions that are not possible simply are not included. +*/ + +function buildGraph() { + const graph = {}; + // https://jsperf.com/object-keys-vs-for-in-with-closure/3 + const models = Object.keys(conversions); + + for (let len = models.length, i = 0; i < len; i++) { + graph[models[i]] = { + // http://jsperf.com/1-vs-infinity + // micro-opt, but this is simple. + distance: -1, + parent: null + }; + } + + return graph; +} + +// https://en.wikipedia.org/wiki/Breadth-first_search +function deriveBFS(fromModel) { + const graph = buildGraph(); + const queue = [fromModel]; // Unshift -> queue -> pop + + graph[fromModel].distance = 0; + + while (queue.length) { + const current = queue.pop(); + const adjacents = Object.keys(conversions[current]); + + for (let len = adjacents.length, i = 0; i < len; i++) { + const adjacent = adjacents[i]; + const node = graph[adjacent]; + + if (node.distance === -1) { + node.distance = graph[current].distance + 1; + node.parent = current; + queue.unshift(adjacent); + } + } + } + + return graph; +} + +function link(from, to) { + return function (args) { + return to(from(args)); + }; +} + +function wrapConversion(toModel, graph) { + const path = [graph[toModel].parent, toModel]; + let fn = conversions[graph[toModel].parent][toModel]; + + let cur = graph[toModel].parent; + while (graph[cur].parent) { + path.unshift(graph[cur].parent); + fn = link(conversions[graph[cur].parent][cur], fn); + cur = graph[cur].parent; + } + + fn.conversion = path; + return fn; +} + +module.exports = function (fromModel) { + const graph = deriveBFS(fromModel); + const conversion = {}; + + const models = Object.keys(graph); + for (let len = models.length, i = 0; i < len; i++) { + const toModel = models[i]; + const node = graph[toModel]; + + if (node.parent === null) { + // No possible conversion, or this node is the source model. + continue; + } + + conversion[toModel] = wrapConversion(toModel, graph); + } + + return conversion; +}; + diff --git a/node_modules/color-name/LICENSE b/node_modules/color-name/LICENSE new file mode 100644 index 0000000000000000000000000000000000000000..c6b10012540c24ceec902ae292dbfe31214d40f8 --- /dev/null +++ b/node_modules/color-name/LICENSE @@ -0,0 +1,8 @@ +The MIT License (MIT) +Copyright (c) 2015 Dmitry Ivanov + +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. \ No newline at end of file diff --git a/node_modules/color-name/README.md b/node_modules/color-name/README.md new file mode 100644 index 0000000000000000000000000000000000000000..932b979176f33bf738aa6293c70bb3e451f2baf5 --- /dev/null +++ b/node_modules/color-name/README.md @@ -0,0 +1,11 @@ +A JSON with color names and its values. Based on http://dev.w3.org/csswg/css-color/#named-colors. + +[![NPM](https://nodei.co/npm/color-name.png?mini=true)](https://nodei.co/npm/color-name/) + + +```js +var colors = require('color-name'); +colors.red //[255,0,0] +``` + + diff --git a/node_modules/color-name/index.js b/node_modules/color-name/index.js new file mode 100644 index 0000000000000000000000000000000000000000..b7c198a6f3d7c579041efc7a54358fd89cddf43a --- /dev/null +++ b/node_modules/color-name/index.js @@ -0,0 +1,152 @@ +'use strict' + +module.exports = { + "aliceblue": [240, 248, 255], + "antiquewhite": [250, 235, 215], + "aqua": [0, 255, 255], + "aquamarine": [127, 255, 212], + "azure": [240, 255, 255], + "beige": [245, 245, 220], + "bisque": [255, 228, 196], + "black": [0, 0, 0], + "blanchedalmond": [255, 235, 205], + "blue": [0, 0, 255], + "blueviolet": [138, 43, 226], + "brown": [165, 42, 42], + "burlywood": [222, 184, 135], + "cadetblue": [95, 158, 160], + "chartreuse": [127, 255, 0], + "chocolate": [210, 105, 30], + "coral": [255, 127, 80], + "cornflowerblue": [100, 149, 237], + "cornsilk": [255, 248, 220], + "crimson": [220, 20, 60], + "cyan": [0, 255, 255], + "darkblue": [0, 0, 139], + "darkcyan": [0, 139, 139], + "darkgoldenrod": [184, 134, 11], + "darkgray": [169, 169, 169], + "darkgreen": [0, 100, 0], + "darkgrey": [169, 169, 169], + "darkkhaki": [189, 183, 107], + "darkmagenta": [139, 0, 139], + "darkolivegreen": [85, 107, 47], + "darkorange": [255, 140, 0], + "darkorchid": [153, 50, 204], + "darkred": [139, 0, 0], + "darksalmon": [233, 150, 122], + "darkseagreen": [143, 188, 143], + "darkslateblue": [72, 61, 139], + "darkslategray": [47, 79, 79], + "darkslategrey": [47, 79, 79], + "darkturquoise": [0, 206, 209], + "darkviolet": [148, 0, 211], + "deeppink": [255, 20, 147], + "deepskyblue": [0, 191, 255], + "dimgray": [105, 105, 105], + "dimgrey": [105, 105, 105], + "dodgerblue": [30, 144, 255], + "firebrick": [178, 34, 34], + "floralwhite": [255, 250, 240], + "forestgreen": [34, 139, 34], + "fuchsia": [255, 0, 255], + "gainsboro": [220, 220, 220], + "ghostwhite": [248, 248, 255], + "gold": [255, 215, 0], + "goldenrod": [218, 165, 32], + "gray": [128, 128, 128], + "green": [0, 128, 0], + "greenyellow": [173, 255, 47], + "grey": [128, 128, 128], + "honeydew": [240, 255, 240], + "hotpink": [255, 105, 180], + "indianred": [205, 92, 92], + "indigo": [75, 0, 130], + "ivory": [255, 255, 240], + "khaki": [240, 230, 140], + "lavender": [230, 230, 250], + "lavenderblush": [255, 240, 245], + "lawngreen": [124, 252, 0], + "lemonchiffon": [255, 250, 205], + "lightblue": [173, 216, 230], + "lightcoral": [240, 128, 128], + "lightcyan": [224, 255, 255], + "lightgoldenrodyellow": [250, 250, 210], + "lightgray": [211, 211, 211], + "lightgreen": [144, 238, 144], + "lightgrey": [211, 211, 211], + "lightpink": [255, 182, 193], + "lightsalmon": [255, 160, 122], + "lightseagreen": [32, 178, 170], + "lightskyblue": [135, 206, 250], + "lightslategray": [119, 136, 153], + "lightslategrey": [119, 136, 153], + "lightsteelblue": [176, 196, 222], + "lightyellow": [255, 255, 224], + "lime": [0, 255, 0], + "limegreen": [50, 205, 50], + "linen": [250, 240, 230], + "magenta": [255, 0, 255], + "maroon": [128, 0, 0], + "mediumaquamarine": [102, 205, 170], + "mediumblue": [0, 0, 205], + "mediumorchid": [186, 85, 211], + "mediumpurple": [147, 112, 219], + "mediumseagreen": [60, 179, 113], + "mediumslateblue": [123, 104, 238], + "mediumspringgreen": [0, 250, 154], + "mediumturquoise": [72, 209, 204], + "mediumvioletred": [199, 21, 133], + "midnightblue": [25, 25, 112], + "mintcream": [245, 255, 250], + "mistyrose": [255, 228, 225], + "moccasin": [255, 228, 181], + "navajowhite": [255, 222, 173], + "navy": [0, 0, 128], + "oldlace": [253, 245, 230], + "olive": [128, 128, 0], + "olivedrab": [107, 142, 35], + "orange": [255, 165, 0], + "orangered": [255, 69, 0], + "orchid": [218, 112, 214], + "palegoldenrod": [238, 232, 170], + "palegreen": [152, 251, 152], + "paleturquoise": [175, 238, 238], + "palevioletred": [219, 112, 147], + "papayawhip": [255, 239, 213], + "peachpuff": [255, 218, 185], + "peru": [205, 133, 63], + "pink": [255, 192, 203], + "plum": [221, 160, 221], + "powderblue": [176, 224, 230], + "purple": [128, 0, 128], + "rebeccapurple": [102, 51, 153], + "red": [255, 0, 0], + "rosybrown": [188, 143, 143], + "royalblue": [65, 105, 225], + "saddlebrown": [139, 69, 19], + "salmon": [250, 128, 114], + "sandybrown": [244, 164, 96], + "seagreen": [46, 139, 87], + "seashell": [255, 245, 238], + "sienna": [160, 82, 45], + "silver": [192, 192, 192], + "skyblue": [135, 206, 235], + "slateblue": [106, 90, 205], + "slategray": [112, 128, 144], + "slategrey": [112, 128, 144], + "snow": [255, 250, 250], + "springgreen": [0, 255, 127], + "steelblue": [70, 130, 180], + "tan": [210, 180, 140], + "teal": [0, 128, 128], + "thistle": [216, 191, 216], + "tomato": [255, 99, 71], + "turquoise": [64, 224, 208], + "violet": [238, 130, 238], + "wheat": [245, 222, 179], + "white": [255, 255, 255], + "whitesmoke": [245, 245, 245], + "yellow": [255, 255, 0], + "yellowgreen": [154, 205, 50] +}; diff --git a/node_modules/color-name/package.json b/node_modules/color-name/package.json new file mode 100644 index 0000000000000000000000000000000000000000..782dd82878030a00c89c1d72254a2a26dc457986 --- /dev/null +++ b/node_modules/color-name/package.json @@ -0,0 +1,28 @@ +{ + "name": "color-name", + "version": "1.1.4", + "description": "A list of color names and its values", + "main": "index.js", + "files": [ + "index.js" + ], + "scripts": { + "test": "node test.js" + }, + "repository": { + "type": "git", + "url": "git@github.com:colorjs/color-name.git" + }, + "keywords": [ + "color-name", + "color", + "color-keyword", + "keyword" + ], + "author": "DY ", + "license": "MIT", + "bugs": { + "url": "https://github.com/colorjs/color-name/issues" + }, + "homepage": "https://github.com/colorjs/color-name" +} diff --git a/node_modules/cookie/LICENSE b/node_modules/cookie/LICENSE new file mode 100644 index 0000000000000000000000000000000000000000..058b6b4efa3f45896ae691f2558a2a1aca05bebd --- /dev/null +++ b/node_modules/cookie/LICENSE @@ -0,0 +1,24 @@ +(The MIT License) + +Copyright (c) 2012-2014 Roman Shtylman +Copyright (c) 2015 Douglas Christopher Wilson + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +'Software'), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + diff --git a/node_modules/cookie/README.md b/node_modules/cookie/README.md new file mode 100644 index 0000000000000000000000000000000000000000..71fdac1110bba222a716c4b56b90028a6a9e5af4 --- /dev/null +++ b/node_modules/cookie/README.md @@ -0,0 +1,317 @@ +# cookie + +[![NPM Version][npm-version-image]][npm-url] +[![NPM Downloads][npm-downloads-image]][npm-url] +[![Node.js Version][node-image]][node-url] +[![Build Status][ci-image]][ci-url] +[![Coverage Status][coveralls-image]][coveralls-url] + +Basic HTTP cookie parser and serializer for HTTP servers. + +## Installation + +This is a [Node.js](https://nodejs.org/en/) module available through the +[npm registry](https://www.npmjs.com/). Installation is done using the +[`npm install` command](https://docs.npmjs.com/getting-started/installing-npm-packages-locally): + +```sh +$ npm install cookie +``` + +## API + +```js +var cookie = require('cookie'); +``` + +### cookie.parse(str, options) + +Parse an HTTP `Cookie` header string and returning an object of all cookie name-value pairs. +The `str` argument is the string representing a `Cookie` header value and `options` is an +optional object containing additional parsing options. + +```js +var cookies = cookie.parse('foo=bar; equation=E%3Dmc%5E2'); +// { foo: 'bar', equation: 'E=mc^2' } +``` + +#### Options + +`cookie.parse` accepts these properties in the options object. + +##### decode + +Specifies a function that will be used to decode a cookie's value. Since the value of a cookie +has a limited character set (and must be a simple string), this function can be used to decode +a previously-encoded cookie value into a JavaScript string or other object. + +The default function is the global `decodeURIComponent`, which will decode any URL-encoded +sequences into their byte representations. + +**note** if an error is thrown from this function, the original, non-decoded cookie value will +be returned as the cookie's value. + +### cookie.serialize(name, value, options) + +Serialize a cookie name-value pair into a `Set-Cookie` header string. The `name` argument is the +name for the cookie, the `value` argument is the value to set the cookie to, and the `options` +argument is an optional object containing additional serialization options. + +```js +var setCookie = cookie.serialize('foo', 'bar'); +// foo=bar +``` + +#### Options + +`cookie.serialize` accepts these properties in the options object. + +##### domain + +Specifies the value for the [`Domain` `Set-Cookie` attribute][rfc-6265-5.2.3]. By default, no +domain is set, and most clients will consider the cookie to apply to only the current domain. + +##### encode + +Specifies a function that will be used to encode a cookie's value. Since value of a cookie +has a limited character set (and must be a simple string), this function can be used to encode +a value into a string suited for a cookie's value. + +The default function is the global `encodeURIComponent`, which will encode a JavaScript string +into UTF-8 byte sequences and then URL-encode any that fall outside of the cookie range. + +##### expires + +Specifies the `Date` object to be the value for the [`Expires` `Set-Cookie` attribute][rfc-6265-5.2.1]. +By default, no expiration is set, and most clients will consider this a "non-persistent cookie" and +will delete it on a condition like exiting a web browser application. + +**note** the [cookie storage model specification][rfc-6265-5.3] states that if both `expires` and +`maxAge` are set, then `maxAge` takes precedence, but it is possible not all clients by obey this, +so if both are set, they should point to the same date and time. + +##### httpOnly + +Specifies the `boolean` value for the [`HttpOnly` `Set-Cookie` attribute][rfc-6265-5.2.6]. When truthy, +the `HttpOnly` attribute is set, otherwise it is not. By default, the `HttpOnly` attribute is not set. + +**note** be careful when setting this to `true`, as compliant clients will not allow client-side +JavaScript to see the cookie in `document.cookie`. + +##### maxAge + +Specifies the `number` (in seconds) to be the value for the [`Max-Age` `Set-Cookie` attribute][rfc-6265-5.2.2]. +The given number will be converted to an integer by rounding down. By default, no maximum age is set. + +**note** the [cookie storage model specification][rfc-6265-5.3] states that if both `expires` and +`maxAge` are set, then `maxAge` takes precedence, but it is possible not all clients by obey this, +so if both are set, they should point to the same date and time. + +##### partitioned + +Specifies the `boolean` value for the [`Partitioned` `Set-Cookie`](rfc-cutler-httpbis-partitioned-cookies) +attribute. When truthy, the `Partitioned` attribute is set, otherwise it is not. By default, the +`Partitioned` attribute is not set. + +**note** This is an attribute that has not yet been fully standardized, and may change in the future. +This also means many clients may ignore this attribute until they understand it. + +More information about can be found in [the proposal](https://github.com/privacycg/CHIPS). + +##### path + +Specifies the value for the [`Path` `Set-Cookie` attribute][rfc-6265-5.2.4]. By default, the path +is considered the ["default path"][rfc-6265-5.1.4]. + +##### priority + +Specifies the `string` to be the value for the [`Priority` `Set-Cookie` attribute][rfc-west-cookie-priority-00-4.1]. + + - `'low'` will set the `Priority` attribute to `Low`. + - `'medium'` will set the `Priority` attribute to `Medium`, the default priority when not set. + - `'high'` will set the `Priority` attribute to `High`. + +More information about the different priority levels can be found in +[the specification][rfc-west-cookie-priority-00-4.1]. + +**note** This is an attribute that has not yet been fully standardized, and may change in the future. +This also means many clients may ignore this attribute until they understand it. + +##### sameSite + +Specifies the `boolean` or `string` to be the value for the [`SameSite` `Set-Cookie` attribute][rfc-6265bis-09-5.4.7]. + + - `true` will set the `SameSite` attribute to `Strict` for strict same site enforcement. + - `false` will not set the `SameSite` attribute. + - `'lax'` will set the `SameSite` attribute to `Lax` for lax same site enforcement. + - `'none'` will set the `SameSite` attribute to `None` for an explicit cross-site cookie. + - `'strict'` will set the `SameSite` attribute to `Strict` for strict same site enforcement. + +More information about the different enforcement levels can be found in +[the specification][rfc-6265bis-09-5.4.7]. + +**note** This is an attribute that has not yet been fully standardized, and may change in the future. +This also means many clients may ignore this attribute until they understand it. + +##### secure + +Specifies the `boolean` value for the [`Secure` `Set-Cookie` attribute][rfc-6265-5.2.5]. When truthy, +the `Secure` attribute is set, otherwise it is not. By default, the `Secure` attribute is not set. + +**note** be careful when setting this to `true`, as compliant clients will not send the cookie back to +the server in the future if the browser does not have an HTTPS connection. + +## Example + +The following example uses this module in conjunction with the Node.js core HTTP server +to prompt a user for their name and display it back on future visits. + +```js +var cookie = require('cookie'); +var escapeHtml = require('escape-html'); +var http = require('http'); +var url = require('url'); + +function onRequest(req, res) { + // Parse the query string + var query = url.parse(req.url, true, true).query; + + if (query && query.name) { + // Set a new cookie with the name + res.setHeader('Set-Cookie', cookie.serialize('name', String(query.name), { + httpOnly: true, + maxAge: 60 * 60 * 24 * 7 // 1 week + })); + + // Redirect back after setting cookie + res.statusCode = 302; + res.setHeader('Location', req.headers.referer || '/'); + res.end(); + return; + } + + // Parse the cookies on the request + var cookies = cookie.parse(req.headers.cookie || ''); + + // Get the visitor name set in the cookie + var name = cookies.name; + + res.setHeader('Content-Type', 'text/html; charset=UTF-8'); + + if (name) { + res.write('

Welcome back, ' + escapeHtml(name) + '!

'); + } else { + res.write('

Hello, new visitor!

'); + } + + res.write('
'); + res.write(' '); + res.end('
'); +} + +http.createServer(onRequest).listen(3000); +``` + +## Testing + +```sh +$ npm test +``` + +## Benchmark + +``` +$ npm run bench + +> cookie@0.5.0 bench +> node benchmark/index.js + + node@18.18.2 + acorn@8.10.0 + ada@2.6.0 + ares@1.19.1 + brotli@1.0.9 + cldr@43.1 + icu@73.2 + llhttp@6.0.11 + modules@108 + napi@9 + nghttp2@1.57.0 + nghttp3@0.7.0 + ngtcp2@0.8.1 + openssl@3.0.10+quic + simdutf@3.2.14 + tz@2023c + undici@5.26.3 + unicode@15.0 + uv@1.44.2 + uvwasi@0.0.18 + v8@10.2.154.26-node.26 + zlib@1.2.13.1-motley + +> node benchmark/parse-top.js + + cookie.parse - top sites + + 14 tests completed. + + parse accounts.google.com x 2,588,913 ops/sec ±0.74% (186 runs sampled) + parse apple.com x 2,370,002 ops/sec ±0.69% (186 runs sampled) + parse cloudflare.com x 2,213,102 ops/sec ±0.88% (188 runs sampled) + parse docs.google.com x 2,194,157 ops/sec ±1.03% (184 runs sampled) + parse drive.google.com x 2,265,084 ops/sec ±0.79% (187 runs sampled) + parse en.wikipedia.org x 457,099 ops/sec ±0.81% (186 runs sampled) + parse linkedin.com x 504,407 ops/sec ±0.89% (186 runs sampled) + parse maps.google.com x 1,230,959 ops/sec ±0.98% (186 runs sampled) + parse microsoft.com x 926,294 ops/sec ±0.88% (184 runs sampled) + parse play.google.com x 2,311,338 ops/sec ±0.83% (185 runs sampled) + parse support.google.com x 1,508,850 ops/sec ±0.86% (186 runs sampled) + parse www.google.com x 1,022,582 ops/sec ±1.32% (182 runs sampled) + parse youtu.be x 332,136 ops/sec ±1.02% (185 runs sampled) + parse youtube.com x 323,833 ops/sec ±0.77% (183 runs sampled) + +> node benchmark/parse.js + + cookie.parse - generic + + 6 tests completed. + + simple x 3,214,032 ops/sec ±1.61% (183 runs sampled) + decode x 587,237 ops/sec ±1.16% (187 runs sampled) + unquote x 2,954,618 ops/sec ±1.35% (183 runs sampled) + duplicates x 857,008 ops/sec ±0.89% (187 runs sampled) + 10 cookies x 292,133 ops/sec ±0.89% (187 runs sampled) + 100 cookies x 22,610 ops/sec ±0.68% (187 runs sampled) +``` + +## References + +- [RFC 6265: HTTP State Management Mechanism][rfc-6265] +- [Same-site Cookies][rfc-6265bis-09-5.4.7] + +[rfc-cutler-httpbis-partitioned-cookies]: https://tools.ietf.org/html/draft-cutler-httpbis-partitioned-cookies/ +[rfc-west-cookie-priority-00-4.1]: https://tools.ietf.org/html/draft-west-cookie-priority-00#section-4.1 +[rfc-6265bis-09-5.4.7]: https://tools.ietf.org/html/draft-ietf-httpbis-rfc6265bis-09#section-5.4.7 +[rfc-6265]: https://tools.ietf.org/html/rfc6265 +[rfc-6265-5.1.4]: https://tools.ietf.org/html/rfc6265#section-5.1.4 +[rfc-6265-5.2.1]: https://tools.ietf.org/html/rfc6265#section-5.2.1 +[rfc-6265-5.2.2]: https://tools.ietf.org/html/rfc6265#section-5.2.2 +[rfc-6265-5.2.3]: https://tools.ietf.org/html/rfc6265#section-5.2.3 +[rfc-6265-5.2.4]: https://tools.ietf.org/html/rfc6265#section-5.2.4 +[rfc-6265-5.2.5]: https://tools.ietf.org/html/rfc6265#section-5.2.5 +[rfc-6265-5.2.6]: https://tools.ietf.org/html/rfc6265#section-5.2.6 +[rfc-6265-5.3]: https://tools.ietf.org/html/rfc6265#section-5.3 + +## License + +[MIT](LICENSE) + +[ci-image]: https://badgen.net/github/checks/jshttp/cookie/master?label=ci +[ci-url]: https://github.com/jshttp/cookie/actions/workflows/ci.yml +[coveralls-image]: https://badgen.net/coveralls/c/github/jshttp/cookie/master +[coveralls-url]: https://coveralls.io/r/jshttp/cookie?branch=master +[node-image]: https://badgen.net/npm/node/cookie +[node-url]: https://nodejs.org/en/download +[npm-downloads-image]: https://badgen.net/npm/dm/cookie +[npm-url]: https://npmjs.org/package/cookie +[npm-version-image]: https://badgen.net/npm/v/cookie diff --git a/node_modules/cookie/SECURITY.md b/node_modules/cookie/SECURITY.md new file mode 100644 index 0000000000000000000000000000000000000000..fd4a6c53a9cd1abacf91125dab3fde3163b4c412 --- /dev/null +++ b/node_modules/cookie/SECURITY.md @@ -0,0 +1,25 @@ +# Security Policies and Procedures + +## Reporting a Bug + +The `cookie` team and community take all security bugs seriously. Thank +you for improving the security of the project. We appreciate your efforts and +responsible disclosure and will make every effort to acknowledge your +contributions. + +Report security bugs by emailing the current owner(s) of `cookie`. This +information can be found in the npm registry using the command +`npm owner ls cookie`. +If unsure or unable to get the information from the above, open an issue +in the [project issue tracker](https://github.com/jshttp/cookie/issues) +asking for the current contact information. + +To ensure the timely response to your report, please ensure that the entirety +of the report is contained within the email body and not solely behind a web +link or an attachment. + +At least one owner will acknowledge your email within 48 hours, and will send a +more detailed response within 48 hours indicating the next steps in handling +your report. After the initial reply to your report, the owners will +endeavor to keep you informed of the progress towards a fix and full +announcement, and may ask for additional information or guidance. diff --git a/node_modules/cookie/index.js b/node_modules/cookie/index.js new file mode 100644 index 0000000000000000000000000000000000000000..acd5acd6ab3cfd4441516573c5948db0ea6d7785 --- /dev/null +++ b/node_modules/cookie/index.js @@ -0,0 +1,335 @@ +/*! + * cookie + * Copyright(c) 2012-2014 Roman Shtylman + * Copyright(c) 2015 Douglas Christopher Wilson + * MIT Licensed + */ + +'use strict'; + +/** + * Module exports. + * @public + */ + +exports.parse = parse; +exports.serialize = serialize; + +/** + * Module variables. + * @private + */ + +var __toString = Object.prototype.toString +var __hasOwnProperty = Object.prototype.hasOwnProperty + +/** + * RegExp to match cookie-name in RFC 6265 sec 4.1.1 + * This refers out to the obsoleted definition of token in RFC 2616 sec 2.2 + * which has been replaced by the token definition in RFC 7230 appendix B. + * + * cookie-name = token + * token = 1*tchar + * tchar = "!" / "#" / "$" / "%" / "&" / "'" / + * "*" / "+" / "-" / "." / "^" / "_" / + * "`" / "|" / "~" / DIGIT / ALPHA + */ + +var cookieNameRegExp = /^[!#$%&'*+\-.^_`|~0-9A-Za-z]+$/; + +/** + * RegExp to match cookie-value in RFC 6265 sec 4.1.1 + * + * cookie-value = *cookie-octet / ( DQUOTE *cookie-octet DQUOTE ) + * cookie-octet = %x21 / %x23-2B / %x2D-3A / %x3C-5B / %x5D-7E + * ; US-ASCII characters excluding CTLs, + * ; whitespace DQUOTE, comma, semicolon, + * ; and backslash + */ + +var cookieValueRegExp = /^("?)[\u0021\u0023-\u002B\u002D-\u003A\u003C-\u005B\u005D-\u007E]*\1$/; + +/** + * RegExp to match domain-value in RFC 6265 sec 4.1.1 + * + * domain-value = + * ; defined in [RFC1034], Section 3.5, as + * ; enhanced by [RFC1123], Section 2.1 + * =