wreq-js 2.1.0 → 2.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/wreq-js.js CHANGED
@@ -2,6 +2,7 @@
2
2
  import { randomUUID } from "crypto";
3
3
  import { STATUS_CODES } from "http";
4
4
  import { createRequire } from "module";
5
+ import { Readable } from "stream";
5
6
  import { ReadableStream } from "stream/web";
6
7
 
7
8
  // src/types.ts
@@ -86,7 +87,7 @@ var bodyHandleFinalizer = typeof FinalizationRegistry === "function" ? new Final
86
87
  }) : void 0;
87
88
  var DEFAULT_BROWSER = "chrome_142";
88
89
  var DEFAULT_OS = "macos";
89
- var DEFAULT_REQUEST_TIMEOUT_MS = 3e4;
90
+ var DEFAULT_REQUEST_TIMEOUT_MS = 3e5;
90
91
  var SUPPORTED_OSES = ["windows", "macos", "linux", "android", "ios"];
91
92
  var UTF8_DECODER = new TextDecoder("utf-8");
92
93
  var ephemeralIdCounter = 0;
@@ -99,8 +100,7 @@ function generateSessionId() {
99
100
  function normalizeSessionOptions(options) {
100
101
  const sessionId = options?.sessionId ?? generateSessionId();
101
102
  const defaults = {
102
- browser: options?.browser ?? DEFAULT_BROWSER,
103
- os: options?.os ?? DEFAULT_OS
103
+ transportMode: resolveEmulationMode(options?.browser, options?.os, options?.emulation)
104
104
  };
105
105
  if (options?.proxy !== void 0) {
106
106
  defaults.proxy = options.proxy;
@@ -552,6 +552,15 @@ var Response = class _Response {
552
552
  );
553
553
  return response.formData();
554
554
  }
555
+ readable() {
556
+ this.assertBodyAvailable();
557
+ this.bodyUsed = true;
558
+ const stream = this.body;
559
+ if (stream === null) {
560
+ return Readable.from([]);
561
+ }
562
+ return Readable.fromWeb(stream);
563
+ }
555
564
  clone() {
556
565
  if (this.bodyUsed) {
557
566
  throw new TypeError("Cannot clone a Response whose body is already used");
@@ -815,21 +824,26 @@ function resolveTransportContext(config, sessionDefaults) {
815
824
  throw new RequestError("Transport has been closed");
816
825
  }
817
826
  const hasProxy = config.proxy !== void 0;
818
- if (config.browser !== void 0 || config.os !== void 0 || hasProxy || config.insecure !== void 0) {
819
- throw new RequestError("`transport` cannot be combined with browser/os/proxy/insecure options");
827
+ if (config.browser !== void 0 || config.os !== void 0 || config.emulation !== void 0 || hasProxy || config.insecure !== void 0) {
828
+ throw new RequestError("`transport` cannot be combined with browser/os/emulation/proxy/insecure options");
820
829
  }
821
830
  return { transportId: config.transport.id };
822
831
  }
823
832
  if (sessionDefaults?.transportId) {
833
+ if (config.emulation !== void 0) {
834
+ throw new RequestError("Session emulation cannot be changed after creation");
835
+ }
824
836
  if (config.browser !== void 0) {
825
837
  validateBrowserProfile(config.browser);
826
- if (config.browser !== sessionDefaults.browser) {
838
+ const lockedBrowser = sessionDefaults.transportMode.kind === "custom" ? void 0 : sessionDefaults.transportMode.browser;
839
+ if (config.browser !== lockedBrowser) {
827
840
  throw new RequestError("Session browser cannot be changed after creation");
828
841
  }
829
842
  }
830
843
  if (config.os !== void 0) {
831
844
  validateOperatingSystem(config.os);
832
- if (config.os !== sessionDefaults.os) {
845
+ const lockedOs = sessionDefaults.transportMode.kind === "custom" ? void 0 : sessionDefaults.transportMode.os;
846
+ if (config.os !== lockedOs) {
833
847
  throw new RequestError("Session operating system cannot be changed after creation");
834
848
  }
835
849
  }
@@ -846,11 +860,9 @@ function resolveTransportContext(config, sessionDefaults) {
846
860
  }
847
861
  return { transportId: sessionDefaults.transportId };
848
862
  }
849
- const browser = config.browser ?? DEFAULT_BROWSER;
850
- const os = config.os ?? DEFAULT_OS;
851
- validateBrowserProfile(browser);
852
- validateOperatingSystem(os);
853
- const resolved = { browser, os };
863
+ const resolved = {
864
+ mode: resolveEmulationMode(config.browser, config.os, config.emulation)
865
+ };
854
866
  if (config.proxy !== void 0) {
855
867
  resolved.proxy = config.proxy;
856
868
  }
@@ -1095,6 +1107,553 @@ function validatePositiveInteger(value, label) {
1095
1107
  throw new RequestError(`${label} must be greater than 0`);
1096
1108
  }
1097
1109
  }
1110
+ function validateIntegerInRange(value, min, max, label) {
1111
+ validateNonNegativeInteger(value, label);
1112
+ if (value < min || value > max) {
1113
+ throw new RequestError(`${label} must be between ${min} and ${max}`);
1114
+ }
1115
+ }
1116
+ var SUPPORTED_ALPN_PROTOCOLS = /* @__PURE__ */ new Set(["HTTP1", "HTTP2", "HTTP3"]);
1117
+ var SUPPORTED_ALPS_PROTOCOLS = /* @__PURE__ */ new Set(["HTTP1", "HTTP2", "HTTP3"]);
1118
+ var SUPPORTED_CERTIFICATE_COMPRESSION_ALGORITHMS = /* @__PURE__ */ new Set(["zlib", "brotli", "zstd"]);
1119
+ var HTTP2_SETTING_IDS = /* @__PURE__ */ new Set([
1120
+ "HeaderTableSize",
1121
+ "EnablePush",
1122
+ "MaxConcurrentStreams",
1123
+ "InitialWindowSize",
1124
+ "MaxFrameSize",
1125
+ "MaxHeaderListSize",
1126
+ "EnableConnectProtocol",
1127
+ "NoRfc7540Priorities"
1128
+ ]);
1129
+ var HTTP2_PSEUDO_HEADER_IDS = /* @__PURE__ */ new Set(["Method", "Scheme", "Authority", "Path", "Protocol"]);
1130
+ var STANDARD_HTTP2_SETTING_ID_VALUES = /* @__PURE__ */ new Set([1, 2, 3, 4, 5, 6, 8, 9]);
1131
+ var MAX_HTTP2_EXPERIMENTAL_SETTING_ID = 15;
1132
+ var TLS_VERSION_ALIASES = /* @__PURE__ */ new Map([
1133
+ ["1.0", "1.0"],
1134
+ ["1.1", "1.1"],
1135
+ ["1.2", "1.2"],
1136
+ ["1.3", "1.3"],
1137
+ ["tls1.0", "1.0"],
1138
+ ["tls1.1", "1.1"],
1139
+ ["tls1.2", "1.2"],
1140
+ ["tls1.3", "1.3"]
1141
+ ]);
1142
+ function isNonEmpty(value) {
1143
+ for (const _ in value) return true;
1144
+ return false;
1145
+ }
1146
+ function normalizeProtocolList(value, label, allowed) {
1147
+ if (value === void 0) {
1148
+ return void 0;
1149
+ }
1150
+ if (!Array.isArray(value)) {
1151
+ throw new RequestError(`${label} must be an array`);
1152
+ }
1153
+ for (const protocol of value) {
1154
+ if (!allowed.has(protocol)) {
1155
+ throw new RequestError(`${label} values must be one of: HTTP1, HTTP2, HTTP3`);
1156
+ }
1157
+ }
1158
+ return [...value];
1159
+ }
1160
+ function normalizeTlsVersion(value, label) {
1161
+ if (value === void 0) {
1162
+ return void 0;
1163
+ }
1164
+ if (typeof value !== "string") {
1165
+ throw new RequestError(`${label} must be a string`);
1166
+ }
1167
+ const normalized = TLS_VERSION_ALIASES.get(value.trim().toLowerCase());
1168
+ if (!normalized) {
1169
+ throw new RequestError(`${label} must be one of: 1.0, 1.1, 1.2, 1.3`);
1170
+ }
1171
+ return normalized;
1172
+ }
1173
+ function normalizeOrigHeaders(origHeaders) {
1174
+ if (origHeaders === void 0) {
1175
+ return void 0;
1176
+ }
1177
+ if (!Array.isArray(origHeaders)) {
1178
+ throw new RequestError("emulation.origHeaders must be an array of strings");
1179
+ }
1180
+ const normalized = [];
1181
+ const seen = /* @__PURE__ */ new Set();
1182
+ for (const entry of origHeaders) {
1183
+ if (typeof entry !== "string" || entry.trim().length === 0) {
1184
+ throw new RequestError("emulation.origHeaders entries must be non-empty strings");
1185
+ }
1186
+ const trimmed = entry.trim();
1187
+ const duplicateKey = trimmed.toLowerCase();
1188
+ if (seen.has(duplicateKey)) {
1189
+ throw new RequestError(`Duplicate emulation.origHeaders entry: ${trimmed}`);
1190
+ }
1191
+ seen.add(duplicateKey);
1192
+ normalized.push(trimmed);
1193
+ }
1194
+ return normalized.length > 0 ? normalized : void 0;
1195
+ }
1196
+ function normalizeCustomTlsOptions(options) {
1197
+ if (options === void 0) {
1198
+ return void 0;
1199
+ }
1200
+ const normalized = {};
1201
+ const alpnProtocols = normalizeProtocolList(
1202
+ options.alpnProtocols,
1203
+ "emulation.tlsOptions.alpnProtocols",
1204
+ SUPPORTED_ALPN_PROTOCOLS
1205
+ );
1206
+ if (alpnProtocols !== void 0) {
1207
+ normalized.alpnProtocols = alpnProtocols;
1208
+ }
1209
+ const alpsProtocols = normalizeProtocolList(
1210
+ options.alpsProtocols,
1211
+ "emulation.tlsOptions.alpsProtocols",
1212
+ SUPPORTED_ALPS_PROTOCOLS
1213
+ );
1214
+ if (alpsProtocols !== void 0) {
1215
+ normalized.alpsProtocols = alpsProtocols;
1216
+ }
1217
+ const minTlsVersion = normalizeTlsVersion(options.minTlsVersion, "emulation.tlsOptions.minTlsVersion");
1218
+ if (minTlsVersion !== void 0) {
1219
+ normalized.minTlsVersion = minTlsVersion;
1220
+ }
1221
+ const maxTlsVersion = normalizeTlsVersion(options.maxTlsVersion, "emulation.tlsOptions.maxTlsVersion");
1222
+ if (maxTlsVersion !== void 0) {
1223
+ normalized.maxTlsVersion = maxTlsVersion;
1224
+ }
1225
+ if (options.alpsUseNewCodepoint !== void 0) {
1226
+ normalized.alpsUseNewCodepoint = options.alpsUseNewCodepoint;
1227
+ }
1228
+ if (options.sessionTicket !== void 0) {
1229
+ normalized.sessionTicket = options.sessionTicket;
1230
+ }
1231
+ if (options.preSharedKey !== void 0) {
1232
+ normalized.preSharedKey = options.preSharedKey;
1233
+ }
1234
+ if (options.enableEchGrease !== void 0) {
1235
+ normalized.enableEchGrease = options.enableEchGrease;
1236
+ }
1237
+ if (options.permuteExtensions !== void 0) {
1238
+ normalized.permuteExtensions = options.permuteExtensions;
1239
+ }
1240
+ if (options.greaseEnabled !== void 0) {
1241
+ normalized.greaseEnabled = options.greaseEnabled;
1242
+ }
1243
+ if (options.enableOcspStapling !== void 0) {
1244
+ normalized.enableOcspStapling = options.enableOcspStapling;
1245
+ }
1246
+ if (options.enableSignedCertTimestamps !== void 0) {
1247
+ normalized.enableSignedCertTimestamps = options.enableSignedCertTimestamps;
1248
+ }
1249
+ if (options.pskSkipSessionTicket !== void 0) {
1250
+ normalized.pskSkipSessionTicket = options.pskSkipSessionTicket;
1251
+ }
1252
+ if (options.pskDheKe !== void 0) {
1253
+ normalized.pskDheKe = options.pskDheKe;
1254
+ }
1255
+ if (options.renegotiation !== void 0) {
1256
+ normalized.renegotiation = options.renegotiation;
1257
+ }
1258
+ if (options.aesHwOverride !== void 0) {
1259
+ normalized.aesHwOverride = options.aesHwOverride;
1260
+ }
1261
+ if (options.preserveTls13CipherList !== void 0) {
1262
+ normalized.preserveTls13CipherList = options.preserveTls13CipherList;
1263
+ }
1264
+ if (options.randomAesHwOverride !== void 0) {
1265
+ normalized.randomAesHwOverride = options.randomAesHwOverride;
1266
+ }
1267
+ if (options.delegatedCredentials !== void 0) {
1268
+ normalized.delegatedCredentials = options.delegatedCredentials;
1269
+ }
1270
+ if (options.curvesList !== void 0) {
1271
+ normalized.curvesList = options.curvesList;
1272
+ }
1273
+ if (options.cipherList !== void 0) {
1274
+ normalized.cipherList = options.cipherList;
1275
+ }
1276
+ if (options.sigalgsList !== void 0) {
1277
+ normalized.sigalgsList = options.sigalgsList;
1278
+ }
1279
+ if (options.recordSizeLimit !== void 0) {
1280
+ validateIntegerInRange(options.recordSizeLimit, 0, 65535, "emulation.tlsOptions.recordSizeLimit");
1281
+ normalized.recordSizeLimit = options.recordSizeLimit;
1282
+ }
1283
+ if (options.keySharesLimit !== void 0) {
1284
+ validateIntegerInRange(options.keySharesLimit, 0, 255, "emulation.tlsOptions.keySharesLimit");
1285
+ normalized.keySharesLimit = options.keySharesLimit;
1286
+ }
1287
+ if (options.certificateCompressionAlgorithms !== void 0) {
1288
+ if (!Array.isArray(options.certificateCompressionAlgorithms)) {
1289
+ throw new RequestError("emulation.tlsOptions.certificateCompressionAlgorithms must be an array");
1290
+ }
1291
+ const algorithms = [];
1292
+ const seen = /* @__PURE__ */ new Set();
1293
+ for (const algorithm of options.certificateCompressionAlgorithms) {
1294
+ if (!SUPPORTED_CERTIFICATE_COMPRESSION_ALGORITHMS.has(algorithm)) {
1295
+ throw new RequestError(
1296
+ "emulation.tlsOptions.certificateCompressionAlgorithms values must be one of: zlib, brotli, zstd"
1297
+ );
1298
+ }
1299
+ if (seen.has(algorithm)) {
1300
+ throw new RequestError(`Duplicate emulation.tlsOptions.certificateCompressionAlgorithms entry: ${algorithm}`);
1301
+ }
1302
+ seen.add(algorithm);
1303
+ algorithms.push(algorithm);
1304
+ }
1305
+ normalized.certificateCompressionAlgorithms = algorithms;
1306
+ }
1307
+ if (options.extensionPermutation !== void 0) {
1308
+ if (!Array.isArray(options.extensionPermutation)) {
1309
+ throw new RequestError("emulation.tlsOptions.extensionPermutation must be an array");
1310
+ }
1311
+ const permutation = [];
1312
+ const seen = /* @__PURE__ */ new Set();
1313
+ for (const extensionId of options.extensionPermutation) {
1314
+ validateIntegerInRange(extensionId, 0, 65535, "emulation.tlsOptions.extensionPermutation");
1315
+ if (seen.has(extensionId)) {
1316
+ throw new RequestError(`Duplicate emulation.tlsOptions.extensionPermutation entry: ${extensionId}`);
1317
+ }
1318
+ seen.add(extensionId);
1319
+ permutation.push(extensionId);
1320
+ }
1321
+ normalized.extensionPermutation = permutation;
1322
+ }
1323
+ return isNonEmpty(normalized) ? normalized : void 0;
1324
+ }
1325
+ function normalizeCustomHttp1Options(options) {
1326
+ if (options === void 0) {
1327
+ return void 0;
1328
+ }
1329
+ const normalized = {};
1330
+ if (options.http09Responses !== void 0) {
1331
+ normalized.http09Responses = options.http09Responses;
1332
+ }
1333
+ if (options.writev !== void 0) {
1334
+ normalized.writev = options.writev;
1335
+ }
1336
+ if (options.ignoreInvalidHeadersInResponses !== void 0) {
1337
+ normalized.ignoreInvalidHeadersInResponses = options.ignoreInvalidHeadersInResponses;
1338
+ }
1339
+ if (options.allowSpacesAfterHeaderNameInResponses !== void 0) {
1340
+ normalized.allowSpacesAfterHeaderNameInResponses = options.allowSpacesAfterHeaderNameInResponses;
1341
+ }
1342
+ if (options.allowObsoleteMultilineHeadersInResponses !== void 0) {
1343
+ normalized.allowObsoleteMultilineHeadersInResponses = options.allowObsoleteMultilineHeadersInResponses;
1344
+ }
1345
+ if (options.maxHeaders !== void 0) {
1346
+ validateNonNegativeInteger(options.maxHeaders, "emulation.http1Options.maxHeaders");
1347
+ normalized.maxHeaders = options.maxHeaders;
1348
+ }
1349
+ if (options.readBufExactSize !== void 0) {
1350
+ validateNonNegativeInteger(options.readBufExactSize, "emulation.http1Options.readBufExactSize");
1351
+ normalized.readBufExactSize = options.readBufExactSize;
1352
+ }
1353
+ if (options.maxBufSize !== void 0) {
1354
+ validateNonNegativeInteger(options.maxBufSize, "emulation.http1Options.maxBufSize");
1355
+ if (options.maxBufSize < 8192) {
1356
+ throw new RequestError("emulation.http1Options.maxBufSize must be greater than or equal to 8192");
1357
+ }
1358
+ normalized.maxBufSize = options.maxBufSize;
1359
+ }
1360
+ if (normalized.readBufExactSize !== void 0 && normalized.maxBufSize !== void 0) {
1361
+ throw new RequestError("emulation.http1Options.readBufExactSize and maxBufSize cannot both be set");
1362
+ }
1363
+ return isNonEmpty(normalized) ? normalized : void 0;
1364
+ }
1365
+ function normalizeHttp2StreamDependency(dependency, label) {
1366
+ if (!isPlainObject(dependency)) {
1367
+ throw new RequestError(`${label} must be an object`);
1368
+ }
1369
+ validateIntegerInRange(dependency.dependencyId, 0, 2147483647, `${label}.dependencyId`);
1370
+ validateIntegerInRange(dependency.weight, 0, 255, `${label}.weight`);
1371
+ const normalized = {
1372
+ dependencyId: dependency.dependencyId,
1373
+ weight: dependency.weight
1374
+ };
1375
+ if (dependency.exclusive !== void 0) {
1376
+ normalized.exclusive = dependency.exclusive;
1377
+ }
1378
+ return normalized;
1379
+ }
1380
+ function normalizeCustomHttp2Options(options) {
1381
+ if (options === void 0) {
1382
+ return void 0;
1383
+ }
1384
+ const normalized = {};
1385
+ if (options.adaptiveWindow !== void 0) {
1386
+ normalized.adaptiveWindow = options.adaptiveWindow;
1387
+ }
1388
+ if (options.keepAliveWhileIdle !== void 0) {
1389
+ normalized.keepAliveWhileIdle = options.keepAliveWhileIdle;
1390
+ }
1391
+ if (options.enablePush !== void 0) {
1392
+ normalized.enablePush = options.enablePush;
1393
+ }
1394
+ if (options.enableConnectProtocol !== void 0) {
1395
+ normalized.enableConnectProtocol = options.enableConnectProtocol;
1396
+ }
1397
+ if (options.noRfc7540Priorities !== void 0) {
1398
+ normalized.noRfc7540Priorities = options.noRfc7540Priorities;
1399
+ }
1400
+ if (options.initialStreamId !== void 0) {
1401
+ validateNonNegativeInteger(options.initialStreamId, "emulation.http2Options.initialStreamId");
1402
+ normalized.initialStreamId = options.initialStreamId;
1403
+ }
1404
+ if (options.initialConnectionWindowSize !== void 0) {
1405
+ validateNonNegativeInteger(
1406
+ options.initialConnectionWindowSize,
1407
+ "emulation.http2Options.initialConnectionWindowSize"
1408
+ );
1409
+ normalized.initialConnectionWindowSize = options.initialConnectionWindowSize;
1410
+ }
1411
+ if (options.initialWindowSize !== void 0) {
1412
+ validateNonNegativeInteger(options.initialWindowSize, "emulation.http2Options.initialWindowSize");
1413
+ normalized.initialWindowSize = options.initialWindowSize;
1414
+ }
1415
+ if (options.initialMaxSendStreams !== void 0) {
1416
+ validateNonNegativeInteger(options.initialMaxSendStreams, "emulation.http2Options.initialMaxSendStreams");
1417
+ normalized.initialMaxSendStreams = options.initialMaxSendStreams;
1418
+ }
1419
+ if (options.maxFrameSize !== void 0) {
1420
+ validateNonNegativeInteger(options.maxFrameSize, "emulation.http2Options.maxFrameSize");
1421
+ normalized.maxFrameSize = options.maxFrameSize;
1422
+ }
1423
+ if (options.keepAliveInterval !== void 0) {
1424
+ validateNonNegativeInteger(options.keepAliveInterval, "emulation.http2Options.keepAliveInterval");
1425
+ normalized.keepAliveInterval = options.keepAliveInterval;
1426
+ }
1427
+ if (options.keepAliveTimeout !== void 0) {
1428
+ validateNonNegativeInteger(options.keepAliveTimeout, "emulation.http2Options.keepAliveTimeout");
1429
+ normalized.keepAliveTimeout = options.keepAliveTimeout;
1430
+ }
1431
+ if (options.maxConcurrentResetStreams !== void 0) {
1432
+ validateNonNegativeInteger(options.maxConcurrentResetStreams, "emulation.http2Options.maxConcurrentResetStreams");
1433
+ normalized.maxConcurrentResetStreams = options.maxConcurrentResetStreams;
1434
+ }
1435
+ if (options.maxSendBufferSize !== void 0) {
1436
+ validateNonNegativeInteger(options.maxSendBufferSize, "emulation.http2Options.maxSendBufferSize");
1437
+ normalized.maxSendBufferSize = options.maxSendBufferSize;
1438
+ }
1439
+ if (options.maxConcurrentStreams !== void 0) {
1440
+ validateNonNegativeInteger(options.maxConcurrentStreams, "emulation.http2Options.maxConcurrentStreams");
1441
+ normalized.maxConcurrentStreams = options.maxConcurrentStreams;
1442
+ }
1443
+ if (options.maxHeaderListSize !== void 0) {
1444
+ validateNonNegativeInteger(options.maxHeaderListSize, "emulation.http2Options.maxHeaderListSize");
1445
+ normalized.maxHeaderListSize = options.maxHeaderListSize;
1446
+ }
1447
+ if (options.maxPendingAcceptResetStreams !== void 0) {
1448
+ validateNonNegativeInteger(
1449
+ options.maxPendingAcceptResetStreams,
1450
+ "emulation.http2Options.maxPendingAcceptResetStreams"
1451
+ );
1452
+ normalized.maxPendingAcceptResetStreams = options.maxPendingAcceptResetStreams;
1453
+ }
1454
+ if (options.headerTableSize !== void 0) {
1455
+ validateNonNegativeInteger(options.headerTableSize, "emulation.http2Options.headerTableSize");
1456
+ normalized.headerTableSize = options.headerTableSize;
1457
+ }
1458
+ if (options.settingsOrder !== void 0) {
1459
+ if (!Array.isArray(options.settingsOrder)) {
1460
+ throw new RequestError("emulation.http2Options.settingsOrder must be an array");
1461
+ }
1462
+ const settingsOrder = [];
1463
+ const seen = /* @__PURE__ */ new Set();
1464
+ for (const settingId of options.settingsOrder) {
1465
+ if (!HTTP2_SETTING_IDS.has(settingId)) {
1466
+ throw new RequestError("emulation.http2Options.settingsOrder contains an unsupported setting id");
1467
+ }
1468
+ if (seen.has(settingId)) {
1469
+ throw new RequestError(`Duplicate emulation.http2Options.settingsOrder entry: ${settingId}`);
1470
+ }
1471
+ seen.add(settingId);
1472
+ settingsOrder.push(settingId);
1473
+ }
1474
+ normalized.settingsOrder = settingsOrder;
1475
+ }
1476
+ if (options.headersPseudoOrder !== void 0) {
1477
+ if (!Array.isArray(options.headersPseudoOrder)) {
1478
+ throw new RequestError("emulation.http2Options.headersPseudoOrder must be an array");
1479
+ }
1480
+ const headersPseudoOrder = [];
1481
+ const seenPseudo = /* @__PURE__ */ new Set();
1482
+ for (const pseudoId of options.headersPseudoOrder) {
1483
+ if (!HTTP2_PSEUDO_HEADER_IDS.has(pseudoId)) {
1484
+ throw new RequestError("emulation.http2Options.headersPseudoOrder contains an unsupported pseudo-header id");
1485
+ }
1486
+ if (seenPseudo.has(pseudoId)) {
1487
+ throw new RequestError(`Duplicate emulation.http2Options.headersPseudoOrder entry: ${pseudoId}`);
1488
+ }
1489
+ seenPseudo.add(pseudoId);
1490
+ headersPseudoOrder.push(pseudoId);
1491
+ }
1492
+ normalized.headersPseudoOrder = headersPseudoOrder;
1493
+ }
1494
+ if (options.headersStreamDependency !== void 0) {
1495
+ normalized.headersStreamDependency = normalizeHttp2StreamDependency(
1496
+ options.headersStreamDependency,
1497
+ "emulation.http2Options.headersStreamDependency"
1498
+ );
1499
+ }
1500
+ if (options.priorities !== void 0) {
1501
+ if (!Array.isArray(options.priorities)) {
1502
+ throw new RequestError("emulation.http2Options.priorities must be an array");
1503
+ }
1504
+ const priorities = [];
1505
+ const seenStreamIds = /* @__PURE__ */ new Set();
1506
+ for (const [index, priority] of options.priorities.entries()) {
1507
+ if (!isPlainObject(priority)) {
1508
+ throw new RequestError(`emulation.http2Options.priorities[${index}] must be an object`);
1509
+ }
1510
+ validatePositiveInteger(priority.streamId, `emulation.http2Options.priorities[${index}].streamId`);
1511
+ if (seenStreamIds.has(priority.streamId)) {
1512
+ throw new RequestError(`Duplicate emulation.http2Options.priorities streamId: ${priority.streamId}`);
1513
+ }
1514
+ seenStreamIds.add(priority.streamId);
1515
+ priorities.push({
1516
+ streamId: priority.streamId,
1517
+ dependency: normalizeHttp2StreamDependency(
1518
+ priority.dependency,
1519
+ `emulation.http2Options.priorities[${index}].dependency`
1520
+ )
1521
+ });
1522
+ }
1523
+ normalized.priorities = priorities;
1524
+ }
1525
+ if (options.experimentalSettings !== void 0) {
1526
+ if (!Array.isArray(options.experimentalSettings)) {
1527
+ throw new RequestError("emulation.http2Options.experimentalSettings must be an array");
1528
+ }
1529
+ const experimentalSettings = [];
1530
+ const seenIds = /* @__PURE__ */ new Set();
1531
+ for (const [index, setting] of options.experimentalSettings.entries()) {
1532
+ if (!isPlainObject(setting)) {
1533
+ throw new RequestError(`emulation.http2Options.experimentalSettings[${index}] must be an object`);
1534
+ }
1535
+ validateIntegerInRange(
1536
+ setting.id,
1537
+ 1,
1538
+ MAX_HTTP2_EXPERIMENTAL_SETTING_ID,
1539
+ `emulation.http2Options.experimentalSettings[${index}].id`
1540
+ );
1541
+ if (STANDARD_HTTP2_SETTING_ID_VALUES.has(setting.id)) {
1542
+ throw new RequestError(
1543
+ `emulation.http2Options.experimentalSettings[${index}].id must not be a standard HTTP/2 setting id`
1544
+ );
1545
+ }
1546
+ if (seenIds.has(setting.id)) {
1547
+ throw new RequestError(`Duplicate emulation.http2Options.experimentalSettings id: ${setting.id}`);
1548
+ }
1549
+ seenIds.add(setting.id);
1550
+ validateIntegerInRange(
1551
+ setting.value,
1552
+ 0,
1553
+ 4294967295,
1554
+ `emulation.http2Options.experimentalSettings[${index}].value`
1555
+ );
1556
+ experimentalSettings.push({
1557
+ id: setting.id,
1558
+ value: setting.value
1559
+ });
1560
+ }
1561
+ normalized.experimentalSettings = experimentalSettings;
1562
+ }
1563
+ return isNonEmpty(normalized) ? normalized : void 0;
1564
+ }
1565
+ function normalizeCustomEmulationOptions(emulation, allowEmpty) {
1566
+ if (emulation === void 0) {
1567
+ return void 0;
1568
+ }
1569
+ if (!isPlainObject(emulation)) {
1570
+ throw new RequestError("emulation must be an object");
1571
+ }
1572
+ const source = emulation;
1573
+ const normalized = {};
1574
+ const tlsOptions = normalizeCustomTlsOptions(source.tlsOptions);
1575
+ if (tlsOptions !== void 0) {
1576
+ normalized.tlsOptions = tlsOptions;
1577
+ }
1578
+ const http1Options = normalizeCustomHttp1Options(source.http1Options);
1579
+ if (http1Options !== void 0) {
1580
+ normalized.http1Options = http1Options;
1581
+ }
1582
+ const http2Options = normalizeCustomHttp2Options(source.http2Options);
1583
+ if (http2Options !== void 0) {
1584
+ normalized.http2Options = http2Options;
1585
+ }
1586
+ if (source.headers !== void 0) {
1587
+ const headers = headersToTuples(source.headers);
1588
+ if (headers.length > 0) {
1589
+ normalized.headers = headers;
1590
+ }
1591
+ }
1592
+ const origHeaders = normalizeOrigHeaders(source.origHeaders);
1593
+ if (origHeaders !== void 0) {
1594
+ normalized.origHeaders = origHeaders;
1595
+ }
1596
+ if (!allowEmpty && !isNonEmpty(normalized)) {
1597
+ throw new RequestError(
1598
+ "Standalone custom emulation requires at least one of tlsOptions, http1Options, http2Options, headers, or origHeaders"
1599
+ );
1600
+ }
1601
+ return isNonEmpty(normalized) ? normalized : void 0;
1602
+ }
1603
+ function serializeCustomEmulationOptions(emulation, allowEmpty) {
1604
+ const normalized = normalizeCustomEmulationOptions(emulation, allowEmpty);
1605
+ return normalized ? JSON.stringify(normalized) : void 0;
1606
+ }
1607
+ function resolveEmulationMode(browser, os, emulation) {
1608
+ if (browser !== void 0) {
1609
+ validateBrowserProfile(browser);
1610
+ if (os !== void 0) {
1611
+ validateOperatingSystem(os);
1612
+ }
1613
+ const emulationJson = serializeCustomEmulationOptions(emulation, true);
1614
+ return {
1615
+ kind: "preset",
1616
+ browser,
1617
+ os: os ?? DEFAULT_OS,
1618
+ ...emulationJson !== void 0 && { emulationJson }
1619
+ };
1620
+ }
1621
+ if (os !== void 0) {
1622
+ validateOperatingSystem(os);
1623
+ const emulationJson = serializeCustomEmulationOptions(emulation, true);
1624
+ return {
1625
+ kind: "preset",
1626
+ browser: DEFAULT_BROWSER,
1627
+ os,
1628
+ ...emulationJson !== void 0 && { emulationJson }
1629
+ };
1630
+ }
1631
+ if (emulation !== void 0) {
1632
+ const emulationJson = serializeCustomEmulationOptions(emulation, false);
1633
+ if (emulationJson === void 0) {
1634
+ throw new RequestError(
1635
+ "Standalone custom emulation requires at least one of tlsOptions, http1Options, http2Options, headers, or origHeaders"
1636
+ );
1637
+ }
1638
+ return { kind: "custom", emulationJson };
1639
+ }
1640
+ return {
1641
+ kind: "preset",
1642
+ browser: DEFAULT_BROWSER,
1643
+ os: DEFAULT_OS
1644
+ };
1645
+ }
1646
+ function applyNativeEmulationMode(target, mode) {
1647
+ if (mode.kind === "custom") {
1648
+ target.emulationJson = mode.emulationJson;
1649
+ return;
1650
+ }
1651
+ target.browser = mode.browser;
1652
+ target.os = mode.os;
1653
+ if (mode.emulationJson !== void 0) {
1654
+ target.emulationJson = mode.emulationJson;
1655
+ }
1656
+ }
1098
1657
  async function dispatchRequest(options, requestUrl, signal) {
1099
1658
  if (!signal) {
1100
1659
  const requestId2 = generateRequestId();
@@ -1169,8 +1728,9 @@ async function fetch(input, init) {
1169
1728
  if (transport.transportId) {
1170
1729
  requestOptions.transportId = transport.transportId;
1171
1730
  } else {
1172
- requestOptions.browser = transport.browser ?? DEFAULT_BROWSER;
1173
- requestOptions.os = transport.os ?? DEFAULT_OS;
1731
+ if (transport.mode !== void 0) {
1732
+ applyNativeEmulationMode(requestOptions, transport.mode);
1733
+ }
1174
1734
  if (transport.proxy !== void 0) {
1175
1735
  requestOptions.proxy = transport.proxy;
1176
1736
  }
@@ -1194,10 +1754,7 @@ async function fetch(input, init) {
1194
1754
  return dispatchRequest(requestOptions, url, config.signal ?? null);
1195
1755
  }
1196
1756
  async function createTransport(options) {
1197
- const browser = options?.browser ?? DEFAULT_BROWSER;
1198
- const os = options?.os ?? DEFAULT_OS;
1199
- validateBrowserProfile(browser);
1200
- validateOperatingSystem(os);
1757
+ const mode = resolveEmulationMode(options?.browser, options?.os, options?.emulation);
1201
1758
  if (options?.poolIdleTimeout !== void 0) {
1202
1759
  validatePositiveNumber(options.poolIdleTimeout, "poolIdleTimeout");
1203
1760
  }
@@ -1214,9 +1771,7 @@ async function createTransport(options) {
1214
1771
  validatePositiveNumber(options.readTimeout, "readTimeout");
1215
1772
  }
1216
1773
  try {
1217
- const id = nativeBinding.createTransport({
1218
- browser,
1219
- os,
1774
+ const transportOptions = {
1220
1775
  ...options?.proxy !== void 0 && { proxy: options.proxy },
1221
1776
  ...options?.insecure !== void 0 && { insecure: options.insecure },
1222
1777
  ...options?.poolIdleTimeout !== void 0 && { poolIdleTimeout: options.poolIdleTimeout },
@@ -1224,7 +1779,9 @@ async function createTransport(options) {
1224
1779
  ...options?.poolMaxSize !== void 0 && { poolMaxSize: options.poolMaxSize },
1225
1780
  ...options?.connectTimeout !== void 0 && { connectTimeout: options.connectTimeout },
1226
1781
  ...options?.readTimeout !== void 0 && { readTimeout: options.readTimeout }
1227
- });
1782
+ };
1783
+ applyNativeEmulationMode(transportOptions, mode);
1784
+ const id = nativeBinding.createTransport(transportOptions);
1228
1785
  return new Transport(id);
1229
1786
  } catch (error) {
1230
1787
  throw new RequestError(String(error));
@@ -1232,17 +1789,15 @@ async function createTransport(options) {
1232
1789
  }
1233
1790
  async function createSession(options) {
1234
1791
  const { sessionId, defaults } = normalizeSessionOptions(options);
1235
- validateBrowserProfile(defaults.browser);
1236
- validateOperatingSystem(defaults.os);
1237
1792
  let createdId;
1238
1793
  let transportId;
1239
1794
  try {
1240
- transportId = nativeBinding.createTransport({
1241
- browser: defaults.browser,
1242
- os: defaults.os,
1795
+ const transportOptions = {
1243
1796
  ...defaults.proxy !== void 0 && { proxy: defaults.proxy },
1244
1797
  ...defaults.insecure !== void 0 && { insecure: defaults.insecure }
1245
- });
1798
+ };
1799
+ applyNativeEmulationMode(transportOptions, defaults.transportMode);
1800
+ transportId = nativeBinding.createTransport(transportOptions);
1246
1801
  } catch (error) {
1247
1802
  throw new RequestError(String(error));
1248
1803
  }
@@ -1291,6 +1846,9 @@ async function request(options) {
1291
1846
  if (rest.os !== void 0) {
1292
1847
  init.os = rest.os;
1293
1848
  }
1849
+ if (rest.emulation !== void 0) {
1850
+ init.emulation = rest.emulation;
1851
+ }
1294
1852
  if (rest.proxy !== void 0) {
1295
1853
  init.proxy = rest.proxy;
1296
1854
  }
@@ -1424,6 +1982,9 @@ function normalizeStandaloneWebSocketOptions(options) {
1424
1982
  if (options.os !== void 0) {
1425
1983
  normalized.os = options.os;
1426
1984
  }
1985
+ if (options.emulation !== void 0) {
1986
+ normalized.emulation = options.emulation;
1987
+ }
1427
1988
  if (options.headers !== void 0) {
1428
1989
  normalized.headers = options.headers;
1429
1990
  }
@@ -1455,6 +2016,11 @@ function normalizeSessionWebSocketOptions(options) {
1455
2016
  if (optionsWithOverrides.os !== void 0) {
1456
2017
  throw new RequestError("`os` is not supported in session.websocket(); the session controls OS emulation.");
1457
2018
  }
2019
+ if (optionsWithOverrides.emulation !== void 0) {
2020
+ throw new RequestError(
2021
+ "`emulation` is not supported in session.websocket(); the session transport controls emulation."
2022
+ );
2023
+ }
1458
2024
  if (optionsWithOverrides.proxy !== void 0) {
1459
2025
  throw new RequestError("`proxy` is not supported in session.websocket(); the session transport controls proxying.");
1460
2026
  }
@@ -1620,10 +2186,11 @@ var WebSocket = class _WebSocket {
1620
2186
  typeof protocolsOrOptions === "string" || Array.isArray(protocolsOrOptions) ? protocolsOrOptions : normalizedOptions.protocols
1621
2187
  );
1622
2188
  assertNoManualWebSocketProtocolHeader(normalizedOptions.headers);
1623
- validateBrowserProfile(normalizedOptions.browser);
1624
- const os = normalizedOptions.os ?? DEFAULT_OS;
1625
- validateOperatingSystem(os);
1626
- const browser = normalizedOptions.browser ?? DEFAULT_BROWSER;
2189
+ const emulationMode = resolveEmulationMode(
2190
+ normalizedOptions.browser,
2191
+ normalizedOptions.os,
2192
+ normalizedOptions.emulation
2193
+ );
1627
2194
  const protocols = normalizeWebSocketProtocolList(
1628
2195
  typeof protocolsOrOptions === "string" || Array.isArray(protocolsOrOptions) ? protocolsOrOptions : normalizedOptions.protocols
1629
2196
  );
@@ -1632,17 +2199,19 @@ var WebSocket = class _WebSocket {
1632
2199
  url: normalizeWebSocketUrl(url),
1633
2200
  options: normalizedOptions,
1634
2201
  openDispatchMode: "automatic",
1635
- connect: (callbacks) => nativeBinding.websocketConnect({
1636
- url: normalizeWebSocketUrl(url),
1637
- browser,
1638
- os,
1639
- headers: headersToTuples(normalizedOptions.headers ?? {}),
1640
- ...protocols && protocols.length > 0 && { protocols },
1641
- ...normalizedOptions.proxy !== void 0 && { proxy: normalizedOptions.proxy },
1642
- onMessage: callbacks.onMessage,
1643
- onClose: callbacks.onClose,
1644
- onError: callbacks.onError
1645
- }),
2202
+ connect: (callbacks) => {
2203
+ const nativeOptions = {
2204
+ url: normalizeWebSocketUrl(url),
2205
+ headers: headersToTuples(normalizedOptions.headers ?? {}),
2206
+ ...protocols && protocols.length > 0 && { protocols },
2207
+ ...normalizedOptions.proxy !== void 0 && { proxy: normalizedOptions.proxy },
2208
+ onMessage: callbacks.onMessage,
2209
+ onClose: callbacks.onClose,
2210
+ onError: callbacks.onError
2211
+ };
2212
+ applyNativeEmulationMode(nativeOptions, emulationMode);
2213
+ return nativeBinding.websocketConnect(nativeOptions);
2214
+ },
1646
2215
  legacyCallbacks: extractLegacyWebSocketCallbacks(optionsCandidate)
1647
2216
  };
1648
2217
  }
@@ -2036,27 +2605,30 @@ async function websocket(urlOrOptions, options) {
2036
2605
  const normalized = normalizeStandaloneWebSocketArgs(urlOrOptions, options);
2037
2606
  validateWebSocketProtocols(normalized.options.protocols);
2038
2607
  assertNoManualWebSocketProtocolHeader(normalized.options.headers);
2039
- validateBrowserProfile(normalized.options.browser);
2040
- const os = normalized.options.os ?? DEFAULT_OS;
2041
- validateOperatingSystem(os);
2042
- const browser = normalized.options.browser ?? DEFAULT_BROWSER;
2608
+ const emulationMode = resolveEmulationMode(
2609
+ normalized.options.browser,
2610
+ normalized.options.os,
2611
+ normalized.options.emulation
2612
+ );
2043
2613
  const protocols = normalizeWebSocketProtocolList(normalized.options.protocols);
2044
2614
  return WebSocket._connectWithInit({
2045
2615
  _internal: true,
2046
2616
  url: normalized.url,
2047
2617
  options: normalized.options,
2048
2618
  openDispatchMode: "deferred",
2049
- connect: (callbacks) => nativeBinding.websocketConnect({
2050
- url: normalized.url,
2051
- browser,
2052
- os,
2053
- headers: headersToTuples(normalized.options.headers ?? {}),
2054
- ...protocols && protocols.length > 0 && { protocols },
2055
- ...normalized.options.proxy !== void 0 && { proxy: normalized.options.proxy },
2056
- onMessage: callbacks.onMessage,
2057
- onClose: callbacks.onClose,
2058
- onError: callbacks.onError
2059
- }),
2619
+ connect: (callbacks) => {
2620
+ const nativeOptions = {
2621
+ url: normalized.url,
2622
+ headers: headersToTuples(normalized.options.headers ?? {}),
2623
+ ...protocols && protocols.length > 0 && { protocols },
2624
+ ...normalized.options.proxy !== void 0 && { proxy: normalized.options.proxy },
2625
+ onMessage: callbacks.onMessage,
2626
+ onClose: callbacks.onClose,
2627
+ onError: callbacks.onError
2628
+ };
2629
+ applyNativeEmulationMode(nativeOptions, emulationMode);
2630
+ return nativeBinding.websocketConnect(nativeOptions);
2631
+ },
2060
2632
  legacyCallbacks: normalized.legacyCallbacks
2061
2633
  });
2062
2634
  }