wreq-js 2.1.1 → 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
@@ -100,8 +100,7 @@ function generateSessionId() {
100
100
  function normalizeSessionOptions(options) {
101
101
  const sessionId = options?.sessionId ?? generateSessionId();
102
102
  const defaults = {
103
- browser: options?.browser ?? DEFAULT_BROWSER,
104
- os: options?.os ?? DEFAULT_OS
103
+ transportMode: resolveEmulationMode(options?.browser, options?.os, options?.emulation)
105
104
  };
106
105
  if (options?.proxy !== void 0) {
107
106
  defaults.proxy = options.proxy;
@@ -825,21 +824,26 @@ function resolveTransportContext(config, sessionDefaults) {
825
824
  throw new RequestError("Transport has been closed");
826
825
  }
827
826
  const hasProxy = config.proxy !== void 0;
828
- if (config.browser !== void 0 || config.os !== void 0 || hasProxy || config.insecure !== void 0) {
829
- 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");
830
829
  }
831
830
  return { transportId: config.transport.id };
832
831
  }
833
832
  if (sessionDefaults?.transportId) {
833
+ if (config.emulation !== void 0) {
834
+ throw new RequestError("Session emulation cannot be changed after creation");
835
+ }
834
836
  if (config.browser !== void 0) {
835
837
  validateBrowserProfile(config.browser);
836
- if (config.browser !== sessionDefaults.browser) {
838
+ const lockedBrowser = sessionDefaults.transportMode.kind === "custom" ? void 0 : sessionDefaults.transportMode.browser;
839
+ if (config.browser !== lockedBrowser) {
837
840
  throw new RequestError("Session browser cannot be changed after creation");
838
841
  }
839
842
  }
840
843
  if (config.os !== void 0) {
841
844
  validateOperatingSystem(config.os);
842
- if (config.os !== sessionDefaults.os) {
845
+ const lockedOs = sessionDefaults.transportMode.kind === "custom" ? void 0 : sessionDefaults.transportMode.os;
846
+ if (config.os !== lockedOs) {
843
847
  throw new RequestError("Session operating system cannot be changed after creation");
844
848
  }
845
849
  }
@@ -856,11 +860,9 @@ function resolveTransportContext(config, sessionDefaults) {
856
860
  }
857
861
  return { transportId: sessionDefaults.transportId };
858
862
  }
859
- const browser = config.browser ?? DEFAULT_BROWSER;
860
- const os = config.os ?? DEFAULT_OS;
861
- validateBrowserProfile(browser);
862
- validateOperatingSystem(os);
863
- const resolved = { browser, os };
863
+ const resolved = {
864
+ mode: resolveEmulationMode(config.browser, config.os, config.emulation)
865
+ };
864
866
  if (config.proxy !== void 0) {
865
867
  resolved.proxy = config.proxy;
866
868
  }
@@ -1105,6 +1107,553 @@ function validatePositiveInteger(value, label) {
1105
1107
  throw new RequestError(`${label} must be greater than 0`);
1106
1108
  }
1107
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
+ }
1108
1657
  async function dispatchRequest(options, requestUrl, signal) {
1109
1658
  if (!signal) {
1110
1659
  const requestId2 = generateRequestId();
@@ -1179,8 +1728,9 @@ async function fetch(input, init) {
1179
1728
  if (transport.transportId) {
1180
1729
  requestOptions.transportId = transport.transportId;
1181
1730
  } else {
1182
- requestOptions.browser = transport.browser ?? DEFAULT_BROWSER;
1183
- requestOptions.os = transport.os ?? DEFAULT_OS;
1731
+ if (transport.mode !== void 0) {
1732
+ applyNativeEmulationMode(requestOptions, transport.mode);
1733
+ }
1184
1734
  if (transport.proxy !== void 0) {
1185
1735
  requestOptions.proxy = transport.proxy;
1186
1736
  }
@@ -1204,10 +1754,7 @@ async function fetch(input, init) {
1204
1754
  return dispatchRequest(requestOptions, url, config.signal ?? null);
1205
1755
  }
1206
1756
  async function createTransport(options) {
1207
- const browser = options?.browser ?? DEFAULT_BROWSER;
1208
- const os = options?.os ?? DEFAULT_OS;
1209
- validateBrowserProfile(browser);
1210
- validateOperatingSystem(os);
1757
+ const mode = resolveEmulationMode(options?.browser, options?.os, options?.emulation);
1211
1758
  if (options?.poolIdleTimeout !== void 0) {
1212
1759
  validatePositiveNumber(options.poolIdleTimeout, "poolIdleTimeout");
1213
1760
  }
@@ -1224,9 +1771,7 @@ async function createTransport(options) {
1224
1771
  validatePositiveNumber(options.readTimeout, "readTimeout");
1225
1772
  }
1226
1773
  try {
1227
- const id = nativeBinding.createTransport({
1228
- browser,
1229
- os,
1774
+ const transportOptions = {
1230
1775
  ...options?.proxy !== void 0 && { proxy: options.proxy },
1231
1776
  ...options?.insecure !== void 0 && { insecure: options.insecure },
1232
1777
  ...options?.poolIdleTimeout !== void 0 && { poolIdleTimeout: options.poolIdleTimeout },
@@ -1234,7 +1779,9 @@ async function createTransport(options) {
1234
1779
  ...options?.poolMaxSize !== void 0 && { poolMaxSize: options.poolMaxSize },
1235
1780
  ...options?.connectTimeout !== void 0 && { connectTimeout: options.connectTimeout },
1236
1781
  ...options?.readTimeout !== void 0 && { readTimeout: options.readTimeout }
1237
- });
1782
+ };
1783
+ applyNativeEmulationMode(transportOptions, mode);
1784
+ const id = nativeBinding.createTransport(transportOptions);
1238
1785
  return new Transport(id);
1239
1786
  } catch (error) {
1240
1787
  throw new RequestError(String(error));
@@ -1242,17 +1789,15 @@ async function createTransport(options) {
1242
1789
  }
1243
1790
  async function createSession(options) {
1244
1791
  const { sessionId, defaults } = normalizeSessionOptions(options);
1245
- validateBrowserProfile(defaults.browser);
1246
- validateOperatingSystem(defaults.os);
1247
1792
  let createdId;
1248
1793
  let transportId;
1249
1794
  try {
1250
- transportId = nativeBinding.createTransport({
1251
- browser: defaults.browser,
1252
- os: defaults.os,
1795
+ const transportOptions = {
1253
1796
  ...defaults.proxy !== void 0 && { proxy: defaults.proxy },
1254
1797
  ...defaults.insecure !== void 0 && { insecure: defaults.insecure }
1255
- });
1798
+ };
1799
+ applyNativeEmulationMode(transportOptions, defaults.transportMode);
1800
+ transportId = nativeBinding.createTransport(transportOptions);
1256
1801
  } catch (error) {
1257
1802
  throw new RequestError(String(error));
1258
1803
  }
@@ -1301,6 +1846,9 @@ async function request(options) {
1301
1846
  if (rest.os !== void 0) {
1302
1847
  init.os = rest.os;
1303
1848
  }
1849
+ if (rest.emulation !== void 0) {
1850
+ init.emulation = rest.emulation;
1851
+ }
1304
1852
  if (rest.proxy !== void 0) {
1305
1853
  init.proxy = rest.proxy;
1306
1854
  }
@@ -1434,6 +1982,9 @@ function normalizeStandaloneWebSocketOptions(options) {
1434
1982
  if (options.os !== void 0) {
1435
1983
  normalized.os = options.os;
1436
1984
  }
1985
+ if (options.emulation !== void 0) {
1986
+ normalized.emulation = options.emulation;
1987
+ }
1437
1988
  if (options.headers !== void 0) {
1438
1989
  normalized.headers = options.headers;
1439
1990
  }
@@ -1465,6 +2016,11 @@ function normalizeSessionWebSocketOptions(options) {
1465
2016
  if (optionsWithOverrides.os !== void 0) {
1466
2017
  throw new RequestError("`os` is not supported in session.websocket(); the session controls OS emulation.");
1467
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
+ }
1468
2024
  if (optionsWithOverrides.proxy !== void 0) {
1469
2025
  throw new RequestError("`proxy` is not supported in session.websocket(); the session transport controls proxying.");
1470
2026
  }
@@ -1630,10 +2186,11 @@ var WebSocket = class _WebSocket {
1630
2186
  typeof protocolsOrOptions === "string" || Array.isArray(protocolsOrOptions) ? protocolsOrOptions : normalizedOptions.protocols
1631
2187
  );
1632
2188
  assertNoManualWebSocketProtocolHeader(normalizedOptions.headers);
1633
- validateBrowserProfile(normalizedOptions.browser);
1634
- const os = normalizedOptions.os ?? DEFAULT_OS;
1635
- validateOperatingSystem(os);
1636
- const browser = normalizedOptions.browser ?? DEFAULT_BROWSER;
2189
+ const emulationMode = resolveEmulationMode(
2190
+ normalizedOptions.browser,
2191
+ normalizedOptions.os,
2192
+ normalizedOptions.emulation
2193
+ );
1637
2194
  const protocols = normalizeWebSocketProtocolList(
1638
2195
  typeof protocolsOrOptions === "string" || Array.isArray(protocolsOrOptions) ? protocolsOrOptions : normalizedOptions.protocols
1639
2196
  );
@@ -1642,17 +2199,19 @@ var WebSocket = class _WebSocket {
1642
2199
  url: normalizeWebSocketUrl(url),
1643
2200
  options: normalizedOptions,
1644
2201
  openDispatchMode: "automatic",
1645
- connect: (callbacks) => nativeBinding.websocketConnect({
1646
- url: normalizeWebSocketUrl(url),
1647
- browser,
1648
- os,
1649
- headers: headersToTuples(normalizedOptions.headers ?? {}),
1650
- ...protocols && protocols.length > 0 && { protocols },
1651
- ...normalizedOptions.proxy !== void 0 && { proxy: normalizedOptions.proxy },
1652
- onMessage: callbacks.onMessage,
1653
- onClose: callbacks.onClose,
1654
- onError: callbacks.onError
1655
- }),
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
+ },
1656
2215
  legacyCallbacks: extractLegacyWebSocketCallbacks(optionsCandidate)
1657
2216
  };
1658
2217
  }
@@ -2046,27 +2605,30 @@ async function websocket(urlOrOptions, options) {
2046
2605
  const normalized = normalizeStandaloneWebSocketArgs(urlOrOptions, options);
2047
2606
  validateWebSocketProtocols(normalized.options.protocols);
2048
2607
  assertNoManualWebSocketProtocolHeader(normalized.options.headers);
2049
- validateBrowserProfile(normalized.options.browser);
2050
- const os = normalized.options.os ?? DEFAULT_OS;
2051
- validateOperatingSystem(os);
2052
- const browser = normalized.options.browser ?? DEFAULT_BROWSER;
2608
+ const emulationMode = resolveEmulationMode(
2609
+ normalized.options.browser,
2610
+ normalized.options.os,
2611
+ normalized.options.emulation
2612
+ );
2053
2613
  const protocols = normalizeWebSocketProtocolList(normalized.options.protocols);
2054
2614
  return WebSocket._connectWithInit({
2055
2615
  _internal: true,
2056
2616
  url: normalized.url,
2057
2617
  options: normalized.options,
2058
2618
  openDispatchMode: "deferred",
2059
- connect: (callbacks) => nativeBinding.websocketConnect({
2060
- url: normalized.url,
2061
- browser,
2062
- os,
2063
- headers: headersToTuples(normalized.options.headers ?? {}),
2064
- ...protocols && protocols.length > 0 && { protocols },
2065
- ...normalized.options.proxy !== void 0 && { proxy: normalized.options.proxy },
2066
- onMessage: callbacks.onMessage,
2067
- onClose: callbacks.onClose,
2068
- onError: callbacks.onError
2069
- }),
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
+ },
2070
2632
  legacyCallbacks: normalized.legacyCallbacks
2071
2633
  });
2072
2634
  }