@youkno/edge-cli 1.21.315 → 1.21.317

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/.pnp.cjs CHANGED
@@ -273,7 +273,7 @@ const RAW_RUNTIME_STATE =
273
273
  ]],\
274
274
  ["@gar/promise-retry", [\
275
275
  ["npm:1.0.2", {\
276
- "packageLocation": "../../../.yarn/berry/cache/@gar-promise-retry-npm-1.0.2-960b209ddf-10c0.zip/node_modules/@gar/promise-retry/",\
276
+ "packageLocation": "../../../../../../.yarn/berry/cache/@gar-promise-retry-npm-1.0.2-960b209ddf-10c0.zip/node_modules/@gar/promise-retry/",\
277
277
  "packageDependencies": [\
278
278
  ["@gar/promise-retry", "npm:1.0.2"],\
279
279
  ["retry", "npm:0.13.1"]\
@@ -283,7 +283,7 @@ const RAW_RUNTIME_STATE =
283
283
  ]],\
284
284
  ["@isaacs/fs-minipass", [\
285
285
  ["npm:4.0.1", {\
286
- "packageLocation": "../../../.yarn/berry/cache/@isaacs-fs-minipass-npm-4.0.1-677026e841-10c0.zip/node_modules/@isaacs/fs-minipass/",\
286
+ "packageLocation": "../../../../../../.yarn/berry/cache/@isaacs-fs-minipass-npm-4.0.1-677026e841-10c0.zip/node_modules/@isaacs/fs-minipass/",\
287
287
  "packageDependencies": [\
288
288
  ["@isaacs/fs-minipass", "npm:4.0.1"],\
289
289
  ["minipass", "npm:7.1.3"]\
@@ -293,7 +293,7 @@ const RAW_RUNTIME_STATE =
293
293
  ]],\
294
294
  ["@npmcli/agent", [\
295
295
  ["npm:4.0.0", {\
296
- "packageLocation": "../../../.yarn/berry/cache/@npmcli-agent-npm-4.0.0-502e5ae4f0-10c0.zip/node_modules/@npmcli/agent/",\
296
+ "packageLocation": "../../../../../../.yarn/berry/cache/@npmcli-agent-npm-4.0.0-502e5ae4f0-10c0.zip/node_modules/@npmcli/agent/",\
297
297
  "packageDependencies": [\
298
298
  ["@npmcli/agent", "npm:4.0.0"],\
299
299
  ["agent-base", "npm:7.1.4"],\
@@ -307,7 +307,7 @@ const RAW_RUNTIME_STATE =
307
307
  ]],\
308
308
  ["@npmcli/fs", [\
309
309
  ["npm:5.0.0", {\
310
- "packageLocation": "../../../.yarn/berry/cache/@npmcli-fs-npm-5.0.0-9d737ae2f3-10c0.zip/node_modules/@npmcli/fs/",\
310
+ "packageLocation": "../../../../../../.yarn/berry/cache/@npmcli-fs-npm-5.0.0-9d737ae2f3-10c0.zip/node_modules/@npmcli/fs/",\
311
311
  "packageDependencies": [\
312
312
  ["@npmcli/fs", "npm:5.0.0"],\
313
313
  ["semver", "npm:7.7.4"]\
@@ -317,7 +317,7 @@ const RAW_RUNTIME_STATE =
317
317
  ]],\
318
318
  ["@types/node", [\
319
319
  ["npm:24.12.0", {\
320
- "packageLocation": "../../../.yarn/berry/cache/@types-node-npm-24.12.0-ce6de09e0d-10c0.zip/node_modules/@types/node/",\
320
+ "packageLocation": "../../../../../../.yarn/berry/cache/@types-node-npm-24.12.0-ce6de09e0d-10c0.zip/node_modules/@types/node/",\
321
321
  "packageDependencies": [\
322
322
  ["@types/node", "npm:24.12.0"],\
323
323
  ["undici-types", "npm:7.16.0"]\
@@ -340,7 +340,7 @@ const RAW_RUNTIME_STATE =
340
340
  ]],\
341
341
  ["abbrev", [\
342
342
  ["npm:4.0.0", {\
343
- "packageLocation": "../../../.yarn/berry/cache/abbrev-npm-4.0.0-7d848a1ef0-10c0.zip/node_modules/abbrev/",\
343
+ "packageLocation": "../../../../../../.yarn/berry/cache/abbrev-npm-4.0.0-7d848a1ef0-10c0.zip/node_modules/abbrev/",\
344
344
  "packageDependencies": [\
345
345
  ["abbrev", "npm:4.0.0"]\
346
346
  ],\
@@ -349,7 +349,7 @@ const RAW_RUNTIME_STATE =
349
349
  ]],\
350
350
  ["agent-base", [\
351
351
  ["npm:7.1.4", {\
352
- "packageLocation": "../../../.yarn/berry/cache/agent-base-npm-7.1.4-cb8b4604d5-10c0.zip/node_modules/agent-base/",\
352
+ "packageLocation": "../../../../../../.yarn/berry/cache/agent-base-npm-7.1.4-cb8b4604d5-10c0.zip/node_modules/agent-base/",\
353
353
  "packageDependencies": [\
354
354
  ["agent-base", "npm:7.1.4"]\
355
355
  ],\
@@ -358,7 +358,7 @@ const RAW_RUNTIME_STATE =
358
358
  ]],\
359
359
  ["balanced-match", [\
360
360
  ["npm:4.0.4", {\
361
- "packageLocation": "../../../.yarn/berry/cache/balanced-match-npm-4.0.4-fd666b3c7f-10c0.zip/node_modules/balanced-match/",\
361
+ "packageLocation": "../../../../../../.yarn/berry/cache/balanced-match-npm-4.0.4-fd666b3c7f-10c0.zip/node_modules/balanced-match/",\
362
362
  "packageDependencies": [\
363
363
  ["balanced-match", "npm:4.0.4"]\
364
364
  ],\
@@ -367,7 +367,7 @@ const RAW_RUNTIME_STATE =
367
367
  ]],\
368
368
  ["brace-expansion", [\
369
369
  ["npm:5.0.4", {\
370
- "packageLocation": "../../../.yarn/berry/cache/brace-expansion-npm-5.0.4-acb9332524-10c0.zip/node_modules/brace-expansion/",\
370
+ "packageLocation": "../../../../../../.yarn/berry/cache/brace-expansion-npm-5.0.4-acb9332524-10c0.zip/node_modules/brace-expansion/",\
371
371
  "packageDependencies": [\
372
372
  ["balanced-match", "npm:4.0.4"],\
373
373
  ["brace-expansion", "npm:5.0.4"]\
@@ -377,7 +377,7 @@ const RAW_RUNTIME_STATE =
377
377
  ]],\
378
378
  ["cacache", [\
379
379
  ["npm:20.0.3", {\
380
- "packageLocation": "../../../.yarn/berry/cache/cacache-npm-20.0.3-5f244d5bdd-10c0.zip/node_modules/cacache/",\
380
+ "packageLocation": "../../../../../../.yarn/berry/cache/cacache-npm-20.0.3-5f244d5bdd-10c0.zip/node_modules/cacache/",\
381
381
  "packageDependencies": [\
382
382
  ["@npmcli/fs", "npm:5.0.0"],\
383
383
  ["cacache", "npm:20.0.3"],\
@@ -397,7 +397,7 @@ const RAW_RUNTIME_STATE =
397
397
  ]],\
398
398
  ["chownr", [\
399
399
  ["npm:3.0.0", {\
400
- "packageLocation": "../../../.yarn/berry/cache/chownr-npm-3.0.0-5275e85d25-10c0.zip/node_modules/chownr/",\
400
+ "packageLocation": "../../../../../../.yarn/berry/cache/chownr-npm-3.0.0-5275e85d25-10c0.zip/node_modules/chownr/",\
401
401
  "packageDependencies": [\
402
402
  ["chownr", "npm:3.0.0"]\
403
403
  ],\
@@ -406,7 +406,7 @@ const RAW_RUNTIME_STATE =
406
406
  ]],\
407
407
  ["commander", [\
408
408
  ["npm:14.0.3", {\
409
- "packageLocation": "../../../.yarn/berry/cache/commander-npm-14.0.3-93ab31471d-10c0.zip/node_modules/commander/",\
409
+ "packageLocation": "../../../../../../.yarn/berry/cache/commander-npm-14.0.3-93ab31471d-10c0.zip/node_modules/commander/",\
410
410
  "packageDependencies": [\
411
411
  ["commander", "npm:14.0.3"]\
412
412
  ],\
@@ -415,14 +415,14 @@ const RAW_RUNTIME_STATE =
415
415
  ]],\
416
416
  ["debug", [\
417
417
  ["npm:4.4.3", {\
418
- "packageLocation": "../../../.yarn/berry/cache/debug-npm-4.4.3-0105c6123a-10c0.zip/node_modules/debug/",\
418
+ "packageLocation": "../../../../../../.yarn/berry/cache/debug-npm-4.4.3-0105c6123a-10c0.zip/node_modules/debug/",\
419
419
  "packageDependencies": [\
420
420
  ["debug", "npm:4.4.3"]\
421
421
  ],\
422
422
  "linkType": "SOFT"\
423
423
  }],\
424
424
  ["virtual:643ed7cc338bcf145a82d8b05b3bef6bcf150ca545df386225596f10ce53cc90b88b3ca83e348ade1ccea5f3f8e76c92d2f0e2ba544da60d40aff9921c56872d#npm:4.4.3", {\
425
- "packageLocation": "./.yarn/__virtual__/debug-virtual-5da9fc757d/4/.yarn/berry/cache/debug-npm-4.4.3-0105c6123a-10c0.zip/node_modules/debug/",\
425
+ "packageLocation": "./.yarn/__virtual__/debug-virtual-5da9fc757d/7/.yarn/berry/cache/debug-npm-4.4.3-0105c6123a-10c0.zip/node_modules/debug/",\
426
426
  "packageDependencies": [\
427
427
  ["@types/supports-color", null],\
428
428
  ["debug", "virtual:643ed7cc338bcf145a82d8b05b3bef6bcf150ca545df386225596f10ce53cc90b88b3ca83e348ade1ccea5f3f8e76c92d2f0e2ba544da60d40aff9921c56872d#npm:4.4.3"],\
@@ -438,7 +438,7 @@ const RAW_RUNTIME_STATE =
438
438
  ]],\
439
439
  ["env-paths", [\
440
440
  ["npm:2.2.1", {\
441
- "packageLocation": "../../../.yarn/berry/cache/env-paths-npm-2.2.1-7c7577428c-10c0.zip/node_modules/env-paths/",\
441
+ "packageLocation": "../../../../../../.yarn/berry/cache/env-paths-npm-2.2.1-7c7577428c-10c0.zip/node_modules/env-paths/",\
442
442
  "packageDependencies": [\
443
443
  ["env-paths", "npm:2.2.1"]\
444
444
  ],\
@@ -482,7 +482,7 @@ const RAW_RUNTIME_STATE =
482
482
  ]],\
483
483
  ["exponential-backoff", [\
484
484
  ["npm:3.1.3", {\
485
- "packageLocation": "../../../.yarn/berry/cache/exponential-backoff-npm-3.1.3-28be78d98e-10c0.zip/node_modules/exponential-backoff/",\
485
+ "packageLocation": "../../../../../../.yarn/berry/cache/exponential-backoff-npm-3.1.3-28be78d98e-10c0.zip/node_modules/exponential-backoff/",\
486
486
  "packageDependencies": [\
487
487
  ["exponential-backoff", "npm:3.1.3"]\
488
488
  ],\
@@ -491,14 +491,14 @@ const RAW_RUNTIME_STATE =
491
491
  ]],\
492
492
  ["fdir", [\
493
493
  ["npm:6.5.0", {\
494
- "packageLocation": "../../../.yarn/berry/cache/fdir-npm-6.5.0-8814a0dec7-10c0.zip/node_modules/fdir/",\
494
+ "packageLocation": "../../../../../../.yarn/berry/cache/fdir-npm-6.5.0-8814a0dec7-10c0.zip/node_modules/fdir/",\
495
495
  "packageDependencies": [\
496
496
  ["fdir", "npm:6.5.0"]\
497
497
  ],\
498
498
  "linkType": "SOFT"\
499
499
  }],\
500
500
  ["virtual:0e783aadbd2b4b8e6f6056033c0b290501892d23bc7c5dad5477e00e48ad8bd3e4434c3962a52dd75a58e06dbb7218094a494bac954ef2f7f6fdb65d9717e5f4#npm:6.5.0", {\
501
- "packageLocation": "./.yarn/__virtual__/fdir-virtual-abd4ab2082/4/.yarn/berry/cache/fdir-npm-6.5.0-8814a0dec7-10c0.zip/node_modules/fdir/",\
501
+ "packageLocation": "./.yarn/__virtual__/fdir-virtual-abd4ab2082/7/.yarn/berry/cache/fdir-npm-6.5.0-8814a0dec7-10c0.zip/node_modules/fdir/",\
502
502
  "packageDependencies": [\
503
503
  ["@types/picomatch", null],\
504
504
  ["fdir", "virtual:0e783aadbd2b4b8e6f6056033c0b290501892d23bc7c5dad5477e00e48ad8bd3e4434c3962a52dd75a58e06dbb7218094a494bac954ef2f7f6fdb65d9717e5f4#npm:6.5.0"],\
@@ -513,7 +513,7 @@ const RAW_RUNTIME_STATE =
513
513
  ]],\
514
514
  ["fs-minipass", [\
515
515
  ["npm:3.0.3", {\
516
- "packageLocation": "../../../.yarn/berry/cache/fs-minipass-npm-3.0.3-d148d6ac19-10c0.zip/node_modules/fs-minipass/",\
516
+ "packageLocation": "../../../../../../.yarn/berry/cache/fs-minipass-npm-3.0.3-d148d6ac19-10c0.zip/node_modules/fs-minipass/",\
517
517
  "packageDependencies": [\
518
518
  ["fs-minipass", "npm:3.0.3"],\
519
519
  ["minipass", "npm:7.1.3"]\
@@ -533,7 +533,7 @@ const RAW_RUNTIME_STATE =
533
533
  ]],\
534
534
  ["get-tsconfig", [\
535
535
  ["npm:4.13.6", {\
536
- "packageLocation": "../../../.yarn/berry/cache/get-tsconfig-npm-4.13.6-58e6ff95d9-10c0.zip/node_modules/get-tsconfig/",\
536
+ "packageLocation": "../../../../../../.yarn/berry/cache/get-tsconfig-npm-4.13.6-58e6ff95d9-10c0.zip/node_modules/get-tsconfig/",\
537
537
  "packageDependencies": [\
538
538
  ["get-tsconfig", "npm:4.13.6"],\
539
539
  ["resolve-pkg-maps", "npm:1.0.0"]\
@@ -543,7 +543,7 @@ const RAW_RUNTIME_STATE =
543
543
  ]],\
544
544
  ["glob", [\
545
545
  ["npm:13.0.6", {\
546
- "packageLocation": "../../../.yarn/berry/cache/glob-npm-13.0.6-864eb0cece-10c0.zip/node_modules/glob/",\
546
+ "packageLocation": "../../../../../../.yarn/berry/cache/glob-npm-13.0.6-864eb0cece-10c0.zip/node_modules/glob/",\
547
547
  "packageDependencies": [\
548
548
  ["glob", "npm:13.0.6"],\
549
549
  ["minimatch", "npm:10.2.4"],\
@@ -555,7 +555,7 @@ const RAW_RUNTIME_STATE =
555
555
  ]],\
556
556
  ["graceful-fs", [\
557
557
  ["npm:4.2.11", {\
558
- "packageLocation": "../../../.yarn/berry/cache/graceful-fs-npm-4.2.11-24bb648a68-10c0.zip/node_modules/graceful-fs/",\
558
+ "packageLocation": "../../../../../../.yarn/berry/cache/graceful-fs-npm-4.2.11-24bb648a68-10c0.zip/node_modules/graceful-fs/",\
559
559
  "packageDependencies": [\
560
560
  ["graceful-fs", "npm:4.2.11"]\
561
561
  ],\
@@ -564,7 +564,7 @@ const RAW_RUNTIME_STATE =
564
564
  ]],\
565
565
  ["http-cache-semantics", [\
566
566
  ["npm:4.2.0", {\
567
- "packageLocation": "../../../.yarn/berry/cache/http-cache-semantics-npm-4.2.0-fadacfb3ad-10c0.zip/node_modules/http-cache-semantics/",\
567
+ "packageLocation": "../../../../../../.yarn/berry/cache/http-cache-semantics-npm-4.2.0-fadacfb3ad-10c0.zip/node_modules/http-cache-semantics/",\
568
568
  "packageDependencies": [\
569
569
  ["http-cache-semantics", "npm:4.2.0"]\
570
570
  ],\
@@ -573,7 +573,7 @@ const RAW_RUNTIME_STATE =
573
573
  ]],\
574
574
  ["http-proxy-agent", [\
575
575
  ["npm:7.0.2", {\
576
- "packageLocation": "../../../.yarn/berry/cache/http-proxy-agent-npm-7.0.2-643ed7cc33-10c0.zip/node_modules/http-proxy-agent/",\
576
+ "packageLocation": "../../../../../../.yarn/berry/cache/http-proxy-agent-npm-7.0.2-643ed7cc33-10c0.zip/node_modules/http-proxy-agent/",\
577
577
  "packageDependencies": [\
578
578
  ["agent-base", "npm:7.1.4"],\
579
579
  ["debug", "virtual:643ed7cc338bcf145a82d8b05b3bef6bcf150ca545df386225596f10ce53cc90b88b3ca83e348ade1ccea5f3f8e76c92d2f0e2ba544da60d40aff9921c56872d#npm:4.4.3"],\
@@ -584,7 +584,7 @@ const RAW_RUNTIME_STATE =
584
584
  ]],\
585
585
  ["https-proxy-agent", [\
586
586
  ["npm:7.0.6", {\
587
- "packageLocation": "../../../.yarn/berry/cache/https-proxy-agent-npm-7.0.6-27a95c2690-10c0.zip/node_modules/https-proxy-agent/",\
587
+ "packageLocation": "../../../../../../.yarn/berry/cache/https-proxy-agent-npm-7.0.6-27a95c2690-10c0.zip/node_modules/https-proxy-agent/",\
588
588
  "packageDependencies": [\
589
589
  ["agent-base", "npm:7.1.4"],\
590
590
  ["debug", "virtual:643ed7cc338bcf145a82d8b05b3bef6bcf150ca545df386225596f10ce53cc90b88b3ca83e348ade1ccea5f3f8e76c92d2f0e2ba544da60d40aff9921c56872d#npm:4.4.3"],\
@@ -595,7 +595,7 @@ const RAW_RUNTIME_STATE =
595
595
  ]],\
596
596
  ["iconv-lite", [\
597
597
  ["npm:0.7.2", {\
598
- "packageLocation": "../../../.yarn/berry/cache/iconv-lite-npm-0.7.2-716fc012a0-10c0.zip/node_modules/iconv-lite/",\
598
+ "packageLocation": "../../../../../../.yarn/berry/cache/iconv-lite-npm-0.7.2-716fc012a0-10c0.zip/node_modules/iconv-lite/",\
599
599
  "packageDependencies": [\
600
600
  ["iconv-lite", "npm:0.7.2"],\
601
601
  ["safer-buffer", "npm:2.1.2"]\
@@ -605,7 +605,7 @@ const RAW_RUNTIME_STATE =
605
605
  ]],\
606
606
  ["imurmurhash", [\
607
607
  ["npm:0.1.4", {\
608
- "packageLocation": "../../../.yarn/berry/cache/imurmurhash-npm-0.1.4-610c5068a0-10c0.zip/node_modules/imurmurhash/",\
608
+ "packageLocation": "../../../../../../.yarn/berry/cache/imurmurhash-npm-0.1.4-610c5068a0-10c0.zip/node_modules/imurmurhash/",\
609
609
  "packageDependencies": [\
610
610
  ["imurmurhash", "npm:0.1.4"]\
611
611
  ],\
@@ -614,7 +614,7 @@ const RAW_RUNTIME_STATE =
614
614
  ]],\
615
615
  ["ip-address", [\
616
616
  ["npm:10.1.0", {\
617
- "packageLocation": "../../../.yarn/berry/cache/ip-address-npm-10.1.0-d5d5693401-10c0.zip/node_modules/ip-address/",\
617
+ "packageLocation": "../../../../../../.yarn/berry/cache/ip-address-npm-10.1.0-d5d5693401-10c0.zip/node_modules/ip-address/",\
618
618
  "packageDependencies": [\
619
619
  ["ip-address", "npm:10.1.0"]\
620
620
  ],\
@@ -623,7 +623,7 @@ const RAW_RUNTIME_STATE =
623
623
  ]],\
624
624
  ["isexe", [\
625
625
  ["npm:4.0.0", {\
626
- "packageLocation": "../../../.yarn/berry/cache/isexe-npm-4.0.0-588229ad74-10c0.zip/node_modules/isexe/",\
626
+ "packageLocation": "../../../../../../.yarn/berry/cache/isexe-npm-4.0.0-588229ad74-10c0.zip/node_modules/isexe/",\
627
627
  "packageDependencies": [\
628
628
  ["isexe", "npm:4.0.0"]\
629
629
  ],\
@@ -632,7 +632,7 @@ const RAW_RUNTIME_STATE =
632
632
  ]],\
633
633
  ["lru-cache", [\
634
634
  ["npm:11.2.6", {\
635
- "packageLocation": "../../../.yarn/berry/cache/lru-cache-npm-11.2.6-acb7d4323e-10c0.zip/node_modules/lru-cache/",\
635
+ "packageLocation": "../../../../../../.yarn/berry/cache/lru-cache-npm-11.2.6-acb7d4323e-10c0.zip/node_modules/lru-cache/",\
636
636
  "packageDependencies": [\
637
637
  ["lru-cache", "npm:11.2.6"]\
638
638
  ],\
@@ -641,7 +641,7 @@ const RAW_RUNTIME_STATE =
641
641
  ]],\
642
642
  ["make-fetch-happen", [\
643
643
  ["npm:15.0.4", {\
644
- "packageLocation": "../../../.yarn/berry/cache/make-fetch-happen-npm-15.0.4-cd90f16f9b-10c0.zip/node_modules/make-fetch-happen/",\
644
+ "packageLocation": "../../../../../../.yarn/berry/cache/make-fetch-happen-npm-15.0.4-cd90f16f9b-10c0.zip/node_modules/make-fetch-happen/",\
645
645
  "packageDependencies": [\
646
646
  ["@gar/promise-retry", "npm:1.0.2"],\
647
647
  ["@npmcli/agent", "npm:4.0.0"],\
@@ -661,7 +661,7 @@ const RAW_RUNTIME_STATE =
661
661
  ]],\
662
662
  ["minimatch", [\
663
663
  ["npm:10.2.4", {\
664
- "packageLocation": "../../../.yarn/berry/cache/minimatch-npm-10.2.4-11f0605299-10c0.zip/node_modules/minimatch/",\
664
+ "packageLocation": "../../../../../../.yarn/berry/cache/minimatch-npm-10.2.4-11f0605299-10c0.zip/node_modules/minimatch/",\
665
665
  "packageDependencies": [\
666
666
  ["brace-expansion", "npm:5.0.4"],\
667
667
  ["minimatch", "npm:10.2.4"]\
@@ -671,7 +671,7 @@ const RAW_RUNTIME_STATE =
671
671
  ]],\
672
672
  ["minipass", [\
673
673
  ["npm:3.3.6", {\
674
- "packageLocation": "../../../.yarn/berry/cache/minipass-npm-3.3.6-b8d93a945b-10c0.zip/node_modules/minipass/",\
674
+ "packageLocation": "../../../../../../.yarn/berry/cache/minipass-npm-3.3.6-b8d93a945b-10c0.zip/node_modules/minipass/",\
675
675
  "packageDependencies": [\
676
676
  ["minipass", "npm:3.3.6"],\
677
677
  ["yallist", "npm:4.0.0"]\
@@ -679,7 +679,7 @@ const RAW_RUNTIME_STATE =
679
679
  "linkType": "HARD"\
680
680
  }],\
681
681
  ["npm:7.1.3", {\
682
- "packageLocation": "../../../.yarn/berry/cache/minipass-npm-7.1.3-b73a16498d-10c0.zip/node_modules/minipass/",\
682
+ "packageLocation": "../../../../../../.yarn/berry/cache/minipass-npm-7.1.3-b73a16498d-10c0.zip/node_modules/minipass/",\
683
683
  "packageDependencies": [\
684
684
  ["minipass", "npm:7.1.3"]\
685
685
  ],\
@@ -688,7 +688,7 @@ const RAW_RUNTIME_STATE =
688
688
  ]],\
689
689
  ["minipass-collect", [\
690
690
  ["npm:2.0.1", {\
691
- "packageLocation": "../../../.yarn/berry/cache/minipass-collect-npm-2.0.1-73d3907e40-10c0.zip/node_modules/minipass-collect/",\
691
+ "packageLocation": "../../../../../../.yarn/berry/cache/minipass-collect-npm-2.0.1-73d3907e40-10c0.zip/node_modules/minipass-collect/",\
692
692
  "packageDependencies": [\
693
693
  ["minipass", "npm:7.1.3"],\
694
694
  ["minipass-collect", "npm:2.0.1"]\
@@ -698,7 +698,7 @@ const RAW_RUNTIME_STATE =
698
698
  ]],\
699
699
  ["minipass-fetch", [\
700
700
  ["npm:5.0.2", {\
701
- "packageLocation": "../../../.yarn/berry/cache/minipass-fetch-npm-5.0.2-cd03eefed8-10c0.zip/node_modules/minipass-fetch/",\
701
+ "packageLocation": "../../../../../../.yarn/berry/cache/minipass-fetch-npm-5.0.2-cd03eefed8-10c0.zip/node_modules/minipass-fetch/",\
702
702
  "packageDependencies": [\
703
703
  ["iconv-lite", "npm:0.7.2"],\
704
704
  ["minipass", "npm:7.1.3"],\
@@ -711,7 +711,7 @@ const RAW_RUNTIME_STATE =
711
711
  ]],\
712
712
  ["minipass-flush", [\
713
713
  ["npm:1.0.5", {\
714
- "packageLocation": "../../../.yarn/berry/cache/minipass-flush-npm-1.0.5-efe79d9826-10c0.zip/node_modules/minipass-flush/",\
714
+ "packageLocation": "../../../../../../.yarn/berry/cache/minipass-flush-npm-1.0.5-efe79d9826-10c0.zip/node_modules/minipass-flush/",\
715
715
  "packageDependencies": [\
716
716
  ["minipass", "npm:3.3.6"],\
717
717
  ["minipass-flush", "npm:1.0.5"]\
@@ -721,7 +721,7 @@ const RAW_RUNTIME_STATE =
721
721
  ]],\
722
722
  ["minipass-pipeline", [\
723
723
  ["npm:1.2.4", {\
724
- "packageLocation": "../../../.yarn/berry/cache/minipass-pipeline-npm-1.2.4-5924cb077f-10c0.zip/node_modules/minipass-pipeline/",\
724
+ "packageLocation": "../../../../../../.yarn/berry/cache/minipass-pipeline-npm-1.2.4-5924cb077f-10c0.zip/node_modules/minipass-pipeline/",\
725
725
  "packageDependencies": [\
726
726
  ["minipass", "npm:3.3.6"],\
727
727
  ["minipass-pipeline", "npm:1.2.4"]\
@@ -731,7 +731,7 @@ const RAW_RUNTIME_STATE =
731
731
  ]],\
732
732
  ["minipass-sized", [\
733
733
  ["npm:2.0.0", {\
734
- "packageLocation": "../../../.yarn/berry/cache/minipass-sized-npm-2.0.0-a911fc7d3f-10c0.zip/node_modules/minipass-sized/",\
734
+ "packageLocation": "../../../../../../.yarn/berry/cache/minipass-sized-npm-2.0.0-a911fc7d3f-10c0.zip/node_modules/minipass-sized/",\
735
735
  "packageDependencies": [\
736
736
  ["minipass", "npm:7.1.3"],\
737
737
  ["minipass-sized", "npm:2.0.0"]\
@@ -741,7 +741,7 @@ const RAW_RUNTIME_STATE =
741
741
  ]],\
742
742
  ["minizlib", [\
743
743
  ["npm:3.1.0", {\
744
- "packageLocation": "../../../.yarn/berry/cache/minizlib-npm-3.1.0-6680befdba-10c0.zip/node_modules/minizlib/",\
744
+ "packageLocation": "../../../../../../.yarn/berry/cache/minizlib-npm-3.1.0-6680befdba-10c0.zip/node_modules/minizlib/",\
745
745
  "packageDependencies": [\
746
746
  ["minipass", "npm:7.1.3"],\
747
747
  ["minizlib", "npm:3.1.0"]\
@@ -751,7 +751,7 @@ const RAW_RUNTIME_STATE =
751
751
  ]],\
752
752
  ["ms", [\
753
753
  ["npm:2.1.3", {\
754
- "packageLocation": "../../../.yarn/berry/cache/ms-npm-2.1.3-81ff3cfac1-10c0.zip/node_modules/ms/",\
754
+ "packageLocation": "../../../../../../.yarn/berry/cache/ms-npm-2.1.3-81ff3cfac1-10c0.zip/node_modules/ms/",\
755
755
  "packageDependencies": [\
756
756
  ["ms", "npm:2.1.3"]\
757
757
  ],\
@@ -760,7 +760,7 @@ const RAW_RUNTIME_STATE =
760
760
  ]],\
761
761
  ["negotiator", [\
762
762
  ["npm:1.0.0", {\
763
- "packageLocation": "../../../.yarn/berry/cache/negotiator-npm-1.0.0-47d727e27e-10c0.zip/node_modules/negotiator/",\
763
+ "packageLocation": "../../../../../../.yarn/berry/cache/negotiator-npm-1.0.0-47d727e27e-10c0.zip/node_modules/negotiator/",\
764
764
  "packageDependencies": [\
765
765
  ["negotiator", "npm:1.0.0"]\
766
766
  ],\
@@ -788,7 +788,7 @@ const RAW_RUNTIME_STATE =
788
788
  ]],\
789
789
  ["nopt", [\
790
790
  ["npm:9.0.0", {\
791
- "packageLocation": "../../../.yarn/berry/cache/nopt-npm-9.0.0-81316ec15c-10c0.zip/node_modules/nopt/",\
791
+ "packageLocation": "../../../../../../.yarn/berry/cache/nopt-npm-9.0.0-81316ec15c-10c0.zip/node_modules/nopt/",\
792
792
  "packageDependencies": [\
793
793
  ["abbrev", "npm:4.0.0"],\
794
794
  ["nopt", "npm:9.0.0"]\
@@ -798,7 +798,7 @@ const RAW_RUNTIME_STATE =
798
798
  ]],\
799
799
  ["p-map", [\
800
800
  ["npm:7.0.4", {\
801
- "packageLocation": "../../../.yarn/berry/cache/p-map-npm-7.0.4-39386109d0-10c0.zip/node_modules/p-map/",\
801
+ "packageLocation": "../../../../../../.yarn/berry/cache/p-map-npm-7.0.4-39386109d0-10c0.zip/node_modules/p-map/",\
802
802
  "packageDependencies": [\
803
803
  ["p-map", "npm:7.0.4"]\
804
804
  ],\
@@ -807,7 +807,7 @@ const RAW_RUNTIME_STATE =
807
807
  ]],\
808
808
  ["path-scurry", [\
809
809
  ["npm:2.0.2", {\
810
- "packageLocation": "../../../.yarn/berry/cache/path-scurry-npm-2.0.2-f10aa6a77e-10c0.zip/node_modules/path-scurry/",\
810
+ "packageLocation": "../../../../../../.yarn/berry/cache/path-scurry-npm-2.0.2-f10aa6a77e-10c0.zip/node_modules/path-scurry/",\
811
811
  "packageDependencies": [\
812
812
  ["lru-cache", "npm:11.2.6"],\
813
813
  ["minipass", "npm:7.1.3"],\
@@ -818,7 +818,7 @@ const RAW_RUNTIME_STATE =
818
818
  ]],\
819
819
  ["picomatch", [\
820
820
  ["npm:4.0.3", {\
821
- "packageLocation": "../../../.yarn/berry/cache/picomatch-npm-4.0.3-0a647b87cc-10c0.zip/node_modules/picomatch/",\
821
+ "packageLocation": "../../../../../../.yarn/berry/cache/picomatch-npm-4.0.3-0a647b87cc-10c0.zip/node_modules/picomatch/",\
822
822
  "packageDependencies": [\
823
823
  ["picomatch", "npm:4.0.3"]\
824
824
  ],\
@@ -827,7 +827,7 @@ const RAW_RUNTIME_STATE =
827
827
  ]],\
828
828
  ["proc-log", [\
829
829
  ["npm:6.1.0", {\
830
- "packageLocation": "../../../.yarn/berry/cache/proc-log-npm-6.1.0-84e609b3f4-10c0.zip/node_modules/proc-log/",\
830
+ "packageLocation": "../../../../../../.yarn/berry/cache/proc-log-npm-6.1.0-84e609b3f4-10c0.zip/node_modules/proc-log/",\
831
831
  "packageDependencies": [\
832
832
  ["proc-log", "npm:6.1.0"]\
833
833
  ],\
@@ -836,7 +836,7 @@ const RAW_RUNTIME_STATE =
836
836
  ]],\
837
837
  ["resolve-pkg-maps", [\
838
838
  ["npm:1.0.0", {\
839
- "packageLocation": "../../../.yarn/berry/cache/resolve-pkg-maps-npm-1.0.0-135b70c854-10c0.zip/node_modules/resolve-pkg-maps/",\
839
+ "packageLocation": "../../../../../../.yarn/berry/cache/resolve-pkg-maps-npm-1.0.0-135b70c854-10c0.zip/node_modules/resolve-pkg-maps/",\
840
840
  "packageDependencies": [\
841
841
  ["resolve-pkg-maps", "npm:1.0.0"]\
842
842
  ],\
@@ -845,7 +845,7 @@ const RAW_RUNTIME_STATE =
845
845
  ]],\
846
846
  ["retry", [\
847
847
  ["npm:0.13.1", {\
848
- "packageLocation": "../../../.yarn/berry/cache/retry-npm-0.13.1-89eb100ab6-10c0.zip/node_modules/retry/",\
848
+ "packageLocation": "../../../../../../.yarn/berry/cache/retry-npm-0.13.1-89eb100ab6-10c0.zip/node_modules/retry/",\
849
849
  "packageDependencies": [\
850
850
  ["retry", "npm:0.13.1"]\
851
851
  ],\
@@ -854,7 +854,7 @@ const RAW_RUNTIME_STATE =
854
854
  ]],\
855
855
  ["safer-buffer", [\
856
856
  ["npm:2.1.2", {\
857
- "packageLocation": "../../../.yarn/berry/cache/safer-buffer-npm-2.1.2-8d5c0b705e-10c0.zip/node_modules/safer-buffer/",\
857
+ "packageLocation": "../../../../../../.yarn/berry/cache/safer-buffer-npm-2.1.2-8d5c0b705e-10c0.zip/node_modules/safer-buffer/",\
858
858
  "packageDependencies": [\
859
859
  ["safer-buffer", "npm:2.1.2"]\
860
860
  ],\
@@ -863,7 +863,7 @@ const RAW_RUNTIME_STATE =
863
863
  ]],\
864
864
  ["semver", [\
865
865
  ["npm:7.7.4", {\
866
- "packageLocation": "../../../.yarn/berry/cache/semver-npm-7.7.4-746e538da5-10c0.zip/node_modules/semver/",\
866
+ "packageLocation": "../../../../../../.yarn/berry/cache/semver-npm-7.7.4-746e538da5-10c0.zip/node_modules/semver/",\
867
867
  "packageDependencies": [\
868
868
  ["semver", "npm:7.7.4"]\
869
869
  ],\
@@ -872,7 +872,7 @@ const RAW_RUNTIME_STATE =
872
872
  ]],\
873
873
  ["smart-buffer", [\
874
874
  ["npm:4.2.0", {\
875
- "packageLocation": "../../../.yarn/berry/cache/smart-buffer-npm-4.2.0-5ac3f668bb-10c0.zip/node_modules/smart-buffer/",\
875
+ "packageLocation": "../../../../../../.yarn/berry/cache/smart-buffer-npm-4.2.0-5ac3f668bb-10c0.zip/node_modules/smart-buffer/",\
876
876
  "packageDependencies": [\
877
877
  ["smart-buffer", "npm:4.2.0"]\
878
878
  ],\
@@ -881,7 +881,7 @@ const RAW_RUNTIME_STATE =
881
881
  ]],\
882
882
  ["socks", [\
883
883
  ["npm:2.8.7", {\
884
- "packageLocation": "../../../.yarn/berry/cache/socks-npm-2.8.7-d1d20aae19-10c0.zip/node_modules/socks/",\
884
+ "packageLocation": "../../../../../../.yarn/berry/cache/socks-npm-2.8.7-d1d20aae19-10c0.zip/node_modules/socks/",\
885
885
  "packageDependencies": [\
886
886
  ["ip-address", "npm:10.1.0"],\
887
887
  ["smart-buffer", "npm:4.2.0"],\
@@ -892,7 +892,7 @@ const RAW_RUNTIME_STATE =
892
892
  ]],\
893
893
  ["socks-proxy-agent", [\
894
894
  ["npm:8.0.5", {\
895
- "packageLocation": "../../../.yarn/berry/cache/socks-proxy-agent-npm-8.0.5-24d77a90dc-10c0.zip/node_modules/socks-proxy-agent/",\
895
+ "packageLocation": "../../../../../../.yarn/berry/cache/socks-proxy-agent-npm-8.0.5-24d77a90dc-10c0.zip/node_modules/socks-proxy-agent/",\
896
896
  "packageDependencies": [\
897
897
  ["agent-base", "npm:7.1.4"],\
898
898
  ["debug", "virtual:643ed7cc338bcf145a82d8b05b3bef6bcf150ca545df386225596f10ce53cc90b88b3ca83e348ade1ccea5f3f8e76c92d2f0e2ba544da60d40aff9921c56872d#npm:4.4.3"],\
@@ -904,7 +904,7 @@ const RAW_RUNTIME_STATE =
904
904
  ]],\
905
905
  ["ssri", [\
906
906
  ["npm:13.0.1", {\
907
- "packageLocation": "../../../.yarn/berry/cache/ssri-npm-13.0.1-c266f2233c-10c0.zip/node_modules/ssri/",\
907
+ "packageLocation": "../../../../../../.yarn/berry/cache/ssri-npm-13.0.1-c266f2233c-10c0.zip/node_modules/ssri/",\
908
908
  "packageDependencies": [\
909
909
  ["minipass", "npm:7.1.3"],\
910
910
  ["ssri", "npm:13.0.1"]\
@@ -914,7 +914,7 @@ const RAW_RUNTIME_STATE =
914
914
  ]],\
915
915
  ["tar", [\
916
916
  ["npm:7.5.10", {\
917
- "packageLocation": "../../../.yarn/berry/cache/tar-npm-7.5.10-83147ff192-10c0.zip/node_modules/tar/",\
917
+ "packageLocation": "../../../../../../.yarn/berry/cache/tar-npm-7.5.10-83147ff192-10c0.zip/node_modules/tar/",\
918
918
  "packageDependencies": [\
919
919
  ["@isaacs/fs-minipass", "npm:4.0.1"],\
920
920
  ["chownr", "npm:3.0.0"],\
@@ -928,7 +928,7 @@ const RAW_RUNTIME_STATE =
928
928
  ]],\
929
929
  ["tinyglobby", [\
930
930
  ["npm:0.2.15", {\
931
- "packageLocation": "../../../.yarn/berry/cache/tinyglobby-npm-0.2.15-0e783aadbd-10c0.zip/node_modules/tinyglobby/",\
931
+ "packageLocation": "../../../../../../.yarn/berry/cache/tinyglobby-npm-0.2.15-0e783aadbd-10c0.zip/node_modules/tinyglobby/",\
932
932
  "packageDependencies": [\
933
933
  ["fdir", "virtual:0e783aadbd2b4b8e6f6056033c0b290501892d23bc7c5dad5477e00e48ad8bd3e4434c3962a52dd75a58e06dbb7218094a494bac954ef2f7f6fdb65d9717e5f4#npm:6.5.0"],\
934
934
  ["picomatch", "npm:4.0.3"],\
@@ -939,7 +939,7 @@ const RAW_RUNTIME_STATE =
939
939
  ]],\
940
940
  ["tsx", [\
941
941
  ["npm:4.21.0", {\
942
- "packageLocation": "../../../.yarn/berry/cache/tsx-npm-4.21.0-3bc9626d81-10c0.zip/node_modules/tsx/",\
942
+ "packageLocation": "../../../../../../.yarn/berry/cache/tsx-npm-4.21.0-3bc9626d81-10c0.zip/node_modules/tsx/",\
943
943
  "packageDependencies": [\
944
944
  ["esbuild", "npm:0.27.3"],\
945
945
  ["fsevents", "patch:fsevents@npm%3A2.3.3#optional!builtin<compat/fsevents>::version=2.3.3&hash=df0bf1"],\
@@ -951,7 +951,7 @@ const RAW_RUNTIME_STATE =
951
951
  ]],\
952
952
  ["typescript", [\
953
953
  ["patch:typescript@npm%3A5.9.3#optional!builtin<compat/typescript>::version=5.9.3&hash=5786d5", {\
954
- "packageLocation": "../../../.yarn/berry/cache/typescript-patch-6fda4d02cf-10c0.zip/node_modules/typescript/",\
954
+ "packageLocation": "../../../../../../.yarn/berry/cache/typescript-patch-6fda4d02cf-10c0.zip/node_modules/typescript/",\
955
955
  "packageDependencies": [\
956
956
  ["typescript", "patch:typescript@npm%3A5.9.3#optional!builtin<compat/typescript>::version=5.9.3&hash=5786d5"]\
957
957
  ],\
@@ -960,7 +960,7 @@ const RAW_RUNTIME_STATE =
960
960
  ]],\
961
961
  ["undici-types", [\
962
962
  ["npm:7.16.0", {\
963
- "packageLocation": "../../../.yarn/berry/cache/undici-types-npm-7.16.0-0e23b08124-10c0.zip/node_modules/undici-types/",\
963
+ "packageLocation": "../../../../../../.yarn/berry/cache/undici-types-npm-7.16.0-0e23b08124-10c0.zip/node_modules/undici-types/",\
964
964
  "packageDependencies": [\
965
965
  ["undici-types", "npm:7.16.0"]\
966
966
  ],\
@@ -969,7 +969,7 @@ const RAW_RUNTIME_STATE =
969
969
  ]],\
970
970
  ["unique-filename", [\
971
971
  ["npm:5.0.0", {\
972
- "packageLocation": "../../../.yarn/berry/cache/unique-filename-npm-5.0.0-605f54f18e-10c0.zip/node_modules/unique-filename/",\
972
+ "packageLocation": "../../../../../../.yarn/berry/cache/unique-filename-npm-5.0.0-605f54f18e-10c0.zip/node_modules/unique-filename/",\
973
973
  "packageDependencies": [\
974
974
  ["unique-filename", "npm:5.0.0"],\
975
975
  ["unique-slug", "npm:6.0.0"]\
@@ -979,7 +979,7 @@ const RAW_RUNTIME_STATE =
979
979
  ]],\
980
980
  ["unique-slug", [\
981
981
  ["npm:6.0.0", {\
982
- "packageLocation": "../../../.yarn/berry/cache/unique-slug-npm-6.0.0-f26b186e99-10c0.zip/node_modules/unique-slug/",\
982
+ "packageLocation": "../../../../../../.yarn/berry/cache/unique-slug-npm-6.0.0-f26b186e99-10c0.zip/node_modules/unique-slug/",\
983
983
  "packageDependencies": [\
984
984
  ["imurmurhash", "npm:0.1.4"],\
985
985
  ["unique-slug", "npm:6.0.0"]\
@@ -989,7 +989,7 @@ const RAW_RUNTIME_STATE =
989
989
  ]],\
990
990
  ["which", [\
991
991
  ["npm:6.0.1", {\
992
- "packageLocation": "../../../.yarn/berry/cache/which-npm-6.0.1-afc3b2db90-10c0.zip/node_modules/which/",\
992
+ "packageLocation": "../../../../../../.yarn/berry/cache/which-npm-6.0.1-afc3b2db90-10c0.zip/node_modules/which/",\
993
993
  "packageDependencies": [\
994
994
  ["isexe", "npm:4.0.0"],\
995
995
  ["which", "npm:6.0.1"]\
@@ -999,14 +999,14 @@ const RAW_RUNTIME_STATE =
999
999
  ]],\
1000
1000
  ["yallist", [\
1001
1001
  ["npm:4.0.0", {\
1002
- "packageLocation": "../../../.yarn/berry/cache/yallist-npm-4.0.0-b493d9e907-10c0.zip/node_modules/yallist/",\
1002
+ "packageLocation": "../../../../../../.yarn/berry/cache/yallist-npm-4.0.0-b493d9e907-10c0.zip/node_modules/yallist/",\
1003
1003
  "packageDependencies": [\
1004
1004
  ["yallist", "npm:4.0.0"]\
1005
1005
  ],\
1006
1006
  "linkType": "HARD"\
1007
1007
  }],\
1008
1008
  ["npm:5.0.0", {\
1009
- "packageLocation": "../../../.yarn/berry/cache/yallist-npm-5.0.0-8732dd9f1c-10c0.zip/node_modules/yallist/",\
1009
+ "packageLocation": "../../../../../../.yarn/berry/cache/yallist-npm-5.0.0-8732dd9f1c-10c0.zip/node_modules/yallist/",\
1010
1010
  "packageDependencies": [\
1011
1011
  ["yallist", "npm:5.0.0"]\
1012
1012
  ],\
@@ -6718,7 +6718,7 @@ function getPathForDisplay(p) {
6718
6718
  return npath.normalize(npath.fromPortablePath(p));
6719
6719
  }
6720
6720
 
6721
- const [major, minor] = process.versions.node.split(`.`).map((value) => parseInt(value, 10));
6721
+ const [major, minor, patch] = process.versions.node.split(`.`).map((value) => parseInt(value, 10));
6722
6722
  const WATCH_MODE_MESSAGE_USES_ARRAYS = major > 19 || major === 19 && minor >= 2 || major === 18 && minor >= 13;
6723
6723
 
6724
6724
  function readPackageScope(checkPath) {
@@ -6753,9 +6753,9 @@ Instead change the require of ${basename} in ${parentPath} to a dynamic import()
6753
6753
  err.code = `ERR_REQUIRE_ESM`;
6754
6754
  return err;
6755
6755
  }
6756
- function reportRequiredFilesToWatchMode(files) {
6756
+ function reportRequiredFilesToWatchMode(paths) {
6757
6757
  if (process.env.WATCH_REPORT_DEPENDENCIES && process.send) {
6758
- files = files.map((filename) => npath.fromPortablePath(VirtualFS.resolveVirtual(npath.toPortablePath(filename))));
6758
+ const files = paths.map((filename) => npath.fromPortablePath(VirtualFS.resolveVirtual(filename)));
6759
6759
  if (WATCH_MODE_MESSAGE_USES_ARRAYS) {
6760
6760
  process.send({ "watch:require": files });
6761
6761
  } else {
@@ -8398,9 +8398,10 @@ Required by: ${issuerLocator.name}@${issuerLocator.reference} (via ${issuerForDi
8398
8398
  const candidates = [];
8399
8399
  const qualifiedPath = applyNodeExtensionResolution(unqualifiedPath, candidates, { extensions });
8400
8400
  if (qualifiedPath) {
8401
+ reportRequiredFilesToWatchMode([qualifiedPath]);
8401
8402
  return ppath.normalize(qualifiedPath);
8402
8403
  } else {
8403
- reportRequiredFilesToWatchMode(candidates.map((candidate) => npath.fromPortablePath(candidate)));
8404
+ reportRequiredFilesToWatchMode(candidates);
8404
8405
  const unqualifiedPathForDisplay = getPathForDisplay(unqualifiedPath);
8405
8406
  const containingPackage = findPackageLocator(unqualifiedPath);
8406
8407
  if (containingPackage) {
package/.pnp.loader.mjs CHANGED
@@ -1428,11 +1428,12 @@ class VirtualFS extends ProxiedFS {
1428
1428
 
1429
1429
  const URL = Number(process.versions.node.split('.', 1)[0]) < 20 ? URL$1 : globalThis.URL;
1430
1430
 
1431
- const [major, minor] = process.versions.node.split(`.`).map((value) => parseInt(value, 10));
1431
+ const [major, minor, patch] = process.versions.node.split(`.`).map((value) => parseInt(value, 10));
1432
1432
  const WATCH_MODE_MESSAGE_USES_ARRAYS = major > 19 || major === 19 && minor >= 2 || major === 18 && minor >= 13;
1433
1433
  const HAS_LAZY_LOADED_TRANSLATORS = major === 20 && minor < 6 || major === 19 && minor >= 3;
1434
1434
  const SUPPORTS_IMPORT_ATTRIBUTES = major >= 21 || major === 20 && minor >= 10 || major === 18 && minor >= 20;
1435
1435
  const SUPPORTS_IMPORT_ATTRIBUTES_ONLY = major >= 22;
1436
+ const HAS_BROKEN_FSTAT_FOR_ZIP_FDS = major === 26 && minor < 1 || major === 25 && minor >= 7 || major === 24 && minor === 15 || major === 22 && (minor > 22 || minor === 22 && patch >= 3);
1436
1437
 
1437
1438
  function readPackageScope(checkPath) {
1438
1439
  const rootSeparatorIndex = checkPath.indexOf(npath.sep);
@@ -1549,9 +1550,11 @@ async function load$1(urlString, context, nextLoad) {
1549
1550
  "watch:import": WATCH_MODE_MESSAGE_USES_ARRAYS ? [pathToSend] : pathToSend
1550
1551
  });
1551
1552
  }
1553
+ const shouldReadSource = format === `commonjs` && HAS_BROKEN_FSTAT_FOR_ZIP_FDS && filePath.includes(`.zip/`);
1554
+ const source = format !== `commonjs` || shouldReadSource ? await fs.promises.readFile(filePath, `utf8`) : void 0;
1552
1555
  return {
1553
1556
  format,
1554
- source: format === `commonjs` ? void 0 : await fs.promises.readFile(filePath, `utf8`),
1557
+ source,
1555
1558
  shortCircuit: true
1556
1559
  };
1557
1560
  }
Binary file
package/README.md CHANGED
@@ -48,6 +48,10 @@ edge-cli login
48
48
 
49
49
  This opens your browser to the admin sign-in page. After signing in, tokens are saved to `~/.edge-cli-auth/accounts.json`.
50
50
 
51
+ Login creates **two** sessions from the one sign-in: a shell session that drives `edge-cli shell`, and an API-only session that `edge-cli token` prints. Token scope is fixed when the session is created and a refresh re-derives it from the session, so a shell token cannot be narrowed afterwards — the second session is what makes an API-only token possible without a second sign-in.
52
+
53
+ Prefer the API-only token anywhere a token leaves the CLI (Postman, scripts, a colleague's terminal): a `--scope shell` token can run any shell command your account is allowed to, against whatever environment it was issued for. If you logged in before this existed, `edge-cli token` will tell you to log in again rather than hand back the shell-capable one.
54
+
51
55
  ```bash
52
56
  edge-cli login:list # see saved accounts
53
57
  edge-cli login:use <email> # switch default account
@@ -65,9 +69,10 @@ edge-cli health-check
65
69
  edge-cli config
66
70
 
67
71
  # Get an API token (useful for Postman or curl)
68
- edge-cli token
69
- edge-cli token --refresh # force token refresh
70
- edge-cli token --header # print as Authorization header
72
+ edge-cli token # API-only token (aud: edge-api)
73
+ edge-cli token --scope shell # also carries edge-shell; can run shell commands
74
+ edge-cli token --refresh # force token refresh
75
+ edge-cli token --header # print as Authorization header
71
76
 
72
77
  # Run a shell command
73
78
  edge-cli shell "<command>"
@@ -3,17 +3,28 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.registerToken = registerToken;
4
4
  const auth_1 = require("../lib/auth");
5
5
  const config_1 = require("../lib/config");
6
+ const SCOPES = ["api", "shell"];
6
7
  function registerToken(program) {
7
8
  program
8
9
  .command("token")
9
10
  .description("Print a JWT access token for API calls (e.g. Postman)")
10
11
  .option("--refresh", "Force refresh using refresh token when available")
11
12
  .option("--header", "Print as Authorization header line")
13
+ .option("--scope <scope>", `Which token to print: ${SCOPES.join(" | ")}. 'api' carries the edge-api audience only; ` +
14
+ `'shell' also carries edge-shell and can run shell commands`, "api")
12
15
  .action(async function tokenAction(commandOptions) {
13
16
  const parent = this.parent;
14
17
  const opts = (parent?.opts() ?? {});
15
18
  const cfg = await (0, config_1.resolveEffectiveConfig)(opts);
16
- const token = await (0, auth_1.resolveAccessToken)(cfg, Boolean(commandOptions.refresh));
19
+ const requested = (commandOptions.scope ?? "api").toLowerCase();
20
+ if (!SCOPES.includes(requested)) {
21
+ // Refused rather than defaulted: printing a token of a scope nobody asked for is
22
+ // how a shell-capable credential ends up somewhere it was never meant to go.
23
+ throw new Error(`Unknown --scope: ${commandOptions.scope} (expected ${SCOPES.join(" or ")})`);
24
+ }
25
+ const token = requested === "shell"
26
+ ? await (0, auth_1.resolveAccessToken)(cfg, Boolean(commandOptions.refresh))
27
+ : await (0, auth_1.resolveApiAccessToken)(cfg, Boolean(commandOptions.refresh));
17
28
  if (commandOptions.header) {
18
29
  process.stdout.write(`Authorization: Bearer ${token}\n`);
19
30
  return;
package/dist/lib/auth.js CHANGED
@@ -8,6 +8,7 @@ exports.setDefaultLogin = setDefaultLogin;
8
8
  exports.logout = logout;
9
9
  exports.login = login;
10
10
  exports.resolveAccessToken = resolveAccessToken;
11
+ exports.resolveApiAccessToken = resolveApiAccessToken;
11
12
  exports.resolveAuthHeader = resolveAuthHeader;
12
13
  exports.resolveAuthHeaderFast = resolveAuthHeaderFast;
13
14
  const node_fs_1 = __importDefault(require("node:fs"));
@@ -45,6 +46,16 @@ const DEFAULT_DEVICE_NAME = "edge-cli";
45
46
  * exchange.
46
47
  */
47
48
  const EXCHANGE_SCOPE_SHELL = "shell";
49
+ /**
50
+ * The app scope is the *absence* of a scope field -- `TokenScope.fromWire` maps blank to `APP` --
51
+ * so an API-only session is requested by omitting it, not by sending a name for it.
52
+ *
53
+ * `null`, never `undefined`: a default parameter fires when an argument is `undefined`, so passing
54
+ * an `undefined` sentinel to `authExchangeFirebaseToken` silently selected the shell default and
55
+ * every "API-only" session came back with the `edge-shell` audience. `f(null)` does not trigger the
56
+ * default.
57
+ */
58
+ const EXCHANGE_SCOPE_APP = null;
48
59
  function scopeKey(cfg) {
49
60
  return `${cfg.product}/${cfg.env}`;
50
61
  }
@@ -124,6 +135,24 @@ function decodeJwtPayload(token) {
124
135
  return {};
125
136
  }
126
137
  }
138
+ /**
139
+ * The extra audience `TokenScope.SHELL` stamps. Matched by name rather than by "anything that is
140
+ * not the API audience", because the API audience is server-configurable (`api.jwt.audience`) and
141
+ * the CLI cannot know what it was set to.
142
+ */
143
+ const SHELL_AUDIENCE = "edge-shell";
144
+ /**
145
+ * Whether a token can drive the shell.
146
+ *
147
+ * Read from the token rather than inferred from what was requested. Asking for an app-scoped
148
+ * session and checking nothing is how every "API-only" token shipped carrying `edge-shell`: the
149
+ * exchange succeeded, so nothing looked wrong, and the CLI handed out shell credentials for a day.
150
+ */
151
+ function carriesShellAudience(accessToken) {
152
+ const aud = decodeJwtPayload(accessToken).aud;
153
+ const list = Array.isArray(aud) ? aud : typeof aud === "string" ? [aud] : [];
154
+ return list.some((entry) => entry === SHELL_AUDIENCE);
155
+ }
127
156
  function extractEmailFromToken(accessToken) {
128
157
  const payload = decodeJwtPayload(accessToken);
129
158
  const email = payload.email;
@@ -151,12 +180,12 @@ async function requestTokenEndpoint(cfg, endpoint, payload) {
151
180
  }
152
181
  return (await response.json());
153
182
  }
154
- async function authExchangeFirebaseToken(cfg, firebaseToken) {
183
+ async function authExchangeFirebaseToken(cfg, firebaseToken, scope = EXCHANGE_SCOPE_SHELL) {
155
184
  const resp = await requestTokenEndpoint(cfg, "exchange", {
156
185
  firebaseToken,
157
186
  deviceId: authDeviceId(),
158
187
  deviceName: DEFAULT_DEVICE_NAME,
159
- scope: EXCHANGE_SCOPE_SHELL
188
+ ...(scope === null ? {} : { scope })
160
189
  });
161
190
  if (!resp?.accessToken) {
162
191
  throw new Error("Token exchange did not return accessToken");
@@ -222,9 +251,14 @@ async function logout(cfg, email) {
222
251
  if (!account) {
223
252
  throw new Error(`Account not found for ${cfg.product}/${cfg.env}: ${target}`);
224
253
  }
225
- if (account.refreshToken) {
254
+ // Both sessions, or logout leaves the API-only one alive on the server after the CLI has
255
+ // forgotten it -- a session nobody can see and nobody will revoke.
256
+ for (const refreshToken of [account.refreshToken, account.api?.refreshToken]) {
257
+ if (!refreshToken) {
258
+ continue;
259
+ }
226
260
  try {
227
- await authLogoutRefreshToken(cfg, account.refreshToken);
261
+ await authLogoutRefreshToken(cfg, refreshToken);
228
262
  }
229
263
  catch {
230
264
  // best effort
@@ -238,19 +272,44 @@ async function logout(cfg, email) {
238
272
  writeDb(db);
239
273
  return target;
240
274
  }
241
- function storeTokens(cfg, email, tokenResp) {
242
- const db = readDb();
243
- const scope = getScope(db, cfg);
244
- const now = nowEpoch();
245
- scope.accounts[email] = {
275
+ function toSession(tokenResp, now) {
276
+ return {
246
277
  accessToken: tokenResp.accessToken,
247
278
  refreshToken: tokenResp.refreshToken,
248
279
  accessExpEpoch: now + (tokenResp.accessTokenExpiresInSec ?? 0),
249
280
  refreshExpEpoch: tokenResp.refreshToken ? now + (tokenResp.refreshTokenExpiresInSec ?? 0) : 0
250
281
  };
282
+ }
283
+ /**
284
+ * @param apiResp the API-only session, when this call has a fresh one. Omitted on a shell refresh,
285
+ * which must leave any existing `api` session in place -- rewriting the account wholesale would
286
+ * silently drop it and send `edge-cli token` back to "run login again" after every refresh.
287
+ */
288
+ function storeTokens(cfg, email, tokenResp, apiResp) {
289
+ const db = readDb();
290
+ const scope = getScope(db, cfg);
291
+ const now = nowEpoch();
292
+ const existingApi = scope.accounts[email]?.api;
293
+ scope.accounts[email] = {
294
+ ...toSession(tokenResp, now),
295
+ api: apiResp ? toSession(apiResp, now) : existingApi
296
+ };
251
297
  scope.default = email;
252
298
  writeDb(db);
253
299
  }
300
+ /**
301
+ * Replace only the API session, leaving the shell session untouched.
302
+ */
303
+ function storeApiTokens(cfg, email, apiResp) {
304
+ const db = readDb();
305
+ const scope = getScope(db, cfg);
306
+ const account = scope.accounts[email];
307
+ if (!account) {
308
+ return;
309
+ }
310
+ account.api = toSession(apiResp, nowEpoch());
311
+ writeDb(db);
312
+ }
254
313
  function parseCallbackQuery(queryString) {
255
314
  const query = queryString.startsWith("?") ? queryString.slice(1) : queryString;
256
315
  const params = new URLSearchParams(query);
@@ -401,8 +460,13 @@ async function login(cfg) {
401
460
  throw new Error("Authentication callback returned code-based response, exchange not implemented.");
402
461
  }
403
462
  let tokenResp;
463
+ // Kept so the API-only session can be exchanged from the same credential below. The
464
+ // already-first-party branch leaves it undefined: there is no Firebase token to re-exchange,
465
+ // so that path yields a shell session only.
466
+ let firebaseToken;
404
467
  if (parsed.firebaseToken) {
405
- tokenResp = await authExchangeFirebaseToken(cfg, parsed.firebaseToken);
468
+ firebaseToken = parsed.firebaseToken;
469
+ tokenResp = await authExchangeFirebaseToken(cfg, firebaseToken);
406
470
  }
407
471
  else if (parsed.accessToken && parsed.refreshToken) {
408
472
  // Already a first-party pair; nothing to exchange.
@@ -415,15 +479,47 @@ async function login(cfg) {
415
479
  }
416
480
  else if (parsed.accessToken) {
417
481
  // No refresh token alongside it means this is the console's `?jwt=` Firebase token.
418
- tokenResp = await exchangeCallbackToken(cfg, parsed.accessToken);
482
+ firebaseToken = parsed.accessToken;
483
+ tokenResp = await exchangeCallbackToken(cfg, firebaseToken);
419
484
  }
420
485
  if (!tokenResp?.accessToken) {
421
486
  throw new Error("Authentication callback did not include usable token data.");
422
487
  }
423
488
  const email = parsed.email ?? extractEmailFromToken(tokenResp.accessToken);
424
- storeTokens(cfg, email, tokenResp);
489
+ storeTokens(cfg, email, tokenResp, await exchangeApiSession(cfg, firebaseToken));
425
490
  return email;
426
491
  }
492
+ /**
493
+ * Exchange the same Firebase token a second time for an API-only session.
494
+ *
495
+ * Failure is reported and swallowed rather than failing the login: the shell session -- the reason
496
+ * anyone runs this CLI -- already succeeded by this point, and taking the whole login down over the
497
+ * optional half would turn a working setup into a broken one. `edge-cli token` says what to do when
498
+ * the session is missing.
499
+ */
500
+ async function exchangeApiSession(cfg, firebaseToken) {
501
+ if (!firebaseToken) {
502
+ return undefined;
503
+ }
504
+ try {
505
+ const resp = await authExchangeFirebaseToken(cfg, firebaseToken, EXCHANGE_SCOPE_APP);
506
+ if (carriesShellAudience(resp.accessToken)) {
507
+ // Storing it would put a shell-capable token behind `edge-cli token`, which is the one
508
+ // outcome this whole feature exists to prevent. Better no API session than a mislabelled
509
+ // one.
510
+ process.stderr.write("Warning: the server returned a shell-scoped token for an app-scoped exchange; " +
511
+ "discarding it.\n'edge-cli token' will need --scope shell until this is resolved.\n");
512
+ return undefined;
513
+ }
514
+ return resp;
515
+ }
516
+ catch (err) {
517
+ const reason = err instanceof Error ? err.message : String(err);
518
+ process.stderr.write(`Warning: could not create an API-only session (${reason}).\n` +
519
+ `'edge-cli token' will need --scope shell until the next successful login.\n`);
520
+ return undefined;
521
+ }
522
+ }
427
523
  async function validateAccessToken(cfg, accessToken) {
428
524
  const url = new URL(`${cfg.baseUrl.replace(/\/$/, "")}/shell`);
429
525
  url.searchParams.set("cmd", "help");
@@ -496,6 +592,60 @@ async function resolveAccessToken(cfg, forceRefresh = false, skipValidate = fals
496
592
  }
497
593
  return accessToken;
498
594
  }
595
+ /**
596
+ * The account's API-only access token, refreshed when it is at or near expiry.
597
+ *
598
+ * Deliberately does no liveness probe. `validateAccessToken` asks `GET /shell?cmd=help`, which this
599
+ * token is *supposed* to be refused by -- running it here would read a correctly-scoped token as a
600
+ * broken one and refresh it on every call.
601
+ *
602
+ * A missing API session is an error rather than a silent fall back to the shell token: handing back
603
+ * a token with more audiences than the caller asked for is the same silent substitution the server
604
+ * refuses when it will not downgrade a shell request to APP.
605
+ */
606
+ async function resolveApiAccessToken(cfg, forceRefresh = false) {
607
+ const db = readDb();
608
+ const scope = getScope(db, cfg);
609
+ const email = scope.default;
610
+ if (!email) {
611
+ throw new Error(`No JWT session for ${cfg.product}/${cfg.env}. Run 'edge-cli login'.`);
612
+ }
613
+ const account = scope.accounts[email];
614
+ if (!account) {
615
+ throw new Error(`No access token for ${email}. Run 'edge-cli login'.`);
616
+ }
617
+ const api = account.api;
618
+ if (!api?.accessToken) {
619
+ throw new Error(`No API-only session for ${email} on ${cfg.product}/${cfg.env}.\n` +
620
+ `Run 'edge-cli login' to create one, or 'edge-cli token --scope shell' to print the ` +
621
+ `shell-capable token instead (it also drives the shell, so do not paste it elsewhere).`);
622
+ }
623
+ // Checked on read, not only on write, so a session stored by a build that asked for the wrong
624
+ // scope is refused rather than handed out. Those tokens are already on disk in the wild.
625
+ if (carriesShellAudience(api.accessToken)) {
626
+ throw new Error(`The stored API session for ${email} carries the ${SHELL_AUDIENCE} audience, so it is ` +
627
+ `not API-only. Run 'edge-cli login' to replace it.`);
628
+ }
629
+ const expiry = api.accessExpEpoch ?? 0;
630
+ const stale = expiry > 0 && expiry <= nowEpoch() + 60;
631
+ if ((forceRefresh || stale) && api.refreshToken) {
632
+ try {
633
+ const refreshed = await authRefreshToken(cfg, api.refreshToken);
634
+ const merged = {
635
+ accessToken: refreshed.accessToken,
636
+ refreshToken: refreshed.refreshToken || api.refreshToken,
637
+ accessTokenExpiresInSec: refreshed.accessTokenExpiresInSec,
638
+ refreshTokenExpiresInSec: refreshed.refreshTokenExpiresInSec
639
+ };
640
+ storeApiTokens(cfg, email, merged);
641
+ return merged.accessToken;
642
+ }
643
+ catch {
644
+ // Fall through to the stored token; it may still have life left in it.
645
+ }
646
+ }
647
+ return api.accessToken;
648
+ }
499
649
  async function resolveAuthHeader(cfg) {
500
650
  const accessToken = await resolveAccessToken(cfg);
501
651
  return `Bearer ${accessToken}`;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@youkno/edge-cli",
3
- "version": "1.21.315",
3
+ "version": "1.21.317",
4
4
  "description": "Cross-platform Edge CLI",
5
5
  "bin": "dist/index.js",
6
6
  "publishConfig": {
@@ -1,20 +1,43 @@
1
1
  import { Command } from "commander";
2
2
 
3
- import { resolveAccessToken } from "../lib/auth";
3
+ import { resolveAccessToken, resolveApiAccessToken } from "../lib/auth";
4
4
  import { resolveEffectiveConfig } from "../lib/config";
5
5
  import { CliOptions } from "../lib/types";
6
6
 
7
+ const SCOPES = ["api", "shell"] as const;
8
+ type TokenScope = (typeof SCOPES)[number];
9
+
7
10
  export function registerToken(program: Command): void {
8
11
  program
9
12
  .command("token")
10
13
  .description("Print a JWT access token for API calls (e.g. Postman)")
11
14
  .option("--refresh", "Force refresh using refresh token when available")
12
15
  .option("--header", "Print as Authorization header line")
13
- .action(async function tokenAction(this: Command, commandOptions: { refresh?: boolean; header?: boolean }) {
16
+ .option(
17
+ "--scope <scope>",
18
+ `Which token to print: ${SCOPES.join(" | ")}. 'api' carries the edge-api audience only; ` +
19
+ `'shell' also carries edge-shell and can run shell commands`,
20
+ "api"
21
+ )
22
+ .action(async function tokenAction(
23
+ this: Command,
24
+ commandOptions: { refresh?: boolean; header?: boolean; scope?: string }
25
+ ) {
14
26
  const parent = this.parent;
15
27
  const opts = (parent?.opts() ?? {}) as CliOptions;
16
28
  const cfg = await resolveEffectiveConfig(opts);
17
- const token = await resolveAccessToken(cfg, Boolean(commandOptions.refresh));
29
+
30
+ const requested = (commandOptions.scope ?? "api").toLowerCase();
31
+ if (!SCOPES.includes(requested as TokenScope)) {
32
+ // Refused rather than defaulted: printing a token of a scope nobody asked for is
33
+ // how a shell-capable credential ends up somewhere it was never meant to go.
34
+ throw new Error(`Unknown --scope: ${commandOptions.scope} (expected ${SCOPES.join(" or ")})`);
35
+ }
36
+
37
+ const token =
38
+ requested === "shell"
39
+ ? await resolveAccessToken(cfg, Boolean(commandOptions.refresh))
40
+ : await resolveApiAccessToken(cfg, Boolean(commandOptions.refresh));
18
41
 
19
42
  if (commandOptions.header) {
20
43
  process.stdout.write(`Authorization: Bearer ${token}\n`);
package/src/lib/auth.ts CHANGED
@@ -38,13 +38,40 @@ const DEFAULT_DEVICE_NAME = "edge-cli";
38
38
  */
39
39
  const EXCHANGE_SCOPE_SHELL = "shell";
40
40
 
41
- type AuthAccount = {
41
+ /**
42
+ * The app scope is the *absence* of a scope field -- `TokenScope.fromWire` maps blank to `APP` --
43
+ * so an API-only session is requested by omitting it, not by sending a name for it.
44
+ *
45
+ * `null`, never `undefined`: a default parameter fires when an argument is `undefined`, so passing
46
+ * an `undefined` sentinel to `authExchangeFirebaseToken` silently selected the shell default and
47
+ * every "API-only" session came back with the `edge-shell` audience. `f(null)` does not trigger the
48
+ * default.
49
+ */
50
+ const EXCHANGE_SCOPE_APP = null;
51
+
52
+ type AuthSession = {
42
53
  accessToken: string;
43
54
  refreshToken?: string;
44
55
  accessExpEpoch?: number;
45
56
  refreshExpEpoch?: number;
46
57
  };
47
58
 
59
+ type AuthAccount = AuthSession & {
60
+ /**
61
+ * A second session exchanged at login with no scope, so its tokens carry only the `edge-api`
62
+ * audience while the account's main session carries `edge-shell` as well.
63
+ *
64
+ * Two sessions rather than one downgraded token because scope is fixed at exchange time and
65
+ * persisted on `user_session.scope`; refresh re-derives it from the session and ignores the
66
+ * request, so a shell token cannot be narrowed after the fact. Both exchanges reuse the one
67
+ * Firebase token the callback delivered, so this costs an HTTP call rather than a second login.
68
+ *
69
+ * Optional: accounts stored before this existed have no `api` session, and `edge-cli token`
70
+ * says so rather than quietly handing back the shell-capable one.
71
+ */
72
+ api?: AuthSession;
73
+ };
74
+
48
75
  type ScopeData = {
49
76
  default?: string;
50
77
  accounts: Record<string, AuthAccount>;
@@ -149,6 +176,26 @@ function decodeJwtPayload(token: string): Record<string, unknown> {
149
176
  }
150
177
  }
151
178
 
179
+ /**
180
+ * The extra audience `TokenScope.SHELL` stamps. Matched by name rather than by "anything that is
181
+ * not the API audience", because the API audience is server-configurable (`api.jwt.audience`) and
182
+ * the CLI cannot know what it was set to.
183
+ */
184
+ const SHELL_AUDIENCE = "edge-shell";
185
+
186
+ /**
187
+ * Whether a token can drive the shell.
188
+ *
189
+ * Read from the token rather than inferred from what was requested. Asking for an app-scoped
190
+ * session and checking nothing is how every "API-only" token shipped carrying `edge-shell`: the
191
+ * exchange succeeded, so nothing looked wrong, and the CLI handed out shell credentials for a day.
192
+ */
193
+ function carriesShellAudience(accessToken: string): boolean {
194
+ const aud = decodeJwtPayload(accessToken).aud;
195
+ const list = Array.isArray(aud) ? aud : typeof aud === "string" ? [aud] : [];
196
+ return list.some((entry) => entry === SHELL_AUDIENCE);
197
+ }
198
+
152
199
  function extractEmailFromToken(accessToken: string): string {
153
200
  const payload = decodeJwtPayload(accessToken);
154
201
  const email = payload.email;
@@ -185,12 +232,16 @@ async function requestTokenEndpoint(
185
232
  return (await response.json()) as TokenResponse;
186
233
  }
187
234
 
188
- async function authExchangeFirebaseToken(cfg: EffectiveConfig, firebaseToken: string): Promise<TokenResponse> {
235
+ async function authExchangeFirebaseToken(
236
+ cfg: EffectiveConfig,
237
+ firebaseToken: string,
238
+ scope: string | null = EXCHANGE_SCOPE_SHELL
239
+ ): Promise<TokenResponse> {
189
240
  const resp = await requestTokenEndpoint(cfg, "exchange", {
190
241
  firebaseToken,
191
242
  deviceId: authDeviceId(),
192
243
  deviceName: DEFAULT_DEVICE_NAME,
193
- scope: EXCHANGE_SCOPE_SHELL
244
+ ...(scope === null ? {} : { scope })
194
245
  });
195
246
  if (!resp?.accessToken) {
196
247
  throw new Error("Token exchange did not return accessToken");
@@ -261,9 +312,14 @@ export async function logout(cfg: EffectiveConfig, email?: string): Promise<stri
261
312
  throw new Error(`Account not found for ${cfg.product}/${cfg.env}: ${target}`);
262
313
  }
263
314
 
264
- if (account.refreshToken) {
315
+ // Both sessions, or logout leaves the API-only one alive on the server after the CLI has
316
+ // forgotten it -- a session nobody can see and nobody will revoke.
317
+ for (const refreshToken of [account.refreshToken, account.api?.refreshToken]) {
318
+ if (!refreshToken) {
319
+ continue;
320
+ }
265
321
  try {
266
- await authLogoutRefreshToken(cfg, account.refreshToken);
322
+ await authLogoutRefreshToken(cfg, refreshToken);
267
323
  } catch {
268
324
  // best effort
269
325
  }
@@ -278,21 +334,53 @@ export async function logout(cfg: EffectiveConfig, email?: string): Promise<stri
278
334
  return target;
279
335
  }
280
336
 
281
- function storeTokens(cfg: EffectiveConfig, email: string, tokenResp: TokenResponse): void {
337
+ function toSession(tokenResp: TokenResponse, now: number): AuthSession {
338
+ return {
339
+ accessToken: tokenResp.accessToken,
340
+ refreshToken: tokenResp.refreshToken,
341
+ accessExpEpoch: now + (tokenResp.accessTokenExpiresInSec ?? 0),
342
+ refreshExpEpoch: tokenResp.refreshToken ? now + (tokenResp.refreshTokenExpiresInSec ?? 0) : 0
343
+ };
344
+ }
345
+
346
+ /**
347
+ * @param apiResp the API-only session, when this call has a fresh one. Omitted on a shell refresh,
348
+ * which must leave any existing `api` session in place -- rewriting the account wholesale would
349
+ * silently drop it and send `edge-cli token` back to "run login again" after every refresh.
350
+ */
351
+ function storeTokens(
352
+ cfg: EffectiveConfig,
353
+ email: string,
354
+ tokenResp: TokenResponse,
355
+ apiResp?: TokenResponse
356
+ ): void {
282
357
  const db = readDb();
283
358
  const scope = getScope(db, cfg);
284
359
  const now = nowEpoch();
360
+ const existingApi = scope.accounts[email]?.api;
285
361
 
286
362
  scope.accounts[email] = {
287
- accessToken: tokenResp.accessToken,
288
- refreshToken: tokenResp.refreshToken,
289
- accessExpEpoch: now + (tokenResp.accessTokenExpiresInSec ?? 0),
290
- refreshExpEpoch: tokenResp.refreshToken ? now + (tokenResp.refreshTokenExpiresInSec ?? 0) : 0
363
+ ...toSession(tokenResp, now),
364
+ api: apiResp ? toSession(apiResp, now) : existingApi
291
365
  };
292
366
  scope.default = email;
293
367
  writeDb(db);
294
368
  }
295
369
 
370
+ /**
371
+ * Replace only the API session, leaving the shell session untouched.
372
+ */
373
+ function storeApiTokens(cfg: EffectiveConfig, email: string, apiResp: TokenResponse): void {
374
+ const db = readDb();
375
+ const scope = getScope(db, cfg);
376
+ const account = scope.accounts[email];
377
+ if (!account) {
378
+ return;
379
+ }
380
+ account.api = toSession(apiResp, nowEpoch());
381
+ writeDb(db);
382
+ }
383
+
296
384
  function parseCallbackQuery(queryString: string): {
297
385
  email?: string;
298
386
  accessToken?: string;
@@ -464,8 +552,13 @@ export async function login(cfg: EffectiveConfig): Promise<string> {
464
552
  }
465
553
 
466
554
  let tokenResp: TokenResponse | undefined;
555
+ // Kept so the API-only session can be exchanged from the same credential below. The
556
+ // already-first-party branch leaves it undefined: there is no Firebase token to re-exchange,
557
+ // so that path yields a shell session only.
558
+ let firebaseToken: string | undefined;
467
559
  if (parsed.firebaseToken) {
468
- tokenResp = await authExchangeFirebaseToken(cfg, parsed.firebaseToken);
560
+ firebaseToken = parsed.firebaseToken;
561
+ tokenResp = await authExchangeFirebaseToken(cfg, firebaseToken);
469
562
  } else if (parsed.accessToken && parsed.refreshToken) {
470
563
  // Already a first-party pair; nothing to exchange.
471
564
  tokenResp = {
@@ -476,7 +569,8 @@ export async function login(cfg: EffectiveConfig): Promise<string> {
476
569
  };
477
570
  } else if (parsed.accessToken) {
478
571
  // No refresh token alongside it means this is the console's `?jwt=` Firebase token.
479
- tokenResp = await exchangeCallbackToken(cfg, parsed.accessToken);
572
+ firebaseToken = parsed.accessToken;
573
+ tokenResp = await exchangeCallbackToken(cfg, firebaseToken);
480
574
  }
481
575
 
482
576
  if (!tokenResp?.accessToken) {
@@ -484,10 +578,48 @@ export async function login(cfg: EffectiveConfig): Promise<string> {
484
578
  }
485
579
 
486
580
  const email = parsed.email ?? extractEmailFromToken(tokenResp.accessToken);
487
- storeTokens(cfg, email, tokenResp);
581
+ storeTokens(cfg, email, tokenResp, await exchangeApiSession(cfg, firebaseToken));
488
582
  return email;
489
583
  }
490
584
 
585
+ /**
586
+ * Exchange the same Firebase token a second time for an API-only session.
587
+ *
588
+ * Failure is reported and swallowed rather than failing the login: the shell session -- the reason
589
+ * anyone runs this CLI -- already succeeded by this point, and taking the whole login down over the
590
+ * optional half would turn a working setup into a broken one. `edge-cli token` says what to do when
591
+ * the session is missing.
592
+ */
593
+ async function exchangeApiSession(
594
+ cfg: EffectiveConfig,
595
+ firebaseToken: string | undefined
596
+ ): Promise<TokenResponse | undefined> {
597
+ if (!firebaseToken) {
598
+ return undefined;
599
+ }
600
+ try {
601
+ const resp = await authExchangeFirebaseToken(cfg, firebaseToken, EXCHANGE_SCOPE_APP);
602
+ if (carriesShellAudience(resp.accessToken)) {
603
+ // Storing it would put a shell-capable token behind `edge-cli token`, which is the one
604
+ // outcome this whole feature exists to prevent. Better no API session than a mislabelled
605
+ // one.
606
+ process.stderr.write(
607
+ "Warning: the server returned a shell-scoped token for an app-scoped exchange; " +
608
+ "discarding it.\n'edge-cli token' will need --scope shell until this is resolved.\n"
609
+ );
610
+ return undefined;
611
+ }
612
+ return resp;
613
+ } catch (err) {
614
+ const reason = err instanceof Error ? err.message : String(err);
615
+ process.stderr.write(
616
+ `Warning: could not create an API-only session (${reason}).\n` +
617
+ `'edge-cli token' will need --scope shell until the next successful login.\n`
618
+ );
619
+ return undefined;
620
+ }
621
+ }
622
+
491
623
  async function validateAccessToken(cfg: EffectiveConfig, accessToken: string): Promise<boolean> {
492
624
  const url = new URL(`${cfg.baseUrl.replace(/\/$/, "")}/shell`);
493
625
  url.searchParams.set("cmd", "help");
@@ -569,6 +701,67 @@ export async function resolveAccessToken(cfg: EffectiveConfig, forceRefresh = fa
569
701
  return accessToken;
570
702
  }
571
703
 
704
+ /**
705
+ * The account's API-only access token, refreshed when it is at or near expiry.
706
+ *
707
+ * Deliberately does no liveness probe. `validateAccessToken` asks `GET /shell?cmd=help`, which this
708
+ * token is *supposed* to be refused by -- running it here would read a correctly-scoped token as a
709
+ * broken one and refresh it on every call.
710
+ *
711
+ * A missing API session is an error rather than a silent fall back to the shell token: handing back
712
+ * a token with more audiences than the caller asked for is the same silent substitution the server
713
+ * refuses when it will not downgrade a shell request to APP.
714
+ */
715
+ export async function resolveApiAccessToken(cfg: EffectiveConfig, forceRefresh = false): Promise<string> {
716
+ const db = readDb();
717
+ const scope = getScope(db, cfg);
718
+ const email = scope.default;
719
+ if (!email) {
720
+ throw new Error(`No JWT session for ${cfg.product}/${cfg.env}. Run 'edge-cli login'.`);
721
+ }
722
+ const account = scope.accounts[email];
723
+ if (!account) {
724
+ throw new Error(`No access token for ${email}. Run 'edge-cli login'.`);
725
+ }
726
+ const api = account.api;
727
+ if (!api?.accessToken) {
728
+ throw new Error(
729
+ `No API-only session for ${email} on ${cfg.product}/${cfg.env}.\n` +
730
+ `Run 'edge-cli login' to create one, or 'edge-cli token --scope shell' to print the ` +
731
+ `shell-capable token instead (it also drives the shell, so do not paste it elsewhere).`
732
+ );
733
+ }
734
+
735
+ // Checked on read, not only on write, so a session stored by a build that asked for the wrong
736
+ // scope is refused rather than handed out. Those tokens are already on disk in the wild.
737
+ if (carriesShellAudience(api.accessToken)) {
738
+ throw new Error(
739
+ `The stored API session for ${email} carries the ${SHELL_AUDIENCE} audience, so it is ` +
740
+ `not API-only. Run 'edge-cli login' to replace it.`
741
+ );
742
+ }
743
+
744
+ const expiry = api.accessExpEpoch ?? 0;
745
+ const stale = expiry > 0 && expiry <= nowEpoch() + 60;
746
+ if ((forceRefresh || stale) && api.refreshToken) {
747
+ try {
748
+ const refreshed = await authRefreshToken(cfg, api.refreshToken);
749
+ const merged: TokenResponse = {
750
+ accessToken: refreshed.accessToken,
751
+ refreshToken: refreshed.refreshToken || api.refreshToken,
752
+ accessTokenExpiresInSec: refreshed.accessTokenExpiresInSec,
753
+ refreshTokenExpiresInSec: refreshed.refreshTokenExpiresInSec
754
+ };
755
+ storeApiTokens(cfg, email, merged);
756
+ return merged.accessToken;
757
+ } catch {
758
+ // Fall through to the stored token; it may still have life left in it.
759
+ }
760
+ }
761
+
762
+ return api.accessToken;
763
+ }
764
+
572
765
  export async function resolveAuthHeader(cfg: EffectiveConfig): Promise<string> {
573
766
  const accessToken = await resolveAccessToken(cfg);
574
767
  return `Bearer ${accessToken}`;