@cypress/github-action 7.4.4 → 7.4.6

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.
Files changed (3) hide show
  1. package/README.md +63 -57
  2. package/dist/index.js +371 -181
  3. package/package.json +2 -2
package/README.md CHANGED
@@ -97,7 +97,7 @@ name: End-to-end tests
97
97
  on: push
98
98
  jobs:
99
99
  cypress-run:
100
- runs-on: ubuntu-24.04
100
+ runs-on: ubuntu-26.04
101
101
  steps:
102
102
  - name: Checkout
103
103
  uses: actions/checkout@v7
@@ -122,7 +122,7 @@ name: Component tests
122
122
  on: push
123
123
  jobs:
124
124
  cypress-run:
125
- runs-on: ubuntu-24.04
125
+ runs-on: ubuntu-26.04
126
126
  steps:
127
127
  - name: Checkout
128
128
  uses: actions/checkout@v7
@@ -166,7 +166,15 @@ The workflows in the [examples](./examples/) directory use the latest commit fro
166
166
 
167
167
  ### Browser
168
168
 
169
- Specify the browser name or path with the `browser` parameter. The default browser, if none is specified, is the built-in [Electron browser](https://on.cypress.io/guides/guides/launching-browsers#Electron-Browser).
169
+ Specify the browser name or path with the `browser` parameter.
170
+
171
+ The default browser can be set as a [Browser](https://docs.cypress.io/app/references/configuration#Browser) configuration option `defaultBrowser`.
172
+ If no `browser` parameter is specified and `defaultBrowser` is also undefined,
173
+ the built-in [Electron browser](https://on.cypress.io/guides/guides/launching-browsers#Electron-Browser) is used.
174
+
175
+ [cypress@16.0.0](https://docs.cypress.io/app/references/changelog#16-0-0) deprecated the Electron browser and describes the plan to remove it in a future major version of Cypress.
176
+
177
+ Each of the [examples](./examples/) directories in this repo sets `defaultBrowser` to `chrome`.
170
178
 
171
179
  ### Chrome
172
180
 
@@ -175,7 +183,7 @@ name: Chrome
175
183
  on: push
176
184
  jobs:
177
185
  chrome:
178
- runs-on: ubuntu-24.04
186
+ runs-on: ubuntu-26.04
179
187
  name: E2E on Chrome
180
188
  steps:
181
189
  - uses: actions/checkout@v7
@@ -199,7 +207,7 @@ name: Chrome for Testing
199
207
  on: push
200
208
  jobs:
201
209
  chrome:
202
- runs-on: ubuntu-24.04
210
+ runs-on: ubuntu-26.04
203
211
  name: E2E on Chrome for Testing
204
212
  steps:
205
213
  - uses: actions/checkout@v7
@@ -218,7 +226,7 @@ name: Firefox
218
226
  on: push
219
227
  jobs:
220
228
  firefox:
221
- runs-on: ubuntu-24.04
229
+ runs-on: ubuntu-26.04
222
230
  name: E2E on Firefox
223
231
  steps:
224
232
  - uses: actions/checkout@v7
@@ -236,7 +244,7 @@ name: Edge
236
244
  on: push
237
245
  jobs:
238
246
  edge:
239
- runs-on: ubuntu-24.04
247
+ runs-on: ubuntu-26.04
240
248
  name: E2E on Edge
241
249
  steps:
242
250
  - uses: actions/checkout@v7
@@ -256,7 +264,7 @@ name: Chrome headed
256
264
  on: push
257
265
  jobs:
258
266
  cypress-run:
259
- runs-on: ubuntu-24.04
267
+ runs-on: ubuntu-26.04
260
268
  steps:
261
269
  - uses: actions/checkout@v7
262
270
  - uses: cypress-io/github-action@v7
@@ -274,7 +282,7 @@ name: Test in Docker
274
282
  on: push
275
283
  jobs:
276
284
  cypress-run:
277
- runs-on: ubuntu-24.04
285
+ runs-on: ubuntu-26.04
278
286
  # Cypress Docker image from https://hub.docker.com/r/cypress
279
287
  # with browsers pre-installed
280
288
  container:
@@ -298,7 +306,7 @@ name: Test with Docker cypress/included
298
306
  on: push
299
307
  jobs:
300
308
  cypress-run:
301
- runs-on: ubuntu-24.04
309
+ runs-on: ubuntu-26.04
302
310
  container:
303
311
  # Cypress Docker image from https://hub.docker.com/r/cypress/included
304
312
  # with Cypress globally pre-installed
@@ -328,7 +336,7 @@ name: Cypress tests
328
336
  on: push
329
337
  jobs:
330
338
  cypress-run:
331
- runs-on: ubuntu-24.04
339
+ runs-on: ubuntu-26.04
332
340
  steps:
333
341
  - name: Checkout
334
342
  uses: actions/checkout@v7
@@ -346,7 +354,7 @@ name: Cypress tests
346
354
  on: push
347
355
  jobs:
348
356
  cypress-run:
349
- runs-on: ubuntu-24.04
357
+ runs-on: ubuntu-26.04
350
358
  steps:
351
359
  - name: Checkout
352
360
  uses: actions/checkout@v7
@@ -371,7 +379,7 @@ name: Cypress tests
371
379
  on: push
372
380
  jobs:
373
381
  cypress-run:
374
- runs-on: ubuntu-24.04
382
+ runs-on: ubuntu-26.04
375
383
  steps:
376
384
  - name: Checkout
377
385
  uses: actions/checkout@v7
@@ -396,7 +404,7 @@ on: push
396
404
  jobs:
397
405
  cypress-run:
398
406
  name: Cypress run
399
- runs-on: ubuntu-24.04
407
+ runs-on: ubuntu-26.04
400
408
  steps:
401
409
  - name: Checkout
402
410
  uses: actions/checkout@v7
@@ -427,7 +435,7 @@ on: push
427
435
  jobs:
428
436
  cypress-run:
429
437
  name: Cypress run
430
- runs-on: ubuntu-24.04
438
+ runs-on: ubuntu-26.04
431
439
  steps:
432
440
  - name: Checkout
433
441
  uses: actions/checkout@v7
@@ -459,7 +467,7 @@ on: push
459
467
  jobs:
460
468
  cypress-run:
461
469
  name: Cypress run
462
- runs-on: ubuntu-24.04
470
+ runs-on: ubuntu-26.04
463
471
  steps:
464
472
  - name: Checkout
465
473
  uses: actions/checkout@v7
@@ -489,7 +497,7 @@ on: push
489
497
  jobs:
490
498
  cypress-run:
491
499
  name: Cypress run
492
- runs-on: ubuntu-24.04
500
+ runs-on: ubuntu-26.04
493
501
  steps:
494
502
  - name: Checkout
495
503
  uses: actions/checkout@v7
@@ -522,7 +530,7 @@ name: Example echo PR number and URL
522
530
  on: push
523
531
  jobs:
524
532
  cypress-run:
525
- runs-on: ubuntu-24.04
533
+ runs-on: ubuntu-26.04
526
534
  steps:
527
535
  - name: Checkout
528
536
  uses: actions/checkout@v7
@@ -560,7 +568,7 @@ on: push
560
568
  jobs:
561
569
  cypress-run:
562
570
  name: Cypress run
563
- runs-on: ubuntu-24.04
571
+ runs-on: ubuntu-26.04
564
572
  steps:
565
573
  - name: Checkout
566
574
  uses: actions/checkout@v7
@@ -588,7 +596,7 @@ name: tags
588
596
  on: push
589
597
  jobs:
590
598
  cypress-run:
591
- runs-on: ubuntu-24.04
599
+ runs-on: ubuntu-26.04
592
600
  # let's make sure our "app" works on several versions of Node
593
601
  strategy:
594
602
  matrix:
@@ -633,7 +641,7 @@ name: Cypress E2E Tests
633
641
  on: push
634
642
  jobs:
635
643
  cypress-run:
636
- runs-on: ubuntu-24.04
644
+ runs-on: ubuntu-26.04
637
645
  name: E2E
638
646
  steps:
639
647
  - name: Checkout
@@ -661,7 +669,7 @@ name: Artifacts
661
669
  on: push
662
670
  jobs:
663
671
  cypress-run:
664
- runs-on: ubuntu-24.04
672
+ runs-on: ubuntu-26.04
665
673
  name: Artifacts
666
674
  steps:
667
675
  - uses: actions/checkout@v7
@@ -690,7 +698,7 @@ name: example-quiet
690
698
  on: push
691
699
  jobs:
692
700
  cypress-run:
693
- runs-on: ubuntu-24.04
701
+ runs-on: ubuntu-26.04
694
702
  steps:
695
703
  - name: Checkout
696
704
  uses: actions/checkout@v7
@@ -715,7 +723,7 @@ on: push
715
723
  jobs:
716
724
  cypress-run:
717
725
  name: Cypress run
718
- runs-on: ubuntu-24.04
726
+ runs-on: ubuntu-26.04
719
727
  steps:
720
728
  - name: Checkout
721
729
  uses: actions/checkout@v7
@@ -738,7 +746,7 @@ on: push
738
746
  jobs:
739
747
  cypress-run:
740
748
  name: Cypress run
741
- runs-on: ubuntu-24.04
749
+ runs-on: ubuntu-26.04
742
750
  steps:
743
751
  - name: Checkout
744
752
  uses: actions/checkout@v7
@@ -765,7 +773,7 @@ on: push
765
773
  jobs:
766
774
  test:
767
775
  name: Cypress run
768
- runs-on: ubuntu-24.04
776
+ runs-on: ubuntu-26.04
769
777
  strategy:
770
778
  # when one test fails, DO NOT cancel the other
771
779
  # containers, because this will kill Cypress processes
@@ -852,7 +860,7 @@ name: Build
852
860
  on: push
853
861
  jobs:
854
862
  cypress-run:
855
- runs-on: ubuntu-24.04
863
+ runs-on: ubuntu-26.04
856
864
  steps:
857
865
  - name: Checkout
858
866
  uses: actions/checkout@v7
@@ -871,7 +879,7 @@ name: With server
871
879
  on: push
872
880
  jobs:
873
881
  cypress-run:
874
- runs-on: ubuntu-24.04
882
+ runs-on: ubuntu-26.04
875
883
  steps:
876
884
  - name: Checkout
877
885
  uses: actions/checkout@v7
@@ -890,7 +898,7 @@ name: With server
890
898
  on: push
891
899
  jobs:
892
900
  cypress-run:
893
- runs-on: ubuntu-24.04
901
+ runs-on: ubuntu-26.04
894
902
  steps:
895
903
  - name: Checkout
896
904
  uses: actions/checkout@v7
@@ -916,7 +924,7 @@ name: With servers
916
924
  on: push
917
925
  jobs:
918
926
  cypress-run:
919
- runs-on: ubuntu-24.04
927
+ runs-on: ubuntu-26.04
920
928
  steps:
921
929
  - name: Checkout
922
930
  uses: actions/checkout@v7
@@ -946,7 +954,7 @@ name: After server responds
946
954
  on: push
947
955
  jobs:
948
956
  cypress-run:
949
- runs-on: ubuntu-24.04
957
+ runs-on: ubuntu-26.04
950
958
  steps:
951
959
  - name: Checkout
952
960
  uses: actions/checkout@v7
@@ -1035,7 +1043,7 @@ name: Visual
1035
1043
  on: push
1036
1044
  jobs:
1037
1045
  e2e:
1038
- runs-on: ubuntu-24.04
1046
+ runs-on: ubuntu-26.04
1039
1047
  steps:
1040
1048
  - name: Checkout
1041
1049
  uses: actions/checkout@v7
@@ -1082,7 +1090,7 @@ name: Parallel
1082
1090
  on: push
1083
1091
  jobs:
1084
1092
  test:
1085
- runs-on: ubuntu-24.04
1093
+ runs-on: ubuntu-26.04
1086
1094
  strategy:
1087
1095
  matrix:
1088
1096
  # run 3 copies of the current job in parallel
@@ -1167,7 +1175,7 @@ We use `working-directory: app-test` to match the above example directory struct
1167
1175
  on: push
1168
1176
  jobs:
1169
1177
  cypress-run:
1170
- runs-on: ubuntu-24.04
1178
+ runs-on: ubuntu-26.04
1171
1179
  steps:
1172
1180
  - uses: actions/checkout@v7
1173
1181
  - uses: cypress-io/github-action@v7
@@ -1205,7 +1213,7 @@ name: E2E
1205
1213
  on: push
1206
1214
  jobs:
1207
1215
  test:
1208
- runs-on: ubuntu-24.04
1216
+ runs-on: ubuntu-26.04
1209
1217
  steps:
1210
1218
  - uses: actions/checkout@v7
1211
1219
  - name: Install root dependencies
@@ -1237,14 +1245,14 @@ name: example-basic-pnpm
1237
1245
  on: push
1238
1246
  jobs:
1239
1247
  basic-pnpm:
1240
- runs-on: ubuntu-24.04
1248
+ runs-on: ubuntu-26.04
1241
1249
  steps:
1242
1250
  - name: Checkout
1243
1251
  uses: actions/checkout@v7
1244
1252
  - name: Install pnpm
1245
1253
  uses: pnpm/action-setup@v6
1246
1254
  with:
1247
- version: 11
1255
+ version: 12
1248
1256
  - name: Install Node.js
1249
1257
  uses: actions/setup-node@v7
1250
1258
  with:
@@ -1297,7 +1305,7 @@ name: example-yarn-classic
1297
1305
  on: push
1298
1306
  jobs:
1299
1307
  yarn-classic:
1300
- runs-on: ubuntu-24.04
1308
+ runs-on: ubuntu-26.04
1301
1309
  steps:
1302
1310
  - name: Checkout
1303
1311
  uses: actions/checkout@v7
@@ -1320,7 +1328,7 @@ name: example-yarn-modern
1320
1328
  on: push
1321
1329
  jobs:
1322
1330
  yarn-modern:
1323
- runs-on: ubuntu-24.04
1331
+ runs-on: ubuntu-26.04
1324
1332
  steps:
1325
1333
  - name: Checkout
1326
1334
  uses: actions/checkout@v7
@@ -1354,7 +1362,7 @@ name: example-yarn-modern-pnp
1354
1362
  on: push
1355
1363
  jobs:
1356
1364
  yarn-classic:
1357
- runs-on: ubuntu-24.04
1365
+ runs-on: ubuntu-26.04
1358
1366
  steps:
1359
1367
  - name: Checkout
1360
1368
  uses: actions/checkout@v7
@@ -1384,7 +1392,7 @@ jobs:
1384
1392
  # the example has Yarn workspace in its "root" folder
1385
1393
  # examples/start-and-yarn-workspaces
1386
1394
  # and tests in a subfolder like "workspace-1"
1387
- runs-on: ubuntu-24.04
1395
+ runs-on: ubuntu-26.04
1388
1396
  steps:
1389
1397
  - uses: actions/checkout@v7
1390
1398
  - uses: cypress-io/github-action@v7
@@ -1415,7 +1423,7 @@ name: Package manager caching
1415
1423
  on: push
1416
1424
  jobs:
1417
1425
  cypress-run:
1418
- runs-on: ubuntu-24.04
1426
+ runs-on: ubuntu-26.04
1419
1427
  name:
1420
1428
  steps:
1421
1429
  - uses: actions/checkout@v7
@@ -1438,7 +1446,7 @@ name: End-to-end tests
1438
1446
  on: push
1439
1447
  jobs:
1440
1448
  cypress-run:
1441
- runs-on: ubuntu-24.04
1449
+ runs-on: ubuntu-26.04
1442
1450
  # let's make sure our "app" works on several versions of Node
1443
1451
  strategy:
1444
1452
  matrix:
@@ -1476,7 +1484,7 @@ name: Node versions
1476
1484
  on: push
1477
1485
  jobs:
1478
1486
  cypress-run:
1479
- runs-on: ubuntu-24.04
1487
+ runs-on: ubuntu-26.04
1480
1488
  strategy:
1481
1489
  matrix:
1482
1490
  node:
@@ -1505,7 +1513,7 @@ name: E2E
1505
1513
  on: push
1506
1514
  jobs:
1507
1515
  test:
1508
- runs-on: ubuntu-24.04
1516
+ runs-on: ubuntu-26.04
1509
1517
  steps:
1510
1518
  - uses: actions/checkout@v7
1511
1519
  - name: Install dependencies
@@ -1538,7 +1546,7 @@ name: Split build and test
1538
1546
  on: push
1539
1547
  jobs:
1540
1548
  build:
1541
- runs-on: ubuntu-24.04
1549
+ runs-on: ubuntu-26.04
1542
1550
  steps:
1543
1551
  - uses: actions/checkout@v7
1544
1552
  - name: Build app
@@ -1556,7 +1564,7 @@ jobs:
1556
1564
 
1557
1565
  test:
1558
1566
  needs: build
1559
- runs-on: ubuntu-24.04
1567
+ runs-on: ubuntu-26.04
1560
1568
  steps:
1561
1569
  - uses: actions/checkout@v7
1562
1570
  - name: Restore build artifacts
@@ -1584,7 +1592,7 @@ You can tell the CI to stop the job or the individual step if it runs for longer
1584
1592
  ```yml
1585
1593
  jobs:
1586
1594
  cypress-run:
1587
- runs-on: ubuntu-24.04
1595
+ runs-on: ubuntu-26.04
1588
1596
  # stop the job if it runs over 10 minutes
1589
1597
  # to prevent a hanging process from using all your CI minutes
1590
1598
  timeout-minutes: 10
@@ -1629,7 +1637,7 @@ name: CLI migration example
1629
1637
  on: push
1630
1638
  jobs:
1631
1639
  cypress-run:
1632
- runs-on: ubuntu-24.04
1640
+ runs-on: ubuntu-26.04
1633
1641
  steps:
1634
1642
  - name: Check out repo
1635
1643
  uses: actions/checkout@v7
@@ -1817,7 +1825,7 @@ name: info
1817
1825
  on: push
1818
1826
  jobs:
1819
1827
  cypress-run:
1820
- runs-on: ubuntu-24.04
1828
+ runs-on: ubuntu-26.04
1821
1829
  steps:
1822
1830
  - name: Checkout
1823
1831
  uses: actions/checkout@v7
@@ -1834,7 +1842,7 @@ name: info
1834
1842
  on: push
1835
1843
  jobs:
1836
1844
  cypress-run:
1837
- runs-on: ubuntu-24.04
1845
+ runs-on: ubuntu-26.04
1838
1846
  steps:
1839
1847
  - name: Checkout
1840
1848
  uses: actions/checkout@v7
@@ -1865,7 +1873,7 @@ on:
1865
1873
  - cron: '0 4 * * *'
1866
1874
  jobs:
1867
1875
  nightly:
1868
- runs-on: ubuntu-24.04
1876
+ runs-on: ubuntu-26.04
1869
1877
  steps:
1870
1878
  - name: Checkout
1871
1879
  uses: actions/checkout@v7
@@ -1886,7 +1894,7 @@ name: Summary titles
1886
1894
  on: push
1887
1895
  jobs:
1888
1896
  tests:
1889
- runs-on: ubuntu-24.04
1897
+ runs-on: ubuntu-26.04
1890
1898
  steps:
1891
1899
  - uses: actions/checkout@v7
1892
1900
  - name: Cypress headless tests
@@ -1914,7 +1922,7 @@ name: Example no summary
1914
1922
  on: push
1915
1923
  jobs:
1916
1924
  cypress-run:
1917
- runs-on: ubuntu-24.04
1925
+ runs-on: ubuntu-26.04
1918
1926
  steps:
1919
1927
  - name: Checkout
1920
1928
  uses: actions/checkout@v7
@@ -1949,9 +1957,7 @@ View the [CHANGELOG](./CHANGELOG.md) document for an overview of version changes
1949
1957
  ## Compatibility
1950
1958
 
1951
1959
  - `github-action@v7` is the current recommended version, uses `node24` and is compatible with Cypress `10` and above.
1952
- - `github-action@v6` is deprecated. It uses `node20` which has reached its end of life - see [Deprecation of Node 20 on GitHub Actions runners](https://github.blog/changelog/2025-09-19-deprecation-of-node-20-on-github-actions-runners/).
1953
- - `github-action@v6.7.9` is the minimum version required to use GitHub Actions caching services. The legacy caching service used by lower versions of the action is no longer available.
1954
- - `github-action` versions `v1` to `v5` are unsupported: they rely on Node.js `12` and `16` in End-of-life status.
1960
+ - `github-action` versions `v1` to `v6` are unsupported: they rely on Node.js `12`, `16` or `20` in End-of-life status.
1955
1961
 
1956
1962
  Cypress lists browser compatibility information under [System Requirements](https://docs.cypress.io/app/get-started/install-cypress#Browsers).
1957
1963
 
package/dist/index.js CHANGED
@@ -14465,6 +14465,26 @@ var EXPANSION_MAX = 100000
14465
14465
  // characters) so legitimate input is unaffected.
14466
14466
  var EXPANSION_MAX_LENGTH = 4000000
14467
14467
 
14468
+ // `expand` recurses once per level of brace *nesting* - both when expanding a
14469
+ // set's comma members and when re-wrapping a set whose body is a single part.
14470
+ // The CVE-2026-14257 fix made the *tail* iterative (recursion on `m.post`, one
14471
+ // level per chained group), which left nesting depth unbounded: about 3,100
14472
+ // levels of `{{{...a,b...}}}` - only ~6KB of input - exhausted the native stack
14473
+ // and crashed the process. `EXPANSION_MAX_DEPTH` bounds how deep the parser
14474
+ // will follow nesting. It sits far above any realistic pattern and well below
14475
+ // the depth at which the stack runs out.
14476
+ var EXPANSION_MAX_DEPTH = 1000
14477
+
14478
+ // Bash keeps a quirk where a brace group followed by a comma set still expands
14479
+ // (`{a},b}`). The parser implements it by rewriting the string and restarting
14480
+ // the scan, absorbing one `}` per pass. `n` trailing braces therefore cost `n`
14481
+ // full passes over a string that itself grows by one `escClose` sentinel each
14482
+ // time - quadratic in `n`, with a ~26x constant from the sentinel's length.
14483
+ // 128KB of `'{a}' + '}'.repeat(n) + ',z}'` blocked the event loop for 27
14484
+ // seconds to produce two results. `EXPANSION_MAX_REWRITES` bounds how many
14485
+ // times the scan may restart. Real `{a},b}` input needs a handful.
14486
+ var EXPANSION_MAX_REWRITES = 1000
14487
+
14468
14488
  function numeric(str) {
14469
14489
  return parseInt(str, 10) == str
14470
14490
  ? parseInt(str, 10)
@@ -14488,34 +14508,54 @@ function unescapeBraces(str) {
14488
14508
  }
14489
14509
 
14490
14510
 
14511
+ // Like `target.push(...items)` but doesn't overflow the stack
14512
+ function pushAll(target, items) {
14513
+ for (var i = 0; i < items.length; i++) {
14514
+ target.push(items[i]);
14515
+ }
14516
+ }
14517
+
14491
14518
  // Basically just str.split(","), but handling cases
14492
14519
  // where we have nested braced sections, which should be
14493
14520
  // treated as individual members, like {a,{b,c},d}
14494
14521
  function parseCommaParts(str) {
14495
- if (!str)
14496
- return [''];
14497
-
14498
14522
  var parts = [];
14499
- var m = balanced('{', '}', str);
14500
14523
 
14501
- if (!m)
14502
- return str.split(',');
14524
+ // Walk the brace groups iteratively. Recursing on `post` once per group let a
14525
+ // chain of them exhaust the stack - the parsing-side counterpart to
14526
+ // the `expand` overflow fixed for CVE-2026-14257, and not something `max` or
14527
+ // `maxLength` can bound, since it happens before expansion.
14528
+ //
14529
+ // The part the next chunk continues
14530
+ var carry = '';
14503
14531
 
14504
- var pre = m.pre;
14505
- var body = m.body;
14506
- var post = m.post;
14507
- var p = pre.split(',');
14532
+ for (;;) {
14533
+ var m = balanced('{', '}', str);
14508
14534
 
14509
- p[p.length-1] += '{' + body + '}';
14510
- var postParts = parseCommaParts(post);
14511
- if (post.length) {
14512
- p[p.length-1] += postParts.shift();
14513
- p.push.apply(p, postParts);
14514
- }
14535
+ if (!m) {
14536
+ var tail = str.split(',');
14537
+ tail[0] = carry + tail[0];
14538
+ pushAll(parts, tail);
14539
+ return parts;
14540
+ }
14515
14541
 
14516
- parts.push.apply(parts, p);
14542
+ var pre = m.pre;
14543
+ var body = m.body;
14544
+ var post = m.post;
14545
+ var p = pre.split(',');
14517
14546
 
14518
- return parts;
14547
+ p[0] = carry + p[0];
14548
+ p[p.length-1] += '{' + body + '}';
14549
+
14550
+ if (!post.length) {
14551
+ pushAll(parts, p);
14552
+ return parts;
14553
+ }
14554
+
14555
+ carry = p.pop();
14556
+ pushAll(parts, p);
14557
+ str = post;
14558
+ }
14519
14559
  }
14520
14560
 
14521
14561
  function expandTop(str, options) {
@@ -14525,6 +14565,8 @@ function expandTop(str, options) {
14525
14565
  options = options || {};
14526
14566
  var max = options.max == null ? EXPANSION_MAX : options.max;
14527
14567
  var maxLength = options.maxLength == null ? EXPANSION_MAX_LENGTH : options.maxLength;
14568
+ var maxDepth = options.maxDepth == null ? EXPANSION_MAX_DEPTH : options.maxDepth;
14569
+ var maxRewrites = options.maxRewrites == null ? EXPANSION_MAX_REWRITES : options.maxRewrites;
14528
14570
 
14529
14571
  // I don't know why Bash 4.3 does this, but it does.
14530
14572
  // Anything starting with {} will have the first two bytes preserved
@@ -14536,7 +14578,7 @@ function expandTop(str, options) {
14536
14578
  str = '\\{\\}' + str.substr(2);
14537
14579
  }
14538
14580
 
14539
- return expand(escapeBraces(str), max, maxLength, true).map(unescapeBraces);
14581
+ return expand(escapeBraces(str), max, maxLength, maxDepth, 0, maxRewrites, true).map(unescapeBraces);
14540
14582
  }
14541
14583
 
14542
14584
  function identity(e) {
@@ -14660,8 +14702,18 @@ function expand(
14660
14702
  str,
14661
14703
  max,
14662
14704
  maxLength,
14705
+ maxDepth,
14706
+ depth,
14707
+ maxRewrites,
14663
14708
  isTop
14664
14709
  ) {
14710
+ // Too deeply nested to keep following: treat the rest as literal, the same
14711
+ // way a group that cannot expand is already handled. Truncating rather than
14712
+ // throwing keeps expansion total, matching `max` and `maxLength`.
14713
+ if (depth > maxDepth) {
14714
+ return [str];
14715
+ }
14716
+
14665
14717
  // Consume the string's top-level brace groups left to right, threading a
14666
14718
  // running set of combined prefixes (`acc`). Expanding the tail iteratively -
14667
14719
  // rather than recursing on `m.post` once per group - keeps the native stack
@@ -14682,6 +14734,9 @@ function expand(
14682
14734
  // `accBase[a]` records how much of `acc[a]` predates the current run;
14683
14735
  // `combine` treats an expansion as empty when it adds nothing past that.
14684
14736
  var accBase = [0]
14737
+ // How many times the `{a},b}` rewrite below has restarted the scan. Each pass
14738
+ // re-reads the whole string, so leaving this unbounded is quadratic.
14739
+ var rewrites = 0
14685
14740
  var dropEmpties = false
14686
14741
  var firstGroup = true
14687
14742
  var nextBase
@@ -14713,7 +14768,8 @@ function expand(
14713
14768
  var isOptions = m.body.indexOf(',') >= 0;
14714
14769
  if (!isSequence && !isOptions) {
14715
14770
  // {a},b}
14716
- if (m.post.match(/,(?!,).*\}/)) {
14771
+ if (rewrites < maxRewrites && m.post.match(/,(?!,).*\}/)) {
14772
+ rewrites++;
14717
14773
  str = m.pre + '{' + m.body + escClose + m.post;
14718
14774
  // The rewritten string is expanded as if it were a fresh top-level one,
14719
14775
  // so start a new empty-drop run: anchor the baseline at what `acc`
@@ -14752,7 +14808,7 @@ function expand(
14752
14808
  var n = parseCommaParts(m.body);
14753
14809
  if (n.length === 1 && n[0] !== undefined) {
14754
14810
  // x{{a,b}}y ==> x{a}y x{b}y
14755
- n = expand(n[0], max, maxLength, false).map(embrace);
14811
+ n = expand(n[0], max, maxLength, maxDepth, depth + 1, maxRewrites, false).map(embrace);
14756
14812
  //XXX is this necessary? Can't seem to hit it in tests.
14757
14813
  /* c8 ignore start */
14758
14814
  if (n.length === 1) {
@@ -14791,7 +14847,7 @@ function expand(
14791
14847
  values = []
14792
14848
  var valuesLength = 0
14793
14849
  outer: for (var j = 0; j < n.length; j++) {
14794
- var expanded = expand(n[j], max, maxLength, false)
14850
+ var expanded = expand(n[j], max, maxLength, maxDepth, depth + 1, maxRewrites, false)
14795
14851
  for (var k = 0; k < expanded.length; k++) {
14796
14852
  var v = expanded[k]
14797
14853
  if (dropsEmpties && !v) continue
@@ -29789,7 +29845,7 @@ async function connectH1 (client, socket) {
29789
29845
 
29790
29846
  function clearIdleSocketValidation (socket) {
29791
29847
  if (socket[kIdleSocketValidationTimeout]) {
29792
- clearTimeout(socket[kIdleSocketValidationTimeout])
29848
+ clearImmediate(socket[kIdleSocketValidationTimeout])
29793
29849
  socket[kIdleSocketValidationTimeout] = null
29794
29850
  }
29795
29851
 
@@ -29798,15 +29854,23 @@ function clearIdleSocketValidation (socket) {
29798
29854
 
29799
29855
  function scheduleIdleSocketValidation (client, socket) {
29800
29856
  socket[kIdleSocketValidation] = 1
29801
- socket[kIdleSocketValidationTimeout] = setTimeout(() => {
29857
+ // Yield to the check phase (after poll) so unsolicited bytes / FIN / RST
29858
+ // already pending on this idle keep-alive socket are processed before the
29859
+ // next request is written (GHSA-35p6-xmwp-9g52).
29860
+ //
29861
+ // setTimeout(0) pays Node's ~1ms timer floor on every sequential reuse
29862
+ // (#5493). setImmediate avoids that, but an *unref'd* Immediate lets poll
29863
+ // block for ~500ms when the event loop is otherwise idle (#5600 / #5606).
29864
+ // A ref'd Immediate both keeps the pending request alive and makes poll
29865
+ // return immediately — the hybrid those issues asked for.
29866
+ socket[kIdleSocketValidationTimeout] = setImmediate(() => {
29802
29867
  socket[kIdleSocketValidationTimeout] = null
29803
29868
  socket[kIdleSocketValidation] = 2
29804
29869
 
29805
29870
  if (client[kSocket] === socket && !socket.destroyed) {
29806
29871
  client[kResume]()
29807
29872
  }
29808
- }, 0)
29809
- socket[kIdleSocketValidationTimeout].unref?.()
29873
+ })
29810
29874
  }
29811
29875
 
29812
29876
  /**
@@ -33478,6 +33542,7 @@ class RetryHandler {
33478
33542
  this.end = null
33479
33543
  this.etag = null
33480
33544
  this.resume = null
33545
+ this.headersSent = false
33481
33546
 
33482
33547
  // Handle possible onConnect duplication
33483
33548
  this.handler.onConnect(reason => {
@@ -33490,6 +33555,20 @@ class RetryHandler {
33490
33555
  })
33491
33556
  }
33492
33557
 
33558
+ checkpointResponseEnd (headers, resume) {
33559
+ if (this.end == null && this.opts.method !== 'HEAD') {
33560
+ const contentLength = headers['content-length']
33561
+ this.end = contentLength != null ? Number(contentLength) - 1 : null
33562
+
33563
+ assert(
33564
+ this.end == null || Number.isFinite(this.end),
33565
+ 'invalid content-length'
33566
+ )
33567
+ }
33568
+
33569
+ this.resume = this.end != null ? resume : null
33570
+ }
33571
+
33493
33572
  onRequestSent () {
33494
33573
  if (this.handler.onRequestSent) {
33495
33574
  this.handler.onRequestSent()
@@ -33579,6 +33658,8 @@ class RetryHandler {
33579
33658
 
33580
33659
  if (statusCode >= 300) {
33581
33660
  if (this.retryOpts.statusCodes.includes(statusCode) === false) {
33661
+ this.headersSent = true
33662
+ this.checkpointResponseEnd(headers, resume)
33582
33663
  return this.handler.onHeaders(
33583
33664
  statusCode,
33584
33665
  rawHeaders,
@@ -33647,8 +33728,15 @@ class RetryHandler {
33647
33728
 
33648
33729
  const { start, size, end = size - 1 } = contentRange
33649
33730
 
33650
- assert(this.start === start, 'content-range mismatch')
33651
- assert(this.end == null || this.end === end, 'content-range mismatch')
33731
+ if (this.start !== start || (this.end != null && this.end !== end)) {
33732
+ this.abort(
33733
+ new RequestRetryError('Content-Range mismatch', statusCode, {
33734
+ headers,
33735
+ data: { count: this.retryCount }
33736
+ })
33737
+ )
33738
+ return false
33739
+ }
33652
33740
 
33653
33741
  this.resume = resume
33654
33742
  return true
@@ -33660,6 +33748,7 @@ class RetryHandler {
33660
33748
  const range = parseRangeHeader(headers['content-range'])
33661
33749
 
33662
33750
  if (range == null) {
33751
+ this.headersSent = true
33663
33752
  return this.handler.onHeaders(
33664
33753
  statusCode,
33665
33754
  rawHeaders,
@@ -33698,6 +33787,7 @@ class RetryHandler {
33698
33787
  )
33699
33788
 
33700
33789
  this.resume = resume
33790
+ this.headersSent = true
33701
33791
  this.etag = headers.etag != null ? headers.etag : null
33702
33792
 
33703
33793
  // Weak etags are not useful for comparison nor cache
@@ -33737,7 +33827,7 @@ class RetryHandler {
33737
33827
  }
33738
33828
 
33739
33829
  onError (err) {
33740
- if (this.aborted || isDisturbed(this.opts.body)) {
33830
+ if (this.aborted || isDisturbed(this.opts.body) || (this.headersSent && this.resume == null)) {
33741
33831
  return this.handler.onError(err)
33742
33832
  }
33743
33833
 
@@ -38223,6 +38313,49 @@ const COLON = 0x3A
38223
38313
  */
38224
38314
  const SPACE = 0x20
38225
38315
 
38316
+ const DATA = Buffer.from('data')
38317
+ const EVENT = Buffer.from('event')
38318
+ const ID = Buffer.from('id')
38319
+ const RETRY = Buffer.from('retry')
38320
+
38321
+ function isASCIINumberBytes (buffer, start) {
38322
+ if (start >= buffer.length) {
38323
+ return false
38324
+ }
38325
+
38326
+ for (let i = start; i < buffer.length; i++) {
38327
+ if (buffer[i] < 0x30 || buffer[i] > 0x39) {
38328
+ return false
38329
+ }
38330
+ }
38331
+
38332
+ return true
38333
+ }
38334
+
38335
+ function isValidLastEventIdBytes (buffer, start) {
38336
+ for (let i = start; i < buffer.length; i++) {
38337
+ if (buffer[i] === 0x00) {
38338
+ return false
38339
+ }
38340
+ }
38341
+
38342
+ return true
38343
+ }
38344
+
38345
+ function isFieldName (line, length, field) {
38346
+ if (length !== field.length) {
38347
+ return false
38348
+ }
38349
+
38350
+ for (let i = 0; i < length; i++) {
38351
+ if (line[i] !== field[i]) {
38352
+ return false
38353
+ }
38354
+ }
38355
+
38356
+ return true
38357
+ }
38358
+
38226
38359
  /**
38227
38360
  * @typedef {object} EventSourceStreamEvent
38228
38361
  * @type {object}
@@ -38263,11 +38396,14 @@ class EventSourceStream extends Transform {
38263
38396
  eventEndCheck = false
38264
38397
 
38265
38398
  /**
38266
- * @type {Buffer}
38399
+ * @type {Buffer[]}
38267
38400
  */
38268
- buffer = null
38401
+ chunks = []
38269
38402
 
38403
+ chunkIndex = 0
38270
38404
  pos = 0
38405
+ lineChunkIndex = 0
38406
+ linePos = 0
38271
38407
 
38272
38408
  event = {
38273
38409
  data: undefined,
@@ -38306,92 +38442,20 @@ class EventSourceStream extends Transform {
38306
38442
  return
38307
38443
  }
38308
38444
 
38309
- // Cache the chunk in the buffer, as the data might not be complete while
38310
- // processing it
38311
- // TODO: Investigate if there is a more performant way to handle
38312
- // incoming chunks
38313
- // see: https://github.com/nodejs/undici/issues/2630
38314
- if (this.buffer) {
38315
- this.buffer = Buffer.concat([this.buffer, chunk])
38316
- } else {
38317
- this.buffer = chunk
38318
- }
38445
+ this.chunks.push(chunk)
38319
38446
 
38320
38447
  // Strip leading byte-order-mark if we opened the stream and started
38321
38448
  // the processing of the incoming data
38322
38449
  if (this.checkBOM) {
38323
- switch (this.buffer.length) {
38324
- case 1:
38325
- // Check if the first byte is the same as the first byte of the BOM
38326
- if (this.buffer[0] === BOM[0]) {
38327
- // If it is, we need to wait for more data
38328
- callback()
38329
- return
38330
- }
38331
- // Set the checkBOM flag to false as we don't need to check for the
38332
- // BOM anymore
38333
- this.checkBOM = false
38334
-
38335
- // The buffer only contains one byte so we need to wait for more data
38336
- callback()
38337
- return
38338
- case 2:
38339
- // Check if the first two bytes are the same as the first two bytes
38340
- // of the BOM
38341
- if (
38342
- this.buffer[0] === BOM[0] &&
38343
- this.buffer[1] === BOM[1]
38344
- ) {
38345
- // If it is, we need to wait for more data, because the third byte
38346
- // is needed to determine if it is the BOM or not
38347
- callback()
38348
- return
38349
- }
38350
-
38351
- // Set the checkBOM flag to false as we don't need to check for the
38352
- // BOM anymore
38353
- this.checkBOM = false
38354
- break
38355
- case 3:
38356
- // Check if the first three bytes are the same as the first three
38357
- // bytes of the BOM
38358
- if (
38359
- this.buffer[0] === BOM[0] &&
38360
- this.buffer[1] === BOM[1] &&
38361
- this.buffer[2] === BOM[2]
38362
- ) {
38363
- // If it is, we can drop the buffered data, as it is only the BOM
38364
- this.buffer = Buffer.alloc(0)
38365
- // Set the checkBOM flag to false as we don't need to check for the
38366
- // BOM anymore
38367
- this.checkBOM = false
38368
-
38369
- // Await more data
38370
- callback()
38371
- return
38372
- }
38373
- // If it is not the BOM, we can start processing the data
38374
- this.checkBOM = false
38375
- break
38376
- default:
38377
- // The buffer is longer than 3 bytes, so we can drop the BOM if it is
38378
- // present
38379
- if (
38380
- this.buffer[0] === BOM[0] &&
38381
- this.buffer[1] === BOM[1] &&
38382
- this.buffer[2] === BOM[2]
38383
- ) {
38384
- // Remove the BOM from the buffer
38385
- this.buffer = this.buffer.subarray(3)
38386
- }
38387
-
38388
- // Set the checkBOM flag to false as we don't need to check for the
38389
- this.checkBOM = false
38390
- break
38450
+ if (this.handleBOM()) {
38451
+ callback()
38452
+ return
38391
38453
  }
38392
38454
  }
38393
38455
 
38394
- while (this.pos < this.buffer.length) {
38456
+ while (this.hasCurrentByte()) {
38457
+ const byte = this.currentByte()
38458
+
38395
38459
  // If the previous line ended with an end-of-line, we need to check
38396
38460
  // if the next character is also an end-of-line.
38397
38461
  if (this.eventEndCheck) {
@@ -38404,10 +38468,9 @@ class EventSourceStream extends Transform {
38404
38468
  if (this.crlfCheck) {
38405
38469
  // If the current character is a line feed, we can remove it
38406
38470
  // from the buffer and reset the crlfCheck flag
38407
- if (this.buffer[this.pos] === LF) {
38408
- this.buffer = this.buffer.subarray(this.pos + 1)
38409
- this.pos = 0
38471
+ if (byte === LF) {
38410
38472
  this.crlfCheck = false
38473
+ this.consumeCurrentByte()
38411
38474
 
38412
38475
  // It is possible that the line feed is not the end of the
38413
38476
  // event. We need to check if the next character is an
@@ -38423,19 +38486,17 @@ class EventSourceStream extends Transform {
38423
38486
  this.crlfCheck = false
38424
38487
  }
38425
38488
 
38426
- if (this.buffer[this.pos] === LF || this.buffer[this.pos] === CR) {
38489
+ if (byte === LF || byte === CR) {
38427
38490
  // If the current character is a carriage return, we need to
38428
38491
  // set the crlfCheck flag to true, as we need to check if the
38429
38492
  // next character is a line feed so we can remove it from the
38430
38493
  // buffer
38431
- if (this.buffer[this.pos] === CR) {
38494
+ if (byte === CR) {
38432
38495
  this.crlfCheck = true
38433
38496
  }
38434
38497
 
38435
- this.buffer = this.buffer.subarray(this.pos + 1)
38436
- this.pos = 0
38437
- if (
38438
- this.event.data !== undefined || this.event.event || this.event.id || this.event.retry) {
38498
+ this.consumeCurrentByte()
38499
+ if (this.hasPendingEvent()) {
38439
38500
  this.processEvent(this.event)
38440
38501
  }
38441
38502
  this.clearEvent()
@@ -38449,22 +38510,18 @@ class EventSourceStream extends Transform {
38449
38510
 
38450
38511
  // If the current character is an end-of-line, we can process the
38451
38512
  // line
38452
- if (this.buffer[this.pos] === LF || this.buffer[this.pos] === CR) {
38513
+ if (byte === LF || byte === CR) {
38453
38514
  // If the current character is a carriage return, we need to
38454
38515
  // set the crlfCheck flag to true, as we need to check if the
38455
38516
  // next character is a line feed
38456
- if (this.buffer[this.pos] === CR) {
38517
+ if (byte === CR) {
38457
38518
  this.crlfCheck = true
38458
38519
  }
38459
38520
 
38460
38521
  // In any case, we can process the line as we reached an
38461
38522
  // end-of-line character
38462
- this.parseLine(this.buffer.subarray(0, this.pos), this.event)
38463
-
38464
- // Remove the processed line from the buffer
38465
- this.buffer = this.buffer.subarray(this.pos + 1)
38466
- // Reset the position as we removed the processed line from the buffer
38467
- this.pos = 0
38523
+ this.parseLine(this.readLine(), this.event)
38524
+ this.consumeCurrentByte()
38468
38525
  // A line was processed and this could be the end of the event. We need
38469
38526
  // to check if the next line is empty to determine if the event is
38470
38527
  // finished.
@@ -38472,7 +38529,7 @@ class EventSourceStream extends Transform {
38472
38529
  continue
38473
38530
  }
38474
38531
 
38475
- this.pos++
38532
+ this.advanceCursor()
38476
38533
  }
38477
38534
 
38478
38535
  callback()
@@ -38497,64 +38554,53 @@ class EventSourceStream extends Transform {
38497
38554
  return
38498
38555
  }
38499
38556
 
38500
- let field = ''
38501
- let value = ''
38557
+ let fieldLength = line.length
38558
+ let valueStart = line.length
38502
38559
 
38503
38560
  // If the line contains a U+003A COLON character (:)
38504
38561
  if (colonPosition !== -1) {
38505
- // Collect the characters on the line before the first U+003A COLON
38506
- // character (:), and let field be that string.
38507
- // TODO: Investigate if there is a more performant way to extract the
38508
- // field
38509
- // see: https://github.com/nodejs/undici/issues/2630
38510
- field = line.subarray(0, colonPosition).toString('utf8')
38562
+ fieldLength = colonPosition
38511
38563
 
38512
38564
  // Collect the characters on the line after the first U+003A COLON
38513
38565
  // character (:), and let value be that string.
38514
38566
  // If value starts with a U+0020 SPACE character, remove it from value.
38515
- let valueStart = colonPosition + 1
38567
+ valueStart = colonPosition + 1
38516
38568
  if (line[valueStart] === SPACE) {
38517
38569
  ++valueStart
38518
38570
  }
38519
- // TODO: Investigate if there is a more performant way to extract the
38520
- // value
38521
- // see: https://github.com/nodejs/undici/issues/2630
38522
- value = line.subarray(valueStart).toString('utf8')
38571
+ }
38523
38572
 
38524
- // Otherwise, the string is not empty but does not contain a U+003A COLON
38525
- // character (:)
38526
- } else {
38527
- // Process the field using the steps described below, using the whole
38528
- // line as the field name, and the empty string as the field value.
38529
- field = line.toString('utf8')
38530
- value = ''
38531
- }
38532
-
38533
- // Modify the event with the field name and value. The value is also
38534
- // decoded as UTF-8
38535
- switch (field) {
38536
- case 'data':
38537
- if (event[field] === undefined) {
38538
- event[field] = value
38539
- } else {
38540
- event[field] += `\n${value}`
38541
- }
38542
- break
38543
- case 'retry':
38544
- if (isASCIINumber(value)) {
38545
- event[field] = value
38546
- }
38547
- break
38548
- case 'id':
38549
- if (isValidLastEventId(value)) {
38550
- event[field] = value
38551
- }
38552
- break
38553
- case 'event':
38554
- if (value.length > 0) {
38555
- event[field] = value
38556
- }
38557
- break
38573
+ if (isFieldName(line, fieldLength, DATA)) {
38574
+ const value = line.toString('utf8', valueStart)
38575
+
38576
+ if (event.data === undefined) {
38577
+ event.data = value
38578
+ } else {
38579
+ event.data += `\n${value}`
38580
+ }
38581
+ return
38582
+ }
38583
+
38584
+ if (isFieldName(line, fieldLength, RETRY)) {
38585
+ if (isASCIINumberBytes(line, valueStart)) {
38586
+ event.retry = line.toString('utf8', valueStart)
38587
+ }
38588
+ return
38589
+ }
38590
+
38591
+ if (isFieldName(line, fieldLength, ID)) {
38592
+ if (isValidLastEventIdBytes(line, valueStart)) {
38593
+ event.id = line.toString('utf8', valueStart)
38594
+ }
38595
+ return
38596
+ }
38597
+
38598
+ if (isFieldName(line, fieldLength, EVENT)) {
38599
+ const value = line.toString('utf8', valueStart)
38600
+
38601
+ if (value.length > 0) {
38602
+ event.event = value
38603
+ }
38558
38604
  }
38559
38605
  }
38560
38606
 
@@ -38584,13 +38630,152 @@ class EventSourceStream extends Transform {
38584
38630
  }
38585
38631
 
38586
38632
  clearEvent () {
38587
- this.event = {
38588
- data: undefined,
38589
- event: undefined,
38590
- id: undefined,
38591
- retry: undefined
38633
+ this.event.data = undefined
38634
+ this.event.event = undefined
38635
+ this.event.id = undefined
38636
+ this.event.retry = undefined
38637
+ }
38638
+
38639
+ hasPendingEvent () {
38640
+ return this.event.data !== undefined ||
38641
+ this.event.event !== undefined ||
38642
+ this.event.id !== undefined ||
38643
+ this.event.retry !== undefined
38644
+ }
38645
+
38646
+ hasCurrentByte () {
38647
+ return this.chunkIndex < this.chunks.length &&
38648
+ this.pos < this.chunks[this.chunkIndex].length
38649
+ }
38650
+
38651
+ currentByte () {
38652
+ return this.chunks[this.chunkIndex][this.pos]
38653
+ }
38654
+
38655
+ consumeCurrentByte () {
38656
+ this.advanceCursor()
38657
+ this.syncLineStartToCursor()
38658
+ }
38659
+
38660
+ advanceCursor () {
38661
+ this.pos++
38662
+
38663
+ while (this.chunkIndex < this.chunks.length && this.pos >= this.chunks[this.chunkIndex].length) {
38664
+ this.chunkIndex++
38665
+ this.pos = 0
38592
38666
  }
38593
38667
  }
38668
+
38669
+ syncLineStartToCursor () {
38670
+ this.lineChunkIndex = this.chunkIndex
38671
+ this.linePos = this.pos
38672
+ this.dropConsumedChunks()
38673
+ }
38674
+
38675
+ dropConsumedChunks () {
38676
+ while (this.lineChunkIndex > 0) {
38677
+ this.chunks.shift()
38678
+ this.lineChunkIndex--
38679
+ this.chunkIndex--
38680
+ }
38681
+
38682
+ if (this.chunkIndex === this.chunks.length) {
38683
+ this.chunks.length = 0
38684
+ this.chunkIndex = 0
38685
+ this.pos = 0
38686
+ this.lineChunkIndex = 0
38687
+ this.linePos = 0
38688
+ }
38689
+ }
38690
+
38691
+ readLine () {
38692
+ if (this.lineChunkIndex === this.chunkIndex) {
38693
+ return this.chunks[this.chunkIndex].subarray(this.linePos, this.pos)
38694
+ }
38695
+
38696
+ const chunks = []
38697
+ let length = 0
38698
+
38699
+ for (let i = this.lineChunkIndex; i <= this.chunkIndex; i++) {
38700
+ const chunk = this.chunks[i]
38701
+ const start = i === this.lineChunkIndex ? this.linePos : 0
38702
+ const end = i === this.chunkIndex ? this.pos : chunk.length
38703
+ const slice = chunk.subarray(start, end)
38704
+ length += slice.length
38705
+ chunks.push(slice)
38706
+ }
38707
+
38708
+ return Buffer.concat(chunks, length)
38709
+ }
38710
+
38711
+ peekBufferedByte (offset) {
38712
+ let chunkIndex = this.lineChunkIndex
38713
+ let pos = this.linePos
38714
+
38715
+ while (chunkIndex < this.chunks.length) {
38716
+ const chunk = this.chunks[chunkIndex]
38717
+ const remaining = chunk.length - pos
38718
+
38719
+ if (offset < remaining) {
38720
+ return chunk[pos + offset]
38721
+ }
38722
+
38723
+ offset -= remaining
38724
+ chunkIndex++
38725
+ pos = 0
38726
+ }
38727
+ }
38728
+
38729
+ discardLeadingBytes (count) {
38730
+ while (count > 0 && this.lineChunkIndex < this.chunks.length) {
38731
+ const chunk = this.chunks[this.lineChunkIndex]
38732
+ const remaining = chunk.length - this.linePos
38733
+
38734
+ if (count < remaining) {
38735
+ this.linePos += count
38736
+ count = 0
38737
+ } else {
38738
+ count -= remaining
38739
+ this.lineChunkIndex++
38740
+ this.linePos = 0
38741
+ }
38742
+ }
38743
+
38744
+ this.chunkIndex = this.lineChunkIndex
38745
+ this.pos = this.linePos
38746
+ this.dropConsumedChunks()
38747
+ }
38748
+
38749
+ handleBOM () {
38750
+ const first = this.peekBufferedByte(0)
38751
+ const second = this.peekBufferedByte(1)
38752
+ const third = this.peekBufferedByte(2)
38753
+
38754
+ if (second === undefined) {
38755
+ if (first === BOM[0]) {
38756
+ return true
38757
+ }
38758
+
38759
+ this.checkBOM = false
38760
+ return true
38761
+ }
38762
+
38763
+ if (third === undefined) {
38764
+ if (first === BOM[0] && second === BOM[1]) {
38765
+ return true
38766
+ }
38767
+
38768
+ this.checkBOM = false
38769
+ return false
38770
+ }
38771
+
38772
+ if (first === BOM[0] && second === BOM[1] && third === BOM[2]) {
38773
+ this.discardLeadingBytes(3)
38774
+ }
38775
+
38776
+ this.checkBOM = false
38777
+ return !this.hasCurrentByte()
38778
+ }
38594
38779
  }
38595
38780
 
38596
38781
  module.exports = {
@@ -49881,7 +50066,7 @@ function establishWebSocketConnection (url, protocols, client, ws, onEstablish,
49881
50066
  // is specified, the server needs to include the same field and one of
49882
50067
  // the selected subprotocol values in its response for the connection to
49883
50068
  // be established.
49884
- if (!requestProtocols.includes(secProtocol)) {
50069
+ if (requestProtocols === null || !requestProtocols.includes(secProtocol)) {
49885
50070
  failWebsocketConnection(ws, 'Protocol was not set in the opening handshake.')
49886
50071
  return
49887
50072
  }
@@ -50646,7 +50831,12 @@ class PerMessageDeflate {
50646
50831
 
50647
50832
  if (this.#maxPayloadSize > 0 && this.#inflate[kLength] > this.#maxPayloadSize) {
50648
50833
  callback(new MessageSizeExceededError())
50834
+ // The inflater may still hold buffered input that can emit a late
50835
+ // zlib error. Remove the data listener, then deterministically stop
50836
+ // the stream so a subsequent 'error' cannot fire without a listener
50837
+ // (which would terminate the process as an unhandled error event).
50649
50838
  this.#inflate.removeAllListeners()
50839
+ this.#inflate.destroy()
50650
50840
  this.#inflate = null
50651
50841
  return
50652
50842
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cypress/github-action",
3
- "version": "7.4.4",
3
+ "version": "7.4.6",
4
4
  "description": "GitHub Action for running Cypress end-to-end and component tests",
5
5
  "private": false,
6
6
  "main": "dist/index.js",
@@ -62,7 +62,7 @@
62
62
  "globals": "17.11.0",
63
63
  "husky": "9.1.7",
64
64
  "markdown-link-check": "3.15.0",
65
- "prettier": "3.9.6"
65
+ "prettier": "3.9.9"
66
66
  },
67
67
  "publishConfig": {
68
68
  "access": "public"