@youkno/edge-cli 1.21.316 → 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 +70 -69
- package/.pnp.loader.mjs +5 -2
- package/.yarn/install-state.gz +0 -0
- package/README.md +8 -3
- package/dist/commands/token.js +12 -1
- package/dist/lib/auth.js +162 -12
- package/package.json +1 -1
- package/src/commands/token.ts +26 -3
- package/src/lib/auth.ts +206 -13
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": "
|
|
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": "
|
|
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": "
|
|
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": "
|
|
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": "
|
|
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": "
|
|
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": "
|
|
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": "
|
|
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": "
|
|
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": "
|
|
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": "
|
|
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": "
|
|
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": "
|
|
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/
|
|
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": "
|
|
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": "
|
|
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": "
|
|
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/
|
|
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": "
|
|
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": "
|
|
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": "
|
|
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": "
|
|
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": "
|
|
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": "
|
|
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": "
|
|
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": "
|
|
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": "
|
|
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": "
|
|
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": "
|
|
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": "
|
|
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": "
|
|
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": "
|
|
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": "
|
|
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": "
|
|
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": "
|
|
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": "
|
|
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": "
|
|
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": "
|
|
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": "
|
|
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": "
|
|
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": "
|
|
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": "
|
|
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": "
|
|
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": "
|
|
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": "
|
|
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": "
|
|
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": "
|
|
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": "
|
|
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": "
|
|
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": "
|
|
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": "
|
|
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": "
|
|
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": "
|
|
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": "
|
|
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": "
|
|
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": "
|
|
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": "
|
|
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": "
|
|
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": "
|
|
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": "
|
|
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": "
|
|
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": "
|
|
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": "
|
|
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": "
|
|
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": "
|
|
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(
|
|
6756
|
+
function reportRequiredFilesToWatchMode(paths) {
|
|
6757
6757
|
if (process.env.WATCH_REPORT_DEPENDENCIES && process.send) {
|
|
6758
|
-
files =
|
|
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
|
|
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
|
|
1557
|
+
source,
|
|
1555
1558
|
shortCircuit: true
|
|
1556
1559
|
};
|
|
1557
1560
|
}
|
package/.yarn/install-state.gz
CHANGED
|
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 --
|
|
70
|
-
edge-cli token --
|
|
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>"
|
package/dist/commands/token.js
CHANGED
|
@@ -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
|
|
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:
|
|
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
|
-
|
|
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,
|
|
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
|
|
242
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
package/src/commands/token.ts
CHANGED
|
@@ -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
|
-
.
|
|
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
|
-
|
|
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
|
-
|
|
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(
|
|
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:
|
|
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
|
-
|
|
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,
|
|
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
|
|
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
|
-
|
|
288
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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}`;
|