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.cjs CHANGED
@@ -141,8 +141,7 @@ function generateSessionId() {
141
141
  function normalizeSessionOptions(options) {
142
142
  const sessionId = options?.sessionId ?? generateSessionId();
143
143
  const defaults = {
144
- browser: options?.browser ?? DEFAULT_BROWSER,
145
- os: options?.os ?? DEFAULT_OS
144
+ transportMode: resolveEmulationMode(options?.browser, options?.os, options?.emulation)
146
145
  };
147
146
  if (options?.proxy !== void 0) {
148
147
  defaults.proxy = options.proxy;
@@ -866,21 +865,26 @@ function resolveTransportContext(config, sessionDefaults) {
866
865
  throw new RequestError("Transport has been closed");
867
866
  }
868
867
  const hasProxy = config.proxy !== void 0;
869
- if (config.browser !== void 0 || config.os !== void 0 || hasProxy || config.insecure !== void 0) {
870
- throw new RequestError("`transport` cannot be combined with browser/os/proxy/insecure options");
868
+ if (config.browser !== void 0 || config.os !== void 0 || config.emulation !== void 0 || hasProxy || config.insecure !== void 0) {
869
+ throw new RequestError("`transport` cannot be combined with browser/os/emulation/proxy/insecure options");
871
870
  }
872
871
  return { transportId: config.transport.id };
873
872
  }
874
873
  if (sessionDefaults?.transportId) {
874
+ if (config.emulation !== void 0) {
875
+ throw new RequestError("Session emulation cannot be changed after creation");
876
+ }
875
877
  if (config.browser !== void 0) {
876
878
  validateBrowserProfile(config.browser);
877
- if (config.browser !== sessionDefaults.browser) {
879
+ const lockedBrowser = sessionDefaults.transportMode.kind === "custom" ? void 0 : sessionDefaults.transportMode.browser;
880
+ if (config.browser !== lockedBrowser) {
878
881
  throw new RequestError("Session browser cannot be changed after creation");
879
882
  }
880
883
  }
881
884
  if (config.os !== void 0) {
882
885
  validateOperatingSystem(config.os);
883
- if (config.os !== sessionDefaults.os) {
886
+ const lockedOs = sessionDefaults.transportMode.kind === "custom" ? void 0 : sessionDefaults.transportMode.os;
887
+ if (config.os !== lockedOs) {
884
888
  throw new RequestError("Session operating system cannot be changed after creation");
885
889
  }
886
890
  }
@@ -897,11 +901,9 @@ function resolveTransportContext(config, sessionDefaults) {
897
901
  }
898
902
  return { transportId: sessionDefaults.transportId };
899
903
  }
900
- const browser = config.browser ?? DEFAULT_BROWSER;
901
- const os = config.os ?? DEFAULT_OS;
902
- validateBrowserProfile(browser);
903
- validateOperatingSystem(os);
904
- const resolved = { browser, os };
904
+ const resolved = {
905
+ mode: resolveEmulationMode(config.browser, config.os, config.emulation)
906
+ };
905
907
  if (config.proxy !== void 0) {
906
908
  resolved.proxy = config.proxy;
907
909
  }
@@ -1146,6 +1148,553 @@ function validatePositiveInteger(value, label) {
1146
1148
  throw new RequestError(`${label} must be greater than 0`);
1147
1149
  }
1148
1150
  }
1151
+ function validateIntegerInRange(value, min, max, label) {
1152
+ validateNonNegativeInteger(value, label);
1153
+ if (value < min || value > max) {
1154
+ throw new RequestError(`${label} must be between ${min} and ${max}`);
1155
+ }
1156
+ }
1157
+ var SUPPORTED_ALPN_PROTOCOLS = /* @__PURE__ */ new Set(["HTTP1", "HTTP2", "HTTP3"]);
1158
+ var SUPPORTED_ALPS_PROTOCOLS = /* @__PURE__ */ new Set(["HTTP1", "HTTP2", "HTTP3"]);
1159
+ var SUPPORTED_CERTIFICATE_COMPRESSION_ALGORITHMS = /* @__PURE__ */ new Set(["zlib", "brotli", "zstd"]);
1160
+ var HTTP2_SETTING_IDS = /* @__PURE__ */ new Set([
1161
+ "HeaderTableSize",
1162
+ "EnablePush",
1163
+ "MaxConcurrentStreams",
1164
+ "InitialWindowSize",
1165
+ "MaxFrameSize",
1166
+ "MaxHeaderListSize",
1167
+ "EnableConnectProtocol",
1168
+ "NoRfc7540Priorities"
1169
+ ]);
1170
+ var HTTP2_PSEUDO_HEADER_IDS = /* @__PURE__ */ new Set(["Method", "Scheme", "Authority", "Path", "Protocol"]);
1171
+ var STANDARD_HTTP2_SETTING_ID_VALUES = /* @__PURE__ */ new Set([1, 2, 3, 4, 5, 6, 8, 9]);
1172
+ var MAX_HTTP2_EXPERIMENTAL_SETTING_ID = 15;
1173
+ var TLS_VERSION_ALIASES = /* @__PURE__ */ new Map([
1174
+ ["1.0", "1.0"],
1175
+ ["1.1", "1.1"],
1176
+ ["1.2", "1.2"],
1177
+ ["1.3", "1.3"],
1178
+ ["tls1.0", "1.0"],
1179
+ ["tls1.1", "1.1"],
1180
+ ["tls1.2", "1.2"],
1181
+ ["tls1.3", "1.3"]
1182
+ ]);
1183
+ function isNonEmpty(value) {
1184
+ for (const _ in value) return true;
1185
+ return false;
1186
+ }
1187
+ function normalizeProtocolList(value, label, allowed) {
1188
+ if (value === void 0) {
1189
+ return void 0;
1190
+ }
1191
+ if (!Array.isArray(value)) {
1192
+ throw new RequestError(`${label} must be an array`);
1193
+ }
1194
+ for (const protocol of value) {
1195
+ if (!allowed.has(protocol)) {
1196
+ throw new RequestError(`${label} values must be one of: HTTP1, HTTP2, HTTP3`);
1197
+ }
1198
+ }
1199
+ return [...value];
1200
+ }
1201
+ function normalizeTlsVersion(value, label) {
1202
+ if (value === void 0) {
1203
+ return void 0;
1204
+ }
1205
+ if (typeof value !== "string") {
1206
+ throw new RequestError(`${label} must be a string`);
1207
+ }
1208
+ const normalized = TLS_VERSION_ALIASES.get(value.trim().toLowerCase());
1209
+ if (!normalized) {
1210
+ throw new RequestError(`${label} must be one of: 1.0, 1.1, 1.2, 1.3`);
1211
+ }
1212
+ return normalized;
1213
+ }
1214
+ function normalizeOrigHeaders(origHeaders) {
1215
+ if (origHeaders === void 0) {
1216
+ return void 0;
1217
+ }
1218
+ if (!Array.isArray(origHeaders)) {
1219
+ throw new RequestError("emulation.origHeaders must be an array of strings");
1220
+ }
1221
+ const normalized = [];
1222
+ const seen = /* @__PURE__ */ new Set();
1223
+ for (const entry of origHeaders) {
1224
+ if (typeof entry !== "string" || entry.trim().length === 0) {
1225
+ throw new RequestError("emulation.origHeaders entries must be non-empty strings");
1226
+ }
1227
+ const trimmed = entry.trim();
1228
+ const duplicateKey = trimmed.toLowerCase();
1229
+ if (seen.has(duplicateKey)) {
1230
+ throw new RequestError(`Duplicate emulation.origHeaders entry: ${trimmed}`);
1231
+ }
1232
+ seen.add(duplicateKey);
1233
+ normalized.push(trimmed);
1234
+ }
1235
+ return normalized.length > 0 ? normalized : void 0;
1236
+ }
1237
+ function normalizeCustomTlsOptions(options) {
1238
+ if (options === void 0) {
1239
+ return void 0;
1240
+ }
1241
+ const normalized = {};
1242
+ const alpnProtocols = normalizeProtocolList(
1243
+ options.alpnProtocols,
1244
+ "emulation.tlsOptions.alpnProtocols",
1245
+ SUPPORTED_ALPN_PROTOCOLS
1246
+ );
1247
+ if (alpnProtocols !== void 0) {
1248
+ normalized.alpnProtocols = alpnProtocols;
1249
+ }
1250
+ const alpsProtocols = normalizeProtocolList(
1251
+ options.alpsProtocols,
1252
+ "emulation.tlsOptions.alpsProtocols",
1253
+ SUPPORTED_ALPS_PROTOCOLS
1254
+ );
1255
+ if (alpsProtocols !== void 0) {
1256
+ normalized.alpsProtocols = alpsProtocols;
1257
+ }
1258
+ const minTlsVersion = normalizeTlsVersion(options.minTlsVersion, "emulation.tlsOptions.minTlsVersion");
1259
+ if (minTlsVersion !== void 0) {
1260
+ normalized.minTlsVersion = minTlsVersion;
1261
+ }
1262
+ const maxTlsVersion = normalizeTlsVersion(options.maxTlsVersion, "emulation.tlsOptions.maxTlsVersion");
1263
+ if (maxTlsVersion !== void 0) {
1264
+ normalized.maxTlsVersion = maxTlsVersion;
1265
+ }
1266
+ if (options.alpsUseNewCodepoint !== void 0) {
1267
+ normalized.alpsUseNewCodepoint = options.alpsUseNewCodepoint;
1268
+ }
1269
+ if (options.sessionTicket !== void 0) {
1270
+ normalized.sessionTicket = options.sessionTicket;
1271
+ }
1272
+ if (options.preSharedKey !== void 0) {
1273
+ normalized.preSharedKey = options.preSharedKey;
1274
+ }
1275
+ if (options.enableEchGrease !== void 0) {
1276
+ normalized.enableEchGrease = options.enableEchGrease;
1277
+ }
1278
+ if (options.permuteExtensions !== void 0) {
1279
+ normalized.permuteExtensions = options.permuteExtensions;
1280
+ }
1281
+ if (options.greaseEnabled !== void 0) {
1282
+ normalized.greaseEnabled = options.greaseEnabled;
1283
+ }
1284
+ if (options.enableOcspStapling !== void 0) {
1285
+ normalized.enableOcspStapling = options.enableOcspStapling;
1286
+ }
1287
+ if (options.enableSignedCertTimestamps !== void 0) {
1288
+ normalized.enableSignedCertTimestamps = options.enableSignedCertTimestamps;
1289
+ }
1290
+ if (options.pskSkipSessionTicket !== void 0) {
1291
+ normalized.pskSkipSessionTicket = options.pskSkipSessionTicket;
1292
+ }
1293
+ if (options.pskDheKe !== void 0) {
1294
+ normalized.pskDheKe = options.pskDheKe;
1295
+ }
1296
+ if (options.renegotiation !== void 0) {
1297
+ normalized.renegotiation = options.renegotiation;
1298
+ }
1299
+ if (options.aesHwOverride !== void 0) {
1300
+ normalized.aesHwOverride = options.aesHwOverride;
1301
+ }
1302
+ if (options.preserveTls13CipherList !== void 0) {
1303
+ normalized.preserveTls13CipherList = options.preserveTls13CipherList;
1304
+ }
1305
+ if (options.randomAesHwOverride !== void 0) {
1306
+ normalized.randomAesHwOverride = options.randomAesHwOverride;
1307
+ }
1308
+ if (options.delegatedCredentials !== void 0) {
1309
+ normalized.delegatedCredentials = options.delegatedCredentials;
1310
+ }
1311
+ if (options.curvesList !== void 0) {
1312
+ normalized.curvesList = options.curvesList;
1313
+ }
1314
+ if (options.cipherList !== void 0) {
1315
+ normalized.cipherList = options.cipherList;
1316
+ }
1317
+ if (options.sigalgsList !== void 0) {
1318
+ normalized.sigalgsList = options.sigalgsList;
1319
+ }
1320
+ if (options.recordSizeLimit !== void 0) {
1321
+ validateIntegerInRange(options.recordSizeLimit, 0, 65535, "emulation.tlsOptions.recordSizeLimit");
1322
+ normalized.recordSizeLimit = options.recordSizeLimit;
1323
+ }
1324
+ if (options.keySharesLimit !== void 0) {
1325
+ validateIntegerInRange(options.keySharesLimit, 0, 255, "emulation.tlsOptions.keySharesLimit");
1326
+ normalized.keySharesLimit = options.keySharesLimit;
1327
+ }
1328
+ if (options.certificateCompressionAlgorithms !== void 0) {
1329
+ if (!Array.isArray(options.certificateCompressionAlgorithms)) {
1330
+ throw new RequestError("emulation.tlsOptions.certificateCompressionAlgorithms must be an array");
1331
+ }
1332
+ const algorithms = [];
1333
+ const seen = /* @__PURE__ */ new Set();
1334
+ for (const algorithm of options.certificateCompressionAlgorithms) {
1335
+ if (!SUPPORTED_CERTIFICATE_COMPRESSION_ALGORITHMS.has(algorithm)) {
1336
+ throw new RequestError(
1337
+ "emulation.tlsOptions.certificateCompressionAlgorithms values must be one of: zlib, brotli, zstd"
1338
+ );
1339
+ }
1340
+ if (seen.has(algorithm)) {
1341
+ throw new RequestError(`Duplicate emulation.tlsOptions.certificateCompressionAlgorithms entry: ${algorithm}`);
1342
+ }
1343
+ seen.add(algorithm);
1344
+ algorithms.push(algorithm);
1345
+ }
1346
+ normalized.certificateCompressionAlgorithms = algorithms;
1347
+ }
1348
+ if (options.extensionPermutation !== void 0) {
1349
+ if (!Array.isArray(options.extensionPermutation)) {
1350
+ throw new RequestError("emulation.tlsOptions.extensionPermutation must be an array");
1351
+ }
1352
+ const permutation = [];
1353
+ const seen = /* @__PURE__ */ new Set();
1354
+ for (const extensionId of options.extensionPermutation) {
1355
+ validateIntegerInRange(extensionId, 0, 65535, "emulation.tlsOptions.extensionPermutation");
1356
+ if (seen.has(extensionId)) {
1357
+ throw new RequestError(`Duplicate emulation.tlsOptions.extensionPermutation entry: ${extensionId}`);
1358
+ }
1359
+ seen.add(extensionId);
1360
+ permutation.push(extensionId);
1361
+ }
1362
+ normalized.extensionPermutation = permutation;
1363
+ }
1364
+ return isNonEmpty(normalized) ? normalized : void 0;
1365
+ }
1366
+ function normalizeCustomHttp1Options(options) {
1367
+ if (options === void 0) {
1368
+ return void 0;
1369
+ }
1370
+ const normalized = {};
1371
+ if (options.http09Responses !== void 0) {
1372
+ normalized.http09Responses = options.http09Responses;
1373
+ }
1374
+ if (options.writev !== void 0) {
1375
+ normalized.writev = options.writev;
1376
+ }
1377
+ if (options.ignoreInvalidHeadersInResponses !== void 0) {
1378
+ normalized.ignoreInvalidHeadersInResponses = options.ignoreInvalidHeadersInResponses;
1379
+ }
1380
+ if (options.allowSpacesAfterHeaderNameInResponses !== void 0) {
1381
+ normalized.allowSpacesAfterHeaderNameInResponses = options.allowSpacesAfterHeaderNameInResponses;
1382
+ }
1383
+ if (options.allowObsoleteMultilineHeadersInResponses !== void 0) {
1384
+ normalized.allowObsoleteMultilineHeadersInResponses = options.allowObsoleteMultilineHeadersInResponses;
1385
+ }
1386
+ if (options.maxHeaders !== void 0) {
1387
+ validateNonNegativeInteger(options.maxHeaders, "emulation.http1Options.maxHeaders");
1388
+ normalized.maxHeaders = options.maxHeaders;
1389
+ }
1390
+ if (options.readBufExactSize !== void 0) {
1391
+ validateNonNegativeInteger(options.readBufExactSize, "emulation.http1Options.readBufExactSize");
1392
+ normalized.readBufExactSize = options.readBufExactSize;
1393
+ }
1394
+ if (options.maxBufSize !== void 0) {
1395
+ validateNonNegativeInteger(options.maxBufSize, "emulation.http1Options.maxBufSize");
1396
+ if (options.maxBufSize < 8192) {
1397
+ throw new RequestError("emulation.http1Options.maxBufSize must be greater than or equal to 8192");
1398
+ }
1399
+ normalized.maxBufSize = options.maxBufSize;
1400
+ }
1401
+ if (normalized.readBufExactSize !== void 0 && normalized.maxBufSize !== void 0) {
1402
+ throw new RequestError("emulation.http1Options.readBufExactSize and maxBufSize cannot both be set");
1403
+ }
1404
+ return isNonEmpty(normalized) ? normalized : void 0;
1405
+ }
1406
+ function normalizeHttp2StreamDependency(dependency, label) {
1407
+ if (!isPlainObject(dependency)) {
1408
+ throw new RequestError(`${label} must be an object`);
1409
+ }
1410
+ validateIntegerInRange(dependency.dependencyId, 0, 2147483647, `${label}.dependencyId`);
1411
+ validateIntegerInRange(dependency.weight, 0, 255, `${label}.weight`);
1412
+ const normalized = {
1413
+ dependencyId: dependency.dependencyId,
1414
+ weight: dependency.weight
1415
+ };
1416
+ if (dependency.exclusive !== void 0) {
1417
+ normalized.exclusive = dependency.exclusive;
1418
+ }
1419
+ return normalized;
1420
+ }
1421
+ function normalizeCustomHttp2Options(options) {
1422
+ if (options === void 0) {
1423
+ return void 0;
1424
+ }
1425
+ const normalized = {};
1426
+ if (options.adaptiveWindow !== void 0) {
1427
+ normalized.adaptiveWindow = options.adaptiveWindow;
1428
+ }
1429
+ if (options.keepAliveWhileIdle !== void 0) {
1430
+ normalized.keepAliveWhileIdle = options.keepAliveWhileIdle;
1431
+ }
1432
+ if (options.enablePush !== void 0) {
1433
+ normalized.enablePush = options.enablePush;
1434
+ }
1435
+ if (options.enableConnectProtocol !== void 0) {
1436
+ normalized.enableConnectProtocol = options.enableConnectProtocol;
1437
+ }
1438
+ if (options.noRfc7540Priorities !== void 0) {
1439
+ normalized.noRfc7540Priorities = options.noRfc7540Priorities;
1440
+ }
1441
+ if (options.initialStreamId !== void 0) {
1442
+ validateNonNegativeInteger(options.initialStreamId, "emulation.http2Options.initialStreamId");
1443
+ normalized.initialStreamId = options.initialStreamId;
1444
+ }
1445
+ if (options.initialConnectionWindowSize !== void 0) {
1446
+ validateNonNegativeInteger(
1447
+ options.initialConnectionWindowSize,
1448
+ "emulation.http2Options.initialConnectionWindowSize"
1449
+ );
1450
+ normalized.initialConnectionWindowSize = options.initialConnectionWindowSize;
1451
+ }
1452
+ if (options.initialWindowSize !== void 0) {
1453
+ validateNonNegativeInteger(options.initialWindowSize, "emulation.http2Options.initialWindowSize");
1454
+ normalized.initialWindowSize = options.initialWindowSize;
1455
+ }
1456
+ if (options.initialMaxSendStreams !== void 0) {
1457
+ validateNonNegativeInteger(options.initialMaxSendStreams, "emulation.http2Options.initialMaxSendStreams");
1458
+ normalized.initialMaxSendStreams = options.initialMaxSendStreams;
1459
+ }
1460
+ if (options.maxFrameSize !== void 0) {
1461
+ validateNonNegativeInteger(options.maxFrameSize, "emulation.http2Options.maxFrameSize");
1462
+ normalized.maxFrameSize = options.maxFrameSize;
1463
+ }
1464
+ if (options.keepAliveInterval !== void 0) {
1465
+ validateNonNegativeInteger(options.keepAliveInterval, "emulation.http2Options.keepAliveInterval");
1466
+ normalized.keepAliveInterval = options.keepAliveInterval;
1467
+ }
1468
+ if (options.keepAliveTimeout !== void 0) {
1469
+ validateNonNegativeInteger(options.keepAliveTimeout, "emulation.http2Options.keepAliveTimeout");
1470
+ normalized.keepAliveTimeout = options.keepAliveTimeout;
1471
+ }
1472
+ if (options.maxConcurrentResetStreams !== void 0) {
1473
+ validateNonNegativeInteger(options.maxConcurrentResetStreams, "emulation.http2Options.maxConcurrentResetStreams");
1474
+ normalized.maxConcurrentResetStreams = options.maxConcurrentResetStreams;
1475
+ }
1476
+ if (options.maxSendBufferSize !== void 0) {
1477
+ validateNonNegativeInteger(options.maxSendBufferSize, "emulation.http2Options.maxSendBufferSize");
1478
+ normalized.maxSendBufferSize = options.maxSendBufferSize;
1479
+ }
1480
+ if (options.maxConcurrentStreams !== void 0) {
1481
+ validateNonNegativeInteger(options.maxConcurrentStreams, "emulation.http2Options.maxConcurrentStreams");
1482
+ normalized.maxConcurrentStreams = options.maxConcurrentStreams;
1483
+ }
1484
+ if (options.maxHeaderListSize !== void 0) {
1485
+ validateNonNegativeInteger(options.maxHeaderListSize, "emulation.http2Options.maxHeaderListSize");
1486
+ normalized.maxHeaderListSize = options.maxHeaderListSize;
1487
+ }
1488
+ if (options.maxPendingAcceptResetStreams !== void 0) {
1489
+ validateNonNegativeInteger(
1490
+ options.maxPendingAcceptResetStreams,
1491
+ "emulation.http2Options.maxPendingAcceptResetStreams"
1492
+ );
1493
+ normalized.maxPendingAcceptResetStreams = options.maxPendingAcceptResetStreams;
1494
+ }
1495
+ if (options.headerTableSize !== void 0) {
1496
+ validateNonNegativeInteger(options.headerTableSize, "emulation.http2Options.headerTableSize");
1497
+ normalized.headerTableSize = options.headerTableSize;
1498
+ }
1499
+ if (options.settingsOrder !== void 0) {
1500
+ if (!Array.isArray(options.settingsOrder)) {
1501
+ throw new RequestError("emulation.http2Options.settingsOrder must be an array");
1502
+ }
1503
+ const settingsOrder = [];
1504
+ const seen = /* @__PURE__ */ new Set();
1505
+ for (const settingId of options.settingsOrder) {
1506
+ if (!HTTP2_SETTING_IDS.has(settingId)) {
1507
+ throw new RequestError("emulation.http2Options.settingsOrder contains an unsupported setting id");
1508
+ }
1509
+ if (seen.has(settingId)) {
1510
+ throw new RequestError(`Duplicate emulation.http2Options.settingsOrder entry: ${settingId}`);
1511
+ }
1512
+ seen.add(settingId);
1513
+ settingsOrder.push(settingId);
1514
+ }
1515
+ normalized.settingsOrder = settingsOrder;
1516
+ }
1517
+ if (options.headersPseudoOrder !== void 0) {
1518
+ if (!Array.isArray(options.headersPseudoOrder)) {
1519
+ throw new RequestError("emulation.http2Options.headersPseudoOrder must be an array");
1520
+ }
1521
+ const headersPseudoOrder = [];
1522
+ const seenPseudo = /* @__PURE__ */ new Set();
1523
+ for (const pseudoId of options.headersPseudoOrder) {
1524
+ if (!HTTP2_PSEUDO_HEADER_IDS.has(pseudoId)) {
1525
+ throw new RequestError("emulation.http2Options.headersPseudoOrder contains an unsupported pseudo-header id");
1526
+ }
1527
+ if (seenPseudo.has(pseudoId)) {
1528
+ throw new RequestError(`Duplicate emulation.http2Options.headersPseudoOrder entry: ${pseudoId}`);
1529
+ }
1530
+ seenPseudo.add(pseudoId);
1531
+ headersPseudoOrder.push(pseudoId);
1532
+ }
1533
+ normalized.headersPseudoOrder = headersPseudoOrder;
1534
+ }
1535
+ if (options.headersStreamDependency !== void 0) {
1536
+ normalized.headersStreamDependency = normalizeHttp2StreamDependency(
1537
+ options.headersStreamDependency,
1538
+ "emulation.http2Options.headersStreamDependency"
1539
+ );
1540
+ }
1541
+ if (options.priorities !== void 0) {
1542
+ if (!Array.isArray(options.priorities)) {
1543
+ throw new RequestError("emulation.http2Options.priorities must be an array");
1544
+ }
1545
+ const priorities = [];
1546
+ const seenStreamIds = /* @__PURE__ */ new Set();
1547
+ for (const [index, priority] of options.priorities.entries()) {
1548
+ if (!isPlainObject(priority)) {
1549
+ throw new RequestError(`emulation.http2Options.priorities[${index}] must be an object`);
1550
+ }
1551
+ validatePositiveInteger(priority.streamId, `emulation.http2Options.priorities[${index}].streamId`);
1552
+ if (seenStreamIds.has(priority.streamId)) {
1553
+ throw new RequestError(`Duplicate emulation.http2Options.priorities streamId: ${priority.streamId}`);
1554
+ }
1555
+ seenStreamIds.add(priority.streamId);
1556
+ priorities.push({
1557
+ streamId: priority.streamId,
1558
+ dependency: normalizeHttp2StreamDependency(
1559
+ priority.dependency,
1560
+ `emulation.http2Options.priorities[${index}].dependency`
1561
+ )
1562
+ });
1563
+ }
1564
+ normalized.priorities = priorities;
1565
+ }
1566
+ if (options.experimentalSettings !== void 0) {
1567
+ if (!Array.isArray(options.experimentalSettings)) {
1568
+ throw new RequestError("emulation.http2Options.experimentalSettings must be an array");
1569
+ }
1570
+ const experimentalSettings = [];
1571
+ const seenIds = /* @__PURE__ */ new Set();
1572
+ for (const [index, setting] of options.experimentalSettings.entries()) {
1573
+ if (!isPlainObject(setting)) {
1574
+ throw new RequestError(`emulation.http2Options.experimentalSettings[${index}] must be an object`);
1575
+ }
1576
+ validateIntegerInRange(
1577
+ setting.id,
1578
+ 1,
1579
+ MAX_HTTP2_EXPERIMENTAL_SETTING_ID,
1580
+ `emulation.http2Options.experimentalSettings[${index}].id`
1581
+ );
1582
+ if (STANDARD_HTTP2_SETTING_ID_VALUES.has(setting.id)) {
1583
+ throw new RequestError(
1584
+ `emulation.http2Options.experimentalSettings[${index}].id must not be a standard HTTP/2 setting id`
1585
+ );
1586
+ }
1587
+ if (seenIds.has(setting.id)) {
1588
+ throw new RequestError(`Duplicate emulation.http2Options.experimentalSettings id: ${setting.id}`);
1589
+ }
1590
+ seenIds.add(setting.id);
1591
+ validateIntegerInRange(
1592
+ setting.value,
1593
+ 0,
1594
+ 4294967295,
1595
+ `emulation.http2Options.experimentalSettings[${index}].value`
1596
+ );
1597
+ experimentalSettings.push({
1598
+ id: setting.id,
1599
+ value: setting.value
1600
+ });
1601
+ }
1602
+ normalized.experimentalSettings = experimentalSettings;
1603
+ }
1604
+ return isNonEmpty(normalized) ? normalized : void 0;
1605
+ }
1606
+ function normalizeCustomEmulationOptions(emulation, allowEmpty) {
1607
+ if (emulation === void 0) {
1608
+ return void 0;
1609
+ }
1610
+ if (!isPlainObject(emulation)) {
1611
+ throw new RequestError("emulation must be an object");
1612
+ }
1613
+ const source = emulation;
1614
+ const normalized = {};
1615
+ const tlsOptions = normalizeCustomTlsOptions(source.tlsOptions);
1616
+ if (tlsOptions !== void 0) {
1617
+ normalized.tlsOptions = tlsOptions;
1618
+ }
1619
+ const http1Options = normalizeCustomHttp1Options(source.http1Options);
1620
+ if (http1Options !== void 0) {
1621
+ normalized.http1Options = http1Options;
1622
+ }
1623
+ const http2Options = normalizeCustomHttp2Options(source.http2Options);
1624
+ if (http2Options !== void 0) {
1625
+ normalized.http2Options = http2Options;
1626
+ }
1627
+ if (source.headers !== void 0) {
1628
+ const headers = headersToTuples(source.headers);
1629
+ if (headers.length > 0) {
1630
+ normalized.headers = headers;
1631
+ }
1632
+ }
1633
+ const origHeaders = normalizeOrigHeaders(source.origHeaders);
1634
+ if (origHeaders !== void 0) {
1635
+ normalized.origHeaders = origHeaders;
1636
+ }
1637
+ if (!allowEmpty && !isNonEmpty(normalized)) {
1638
+ throw new RequestError(
1639
+ "Standalone custom emulation requires at least one of tlsOptions, http1Options, http2Options, headers, or origHeaders"
1640
+ );
1641
+ }
1642
+ return isNonEmpty(normalized) ? normalized : void 0;
1643
+ }
1644
+ function serializeCustomEmulationOptions(emulation, allowEmpty) {
1645
+ const normalized = normalizeCustomEmulationOptions(emulation, allowEmpty);
1646
+ return normalized ? JSON.stringify(normalized) : void 0;
1647
+ }
1648
+ function resolveEmulationMode(browser, os, emulation) {
1649
+ if (browser !== void 0) {
1650
+ validateBrowserProfile(browser);
1651
+ if (os !== void 0) {
1652
+ validateOperatingSystem(os);
1653
+ }
1654
+ const emulationJson = serializeCustomEmulationOptions(emulation, true);
1655
+ return {
1656
+ kind: "preset",
1657
+ browser,
1658
+ os: os ?? DEFAULT_OS,
1659
+ ...emulationJson !== void 0 && { emulationJson }
1660
+ };
1661
+ }
1662
+ if (os !== void 0) {
1663
+ validateOperatingSystem(os);
1664
+ const emulationJson = serializeCustomEmulationOptions(emulation, true);
1665
+ return {
1666
+ kind: "preset",
1667
+ browser: DEFAULT_BROWSER,
1668
+ os,
1669
+ ...emulationJson !== void 0 && { emulationJson }
1670
+ };
1671
+ }
1672
+ if (emulation !== void 0) {
1673
+ const emulationJson = serializeCustomEmulationOptions(emulation, false);
1674
+ if (emulationJson === void 0) {
1675
+ throw new RequestError(
1676
+ "Standalone custom emulation requires at least one of tlsOptions, http1Options, http2Options, headers, or origHeaders"
1677
+ );
1678
+ }
1679
+ return { kind: "custom", emulationJson };
1680
+ }
1681
+ return {
1682
+ kind: "preset",
1683
+ browser: DEFAULT_BROWSER,
1684
+ os: DEFAULT_OS
1685
+ };
1686
+ }
1687
+ function applyNativeEmulationMode(target, mode) {
1688
+ if (mode.kind === "custom") {
1689
+ target.emulationJson = mode.emulationJson;
1690
+ return;
1691
+ }
1692
+ target.browser = mode.browser;
1693
+ target.os = mode.os;
1694
+ if (mode.emulationJson !== void 0) {
1695
+ target.emulationJson = mode.emulationJson;
1696
+ }
1697
+ }
1149
1698
  async function dispatchRequest(options, requestUrl, signal) {
1150
1699
  if (!signal) {
1151
1700
  const requestId2 = generateRequestId();
@@ -1220,8 +1769,9 @@ async function fetch(input, init) {
1220
1769
  if (transport.transportId) {
1221
1770
  requestOptions.transportId = transport.transportId;
1222
1771
  } else {
1223
- requestOptions.browser = transport.browser ?? DEFAULT_BROWSER;
1224
- requestOptions.os = transport.os ?? DEFAULT_OS;
1772
+ if (transport.mode !== void 0) {
1773
+ applyNativeEmulationMode(requestOptions, transport.mode);
1774
+ }
1225
1775
  if (transport.proxy !== void 0) {
1226
1776
  requestOptions.proxy = transport.proxy;
1227
1777
  }
@@ -1245,10 +1795,7 @@ async function fetch(input, init) {
1245
1795
  return dispatchRequest(requestOptions, url, config.signal ?? null);
1246
1796
  }
1247
1797
  async function createTransport(options) {
1248
- const browser = options?.browser ?? DEFAULT_BROWSER;
1249
- const os = options?.os ?? DEFAULT_OS;
1250
- validateBrowserProfile(browser);
1251
- validateOperatingSystem(os);
1798
+ const mode = resolveEmulationMode(options?.browser, options?.os, options?.emulation);
1252
1799
  if (options?.poolIdleTimeout !== void 0) {
1253
1800
  validatePositiveNumber(options.poolIdleTimeout, "poolIdleTimeout");
1254
1801
  }
@@ -1265,9 +1812,7 @@ async function createTransport(options) {
1265
1812
  validatePositiveNumber(options.readTimeout, "readTimeout");
1266
1813
  }
1267
1814
  try {
1268
- const id = nativeBinding.createTransport({
1269
- browser,
1270
- os,
1815
+ const transportOptions = {
1271
1816
  ...options?.proxy !== void 0 && { proxy: options.proxy },
1272
1817
  ...options?.insecure !== void 0 && { insecure: options.insecure },
1273
1818
  ...options?.poolIdleTimeout !== void 0 && { poolIdleTimeout: options.poolIdleTimeout },
@@ -1275,7 +1820,9 @@ async function createTransport(options) {
1275
1820
  ...options?.poolMaxSize !== void 0 && { poolMaxSize: options.poolMaxSize },
1276
1821
  ...options?.connectTimeout !== void 0 && { connectTimeout: options.connectTimeout },
1277
1822
  ...options?.readTimeout !== void 0 && { readTimeout: options.readTimeout }
1278
- });
1823
+ };
1824
+ applyNativeEmulationMode(transportOptions, mode);
1825
+ const id = nativeBinding.createTransport(transportOptions);
1279
1826
  return new Transport(id);
1280
1827
  } catch (error) {
1281
1828
  throw new RequestError(String(error));
@@ -1283,17 +1830,15 @@ async function createTransport(options) {
1283
1830
  }
1284
1831
  async function createSession(options) {
1285
1832
  const { sessionId, defaults } = normalizeSessionOptions(options);
1286
- validateBrowserProfile(defaults.browser);
1287
- validateOperatingSystem(defaults.os);
1288
1833
  let createdId;
1289
1834
  let transportId;
1290
1835
  try {
1291
- transportId = nativeBinding.createTransport({
1292
- browser: defaults.browser,
1293
- os: defaults.os,
1836
+ const transportOptions = {
1294
1837
  ...defaults.proxy !== void 0 && { proxy: defaults.proxy },
1295
1838
  ...defaults.insecure !== void 0 && { insecure: defaults.insecure }
1296
- });
1839
+ };
1840
+ applyNativeEmulationMode(transportOptions, defaults.transportMode);
1841
+ transportId = nativeBinding.createTransport(transportOptions);
1297
1842
  } catch (error) {
1298
1843
  throw new RequestError(String(error));
1299
1844
  }
@@ -1342,6 +1887,9 @@ async function request(options) {
1342
1887
  if (rest.os !== void 0) {
1343
1888
  init.os = rest.os;
1344
1889
  }
1890
+ if (rest.emulation !== void 0) {
1891
+ init.emulation = rest.emulation;
1892
+ }
1345
1893
  if (rest.proxy !== void 0) {
1346
1894
  init.proxy = rest.proxy;
1347
1895
  }
@@ -1475,6 +2023,9 @@ function normalizeStandaloneWebSocketOptions(options) {
1475
2023
  if (options.os !== void 0) {
1476
2024
  normalized.os = options.os;
1477
2025
  }
2026
+ if (options.emulation !== void 0) {
2027
+ normalized.emulation = options.emulation;
2028
+ }
1478
2029
  if (options.headers !== void 0) {
1479
2030
  normalized.headers = options.headers;
1480
2031
  }
@@ -1506,6 +2057,11 @@ function normalizeSessionWebSocketOptions(options) {
1506
2057
  if (optionsWithOverrides.os !== void 0) {
1507
2058
  throw new RequestError("`os` is not supported in session.websocket(); the session controls OS emulation.");
1508
2059
  }
2060
+ if (optionsWithOverrides.emulation !== void 0) {
2061
+ throw new RequestError(
2062
+ "`emulation` is not supported in session.websocket(); the session transport controls emulation."
2063
+ );
2064
+ }
1509
2065
  if (optionsWithOverrides.proxy !== void 0) {
1510
2066
  throw new RequestError("`proxy` is not supported in session.websocket(); the session transport controls proxying.");
1511
2067
  }
@@ -1671,10 +2227,11 @@ var WebSocket = class _WebSocket {
1671
2227
  typeof protocolsOrOptions === "string" || Array.isArray(protocolsOrOptions) ? protocolsOrOptions : normalizedOptions.protocols
1672
2228
  );
1673
2229
  assertNoManualWebSocketProtocolHeader(normalizedOptions.headers);
1674
- validateBrowserProfile(normalizedOptions.browser);
1675
- const os = normalizedOptions.os ?? DEFAULT_OS;
1676
- validateOperatingSystem(os);
1677
- const browser = normalizedOptions.browser ?? DEFAULT_BROWSER;
2230
+ const emulationMode = resolveEmulationMode(
2231
+ normalizedOptions.browser,
2232
+ normalizedOptions.os,
2233
+ normalizedOptions.emulation
2234
+ );
1678
2235
  const protocols = normalizeWebSocketProtocolList(
1679
2236
  typeof protocolsOrOptions === "string" || Array.isArray(protocolsOrOptions) ? protocolsOrOptions : normalizedOptions.protocols
1680
2237
  );
@@ -1683,17 +2240,19 @@ var WebSocket = class _WebSocket {
1683
2240
  url: normalizeWebSocketUrl(url),
1684
2241
  options: normalizedOptions,
1685
2242
  openDispatchMode: "automatic",
1686
- connect: (callbacks) => nativeBinding.websocketConnect({
1687
- url: normalizeWebSocketUrl(url),
1688
- browser,
1689
- os,
1690
- headers: headersToTuples(normalizedOptions.headers ?? {}),
1691
- ...protocols && protocols.length > 0 && { protocols },
1692
- ...normalizedOptions.proxy !== void 0 && { proxy: normalizedOptions.proxy },
1693
- onMessage: callbacks.onMessage,
1694
- onClose: callbacks.onClose,
1695
- onError: callbacks.onError
1696
- }),
2243
+ connect: (callbacks) => {
2244
+ const nativeOptions = {
2245
+ url: normalizeWebSocketUrl(url),
2246
+ headers: headersToTuples(normalizedOptions.headers ?? {}),
2247
+ ...protocols && protocols.length > 0 && { protocols },
2248
+ ...normalizedOptions.proxy !== void 0 && { proxy: normalizedOptions.proxy },
2249
+ onMessage: callbacks.onMessage,
2250
+ onClose: callbacks.onClose,
2251
+ onError: callbacks.onError
2252
+ };
2253
+ applyNativeEmulationMode(nativeOptions, emulationMode);
2254
+ return nativeBinding.websocketConnect(nativeOptions);
2255
+ },
1697
2256
  legacyCallbacks: extractLegacyWebSocketCallbacks(optionsCandidate)
1698
2257
  };
1699
2258
  }
@@ -2087,27 +2646,30 @@ async function websocket(urlOrOptions, options) {
2087
2646
  const normalized = normalizeStandaloneWebSocketArgs(urlOrOptions, options);
2088
2647
  validateWebSocketProtocols(normalized.options.protocols);
2089
2648
  assertNoManualWebSocketProtocolHeader(normalized.options.headers);
2090
- validateBrowserProfile(normalized.options.browser);
2091
- const os = normalized.options.os ?? DEFAULT_OS;
2092
- validateOperatingSystem(os);
2093
- const browser = normalized.options.browser ?? DEFAULT_BROWSER;
2649
+ const emulationMode = resolveEmulationMode(
2650
+ normalized.options.browser,
2651
+ normalized.options.os,
2652
+ normalized.options.emulation
2653
+ );
2094
2654
  const protocols = normalizeWebSocketProtocolList(normalized.options.protocols);
2095
2655
  return WebSocket._connectWithInit({
2096
2656
  _internal: true,
2097
2657
  url: normalized.url,
2098
2658
  options: normalized.options,
2099
2659
  openDispatchMode: "deferred",
2100
- connect: (callbacks) => nativeBinding.websocketConnect({
2101
- url: normalized.url,
2102
- browser,
2103
- os,
2104
- headers: headersToTuples(normalized.options.headers ?? {}),
2105
- ...protocols && protocols.length > 0 && { protocols },
2106
- ...normalized.options.proxy !== void 0 && { proxy: normalized.options.proxy },
2107
- onMessage: callbacks.onMessage,
2108
- onClose: callbacks.onClose,
2109
- onError: callbacks.onError
2110
- }),
2660
+ connect: (callbacks) => {
2661
+ const nativeOptions = {
2662
+ url: normalized.url,
2663
+ headers: headersToTuples(normalized.options.headers ?? {}),
2664
+ ...protocols && protocols.length > 0 && { protocols },
2665
+ ...normalized.options.proxy !== void 0 && { proxy: normalized.options.proxy },
2666
+ onMessage: callbacks.onMessage,
2667
+ onClose: callbacks.onClose,
2668
+ onError: callbacks.onError
2669
+ };
2670
+ applyNativeEmulationMode(nativeOptions, emulationMode);
2671
+ return nativeBinding.websocketConnect(nativeOptions);
2672
+ },
2111
2673
  legacyCallbacks: normalized.legacyCallbacks
2112
2674
  });
2113
2675
  }