@mycadet/cli 0.12.9 → 0.12.10
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/package.json +4 -3
- package/src/__tests__/client-web-config.test.ts +0 -1
- package/src/__tests__/nginx-ingress.test.ts +3 -9
- package/src/__tests__/pair.test.ts +149 -78
- package/src/__tests__/ps-cloud-status.test.ts +4 -3
- package/src/__tests__/teleport.test.ts +0 -15
- package/src/__tests__/tunnel.test.ts +253 -68
- package/src/__tests__/uninstall.test.ts +140 -8
- package/src/commands/client.ts +4 -6
- package/src/commands/hatch.ts +4 -1
- package/src/commands/pair.ts +140 -37
- package/src/commands/ps.ts +6 -18
- package/src/commands/teleport.ts +2 -21
- package/src/commands/tunnel.ts +25 -25
- package/src/commands/uninstall.ts +106 -71
- package/src/lib/__tests__/local-gateway-cli.test.ts +42 -0
- package/src/lib/cloud-client.ts +0 -3
- package/src/lib/cloud-login.ts +0 -1
- package/src/lib/color.ts +4 -0
- package/src/lib/docker.ts +40 -58
- package/src/lib/environments/__tests__/paths.test.ts +27 -1
- package/src/lib/environments/paths.ts +16 -8
- package/src/lib/environments/resolve.ts +2 -4
- package/src/lib/hatch-local.ts +15 -8
- package/src/lib/hatch-next-steps.ts +5 -9
- package/src/lib/local.ts +36 -3
- package/src/lib/nginx-ingress.ts +1 -3
- package/src/lib/step-runner.ts +6 -1
|
@@ -245,7 +245,14 @@ async function runTunnelCapturingLogs(): Promise<string> {
|
|
|
245
245
|
|
|
246
246
|
describe("tunnel edge targeting", () => {
|
|
247
247
|
beforeEach(() => {
|
|
248
|
-
process.argv = [
|
|
248
|
+
process.argv = [
|
|
249
|
+
"bun",
|
|
250
|
+
"cadet",
|
|
251
|
+
"tunnel",
|
|
252
|
+
"--provider",
|
|
253
|
+
"tailscale",
|
|
254
|
+
"--foreground",
|
|
255
|
+
];
|
|
249
256
|
writeLockfile(makeLocalEntry());
|
|
250
257
|
globalThis.fetch = withPreconnect(async () => {
|
|
251
258
|
throw new Error("gateway unavailable");
|
|
@@ -311,7 +318,14 @@ describe("tunnel edge targeting", () => {
|
|
|
311
318
|
const entry = makeLocalEntry();
|
|
312
319
|
entry.runtimeUrl = "https://stale-tunnel.ngrok-free.dev";
|
|
313
320
|
writeLockfile(entry);
|
|
314
|
-
process.argv = [
|
|
321
|
+
process.argv = [
|
|
322
|
+
"bun",
|
|
323
|
+
"cadet",
|
|
324
|
+
"tunnel",
|
|
325
|
+
"--provider",
|
|
326
|
+
"ngrok",
|
|
327
|
+
"--foreground",
|
|
328
|
+
];
|
|
315
329
|
|
|
316
330
|
const logs = await runTunnelCapturingLogs();
|
|
317
331
|
|
|
@@ -332,7 +346,14 @@ describe("tunnel edge targeting", () => {
|
|
|
332
346
|
|
|
333
347
|
test("the tunnel level notifies the gateway of the provider's public URL", async () => {
|
|
334
348
|
writeLockfile(makeLocalEntry());
|
|
335
|
-
process.argv = [
|
|
349
|
+
process.argv = [
|
|
350
|
+
"bun",
|
|
351
|
+
"cadet",
|
|
352
|
+
"tunnel",
|
|
353
|
+
"--provider",
|
|
354
|
+
"ngrok",
|
|
355
|
+
"--foreground",
|
|
356
|
+
];
|
|
336
357
|
|
|
337
358
|
await runTunnelCapturingLogs();
|
|
338
359
|
|
|
@@ -348,7 +369,14 @@ describe("tunnel edge targeting", () => {
|
|
|
348
369
|
const cloud = makeCloudEntry();
|
|
349
370
|
const local = makeLocalEntry();
|
|
350
371
|
writeLockfile([cloud, local], cloud.assistantId);
|
|
351
|
-
process.argv = [
|
|
372
|
+
process.argv = [
|
|
373
|
+
"bun",
|
|
374
|
+
"cadet",
|
|
375
|
+
"tunnel",
|
|
376
|
+
"--provider",
|
|
377
|
+
"ngrok",
|
|
378
|
+
"--foreground",
|
|
379
|
+
];
|
|
352
380
|
|
|
353
381
|
const logs = await runTunnelCapturingLogs();
|
|
354
382
|
|
|
@@ -380,6 +408,7 @@ describe("tunnel edge targeting", () => {
|
|
|
380
408
|
"docker-1",
|
|
381
409
|
"--provider",
|
|
382
410
|
"ngrok",
|
|
411
|
+
"--foreground",
|
|
383
412
|
];
|
|
384
413
|
|
|
385
414
|
await runTunnelCapturingLogs();
|
|
@@ -400,7 +429,14 @@ describe("tunnel edge targeting", () => {
|
|
|
400
429
|
const workspaceDir = useTempDefaultWorkspaceDir();
|
|
401
430
|
const docker = makeDockerEntry();
|
|
402
431
|
writeLockfile(docker, docker.assistantId);
|
|
403
|
-
process.argv = [
|
|
432
|
+
process.argv = [
|
|
433
|
+
"bun",
|
|
434
|
+
"cadet",
|
|
435
|
+
"tunnel",
|
|
436
|
+
"--provider",
|
|
437
|
+
"ngrok",
|
|
438
|
+
"--foreground",
|
|
439
|
+
];
|
|
404
440
|
|
|
405
441
|
await runTunnelCapturingLogs();
|
|
406
442
|
|
|
@@ -420,7 +456,14 @@ describe("tunnel edge targeting", () => {
|
|
|
420
456
|
const workspaceDir = useTempDefaultWorkspaceDir();
|
|
421
457
|
const cloud = makeCloudEntry();
|
|
422
458
|
writeLockfile([cloud, makeDockerEntry()], cloud.assistantId);
|
|
423
|
-
process.argv = [
|
|
459
|
+
process.argv = [
|
|
460
|
+
"bun",
|
|
461
|
+
"cadet",
|
|
462
|
+
"tunnel",
|
|
463
|
+
"--provider",
|
|
464
|
+
"ngrok",
|
|
465
|
+
"--foreground",
|
|
466
|
+
];
|
|
424
467
|
|
|
425
468
|
const logs = await runTunnelCapturingLogs();
|
|
426
469
|
|
|
@@ -437,7 +480,14 @@ describe("tunnel edge targeting", () => {
|
|
|
437
480
|
|
|
438
481
|
test("an active cloud assistant with no local entries exits with an error", async () => {
|
|
439
482
|
writeLockfile(makeCloudEntry());
|
|
440
|
-
process.argv = [
|
|
483
|
+
process.argv = [
|
|
484
|
+
"bun",
|
|
485
|
+
"cadet",
|
|
486
|
+
"tunnel",
|
|
487
|
+
"--provider",
|
|
488
|
+
"ngrok",
|
|
489
|
+
"--foreground",
|
|
490
|
+
];
|
|
441
491
|
|
|
442
492
|
const { exited, errors } = await runTunnelExpectingExit1();
|
|
443
493
|
|
|
@@ -456,7 +506,14 @@ describe("tunnel edge targeting", () => {
|
|
|
456
506
|
[cloud, makeLocalEntry("assistant-a"), makeLocalEntry("assistant-b")],
|
|
457
507
|
cloud.assistantId,
|
|
458
508
|
);
|
|
459
|
-
process.argv = [
|
|
509
|
+
process.argv = [
|
|
510
|
+
"bun",
|
|
511
|
+
"cadet",
|
|
512
|
+
"tunnel",
|
|
513
|
+
"--provider",
|
|
514
|
+
"ngrok",
|
|
515
|
+
"--foreground",
|
|
516
|
+
];
|
|
460
517
|
|
|
461
518
|
const { exited, errors } = await runTunnelExpectingExit1();
|
|
462
519
|
|
|
@@ -474,7 +531,15 @@ describe("tunnel edge targeting", () => {
|
|
|
474
531
|
test("a positional cloud assistant name errors without auto-fallback", async () => {
|
|
475
532
|
const local = makeLocalEntry();
|
|
476
533
|
writeLockfile([makeCloudEntry(), local], local.assistantId);
|
|
477
|
-
process.argv = [
|
|
534
|
+
process.argv = [
|
|
535
|
+
"bun",
|
|
536
|
+
"cadet",
|
|
537
|
+
"tunnel",
|
|
538
|
+
"cloud-1",
|
|
539
|
+
"--provider",
|
|
540
|
+
"ngrok",
|
|
541
|
+
"--foreground",
|
|
542
|
+
];
|
|
478
543
|
|
|
479
544
|
const { exited, errors } = await runTunnelExpectingExit1();
|
|
480
545
|
|
|
@@ -493,7 +558,15 @@ describe("tunnel edge targeting", () => {
|
|
|
493
558
|
const local = makeLocalEntry();
|
|
494
559
|
local.name = "Ada";
|
|
495
560
|
writeLockfile([makeCloudEntry(), local], "cloud-1");
|
|
496
|
-
process.argv = [
|
|
561
|
+
process.argv = [
|
|
562
|
+
"bun",
|
|
563
|
+
"cadet",
|
|
564
|
+
"tunnel",
|
|
565
|
+
"Ada",
|
|
566
|
+
"--provider",
|
|
567
|
+
"ngrok",
|
|
568
|
+
"--foreground",
|
|
569
|
+
];
|
|
497
570
|
|
|
498
571
|
await runTunnelCapturingLogs();
|
|
499
572
|
|
|
@@ -517,6 +590,7 @@ describe("tunnel edge targeting", () => {
|
|
|
517
590
|
"Lovelace",
|
|
518
591
|
"--provider",
|
|
519
592
|
"ngrok",
|
|
593
|
+
"--foreground",
|
|
520
594
|
];
|
|
521
595
|
|
|
522
596
|
await runTunnelCapturingLogs();
|
|
@@ -533,7 +607,15 @@ describe("tunnel edge targeting", () => {
|
|
|
533
607
|
const workspaceDir = useTempDefaultWorkspaceDir();
|
|
534
608
|
const local = makeLocalEntry();
|
|
535
609
|
writeLockfile([local, makeAppleContainerEntry()], local.assistantId);
|
|
536
|
-
process.argv = [
|
|
610
|
+
process.argv = [
|
|
611
|
+
"bun",
|
|
612
|
+
"cadet",
|
|
613
|
+
"tunnel",
|
|
614
|
+
"apple-1",
|
|
615
|
+
"--provider",
|
|
616
|
+
"ngrok",
|
|
617
|
+
"--foreground",
|
|
618
|
+
];
|
|
537
619
|
|
|
538
620
|
await runTunnelCapturingLogs();
|
|
539
621
|
|
|
@@ -553,7 +635,14 @@ describe("tunnel edge targeting", () => {
|
|
|
553
635
|
const workspaceDir = useTempDefaultWorkspaceDir();
|
|
554
636
|
const cloud = makeCloudEntry();
|
|
555
637
|
writeLockfile([cloud, makeAppleContainerEntry()], cloud.assistantId);
|
|
556
|
-
process.argv = [
|
|
638
|
+
process.argv = [
|
|
639
|
+
"bun",
|
|
640
|
+
"cadet",
|
|
641
|
+
"tunnel",
|
|
642
|
+
"--provider",
|
|
643
|
+
"ngrok",
|
|
644
|
+
"--foreground",
|
|
645
|
+
];
|
|
557
646
|
|
|
558
647
|
const logs = await runTunnelCapturingLogs();
|
|
559
648
|
|
|
@@ -585,6 +674,7 @@ describe("tunnel edge targeting", () => {
|
|
|
585
674
|
"assistant-b",
|
|
586
675
|
"--provider",
|
|
587
676
|
"ngrok",
|
|
677
|
+
"--foreground",
|
|
588
678
|
];
|
|
589
679
|
|
|
590
680
|
await runTunnelCapturingLogs();
|
|
@@ -599,7 +689,15 @@ describe("tunnel edge targeting", () => {
|
|
|
599
689
|
cloud.name = "Cloudy";
|
|
600
690
|
const local = makeLocalEntry();
|
|
601
691
|
writeLockfile([cloud, local], local.assistantId);
|
|
602
|
-
process.argv = [
|
|
692
|
+
process.argv = [
|
|
693
|
+
"bun",
|
|
694
|
+
"cadet",
|
|
695
|
+
"tunnel",
|
|
696
|
+
"Cloudy",
|
|
697
|
+
"--provider",
|
|
698
|
+
"ngrok",
|
|
699
|
+
"--foreground",
|
|
700
|
+
];
|
|
603
701
|
|
|
604
702
|
const { exited, errors } = await runTunnelExpectingExit1();
|
|
605
703
|
|
|
@@ -620,7 +718,15 @@ describe("tunnel edge targeting", () => {
|
|
|
620
718
|
const second = makeLocalEntry("assistant-b");
|
|
621
719
|
second.name = "Ada";
|
|
622
720
|
writeLockfile([first, second], "assistant-a");
|
|
623
|
-
process.argv = [
|
|
721
|
+
process.argv = [
|
|
722
|
+
"bun",
|
|
723
|
+
"cadet",
|
|
724
|
+
"tunnel",
|
|
725
|
+
"Ada",
|
|
726
|
+
"--provider",
|
|
727
|
+
"ngrok",
|
|
728
|
+
"--foreground",
|
|
729
|
+
];
|
|
624
730
|
|
|
625
731
|
const { exited, errors } = await runTunnelExpectingExit1();
|
|
626
732
|
|
|
@@ -633,7 +739,15 @@ describe("tunnel edge targeting", () => {
|
|
|
633
739
|
});
|
|
634
740
|
|
|
635
741
|
test("an unknown positional name errors", async () => {
|
|
636
|
-
process.argv = [
|
|
742
|
+
process.argv = [
|
|
743
|
+
"bun",
|
|
744
|
+
"cadet",
|
|
745
|
+
"tunnel",
|
|
746
|
+
"nope",
|
|
747
|
+
"--provider",
|
|
748
|
+
"ngrok",
|
|
749
|
+
"--foreground",
|
|
750
|
+
];
|
|
637
751
|
|
|
638
752
|
const { exited, errors } = await runTunnelExpectingExit1();
|
|
639
753
|
|
|
@@ -646,7 +760,14 @@ describe("tunnel edge targeting", () => {
|
|
|
646
760
|
test("targets the edge port for cloudflare", async () => {
|
|
647
761
|
const entry = makeLocalEntry();
|
|
648
762
|
writeLockfile(entry);
|
|
649
|
-
process.argv = [
|
|
763
|
+
process.argv = [
|
|
764
|
+
"bun",
|
|
765
|
+
"cadet",
|
|
766
|
+
"tunnel",
|
|
767
|
+
"--provider",
|
|
768
|
+
"cloudflare",
|
|
769
|
+
"--foreground",
|
|
770
|
+
];
|
|
650
771
|
|
|
651
772
|
await runTunnelCapturingLogs();
|
|
652
773
|
|
|
@@ -661,7 +782,14 @@ describe("tunnel edge targeting", () => {
|
|
|
661
782
|
test("targets the edge port for tailscale and notes a reused webhooks-only edge", async () => {
|
|
662
783
|
const entry = makeLocalEntry();
|
|
663
784
|
writeLockfile(entry);
|
|
664
|
-
process.argv = [
|
|
785
|
+
process.argv = [
|
|
786
|
+
"bun",
|
|
787
|
+
"cadet",
|
|
788
|
+
"tunnel",
|
|
789
|
+
"--provider",
|
|
790
|
+
"tailscale",
|
|
791
|
+
"--foreground",
|
|
792
|
+
];
|
|
665
793
|
ensureTunnelEdgeMock.mockResolvedValue({
|
|
666
794
|
port: EDGE_PORT,
|
|
667
795
|
started: false,
|
|
@@ -681,7 +809,7 @@ describe("tunnel edge targeting", () => {
|
|
|
681
809
|
test("a bare invocation tunnels the default provider", async () => {
|
|
682
810
|
const entry = makeLocalEntry();
|
|
683
811
|
writeLockfile(entry);
|
|
684
|
-
process.argv = ["bun", "cadet", "tunnel"];
|
|
812
|
+
process.argv = ["bun", "cadet", "tunnel", "--foreground"];
|
|
685
813
|
|
|
686
814
|
const logs = await runTunnelCapturingLogs();
|
|
687
815
|
|
|
@@ -700,7 +828,7 @@ describe("tunnel edge targeting", () => {
|
|
|
700
828
|
const entry = makeLocalEntry();
|
|
701
829
|
entry.name = "Ada";
|
|
702
830
|
writeLockfile(entry);
|
|
703
|
-
process.argv = ["bun", "cadet", "tunnel", "Ada"];
|
|
831
|
+
process.argv = ["bun", "cadet", "tunnel", "Ada", "--foreground"];
|
|
704
832
|
|
|
705
833
|
const logs = await runTunnelCapturingLogs();
|
|
706
834
|
|
|
@@ -720,7 +848,14 @@ describe("tunnel edge targeting", () => {
|
|
|
720
848
|
const workspaceDir = writeEntryWorkspaceConfig(entry, {
|
|
721
849
|
telegram: { botUsername: "example_bot" },
|
|
722
850
|
});
|
|
723
|
-
process.argv = [
|
|
851
|
+
process.argv = [
|
|
852
|
+
"bun",
|
|
853
|
+
"cadet",
|
|
854
|
+
"tunnel",
|
|
855
|
+
"--provider",
|
|
856
|
+
"tailscale",
|
|
857
|
+
"--foreground",
|
|
858
|
+
];
|
|
724
859
|
|
|
725
860
|
const warnings: string[] = [];
|
|
726
861
|
const warnSpy = spyOn(console, "warn").mockImplementation(
|
|
@@ -751,7 +886,14 @@ describe("tunnel edge targeting", () => {
|
|
|
751
886
|
const entry = makeLocalEntry();
|
|
752
887
|
writeLockfile(entry);
|
|
753
888
|
const workspaceDir = writeEntryWorkspaceConfig(entry, {});
|
|
754
|
-
process.argv = [
|
|
889
|
+
process.argv = [
|
|
890
|
+
"bun",
|
|
891
|
+
"cadet",
|
|
892
|
+
"tunnel",
|
|
893
|
+
"--provider",
|
|
894
|
+
"tailscale",
|
|
895
|
+
"--foreground",
|
|
896
|
+
];
|
|
755
897
|
|
|
756
898
|
await runTunnelCapturingLogs();
|
|
757
899
|
|
|
@@ -768,7 +910,14 @@ describe("tunnel edge targeting", () => {
|
|
|
768
910
|
const workspaceDir = writeEntryWorkspaceConfig(entry, {
|
|
769
911
|
telegram: { botUsername: "example_bot" },
|
|
770
912
|
});
|
|
771
|
-
process.argv = [
|
|
913
|
+
process.argv = [
|
|
914
|
+
"bun",
|
|
915
|
+
"cadet",
|
|
916
|
+
"tunnel",
|
|
917
|
+
"--provider",
|
|
918
|
+
"ngrok",
|
|
919
|
+
"--foreground",
|
|
920
|
+
];
|
|
772
921
|
|
|
773
922
|
await runTunnelCapturingLogs();
|
|
774
923
|
|
|
@@ -780,7 +929,14 @@ describe("tunnel edge targeting", () => {
|
|
|
780
929
|
});
|
|
781
930
|
|
|
782
931
|
test("missing nginx aborts before any provider spawn", async () => {
|
|
783
|
-
process.argv = [
|
|
932
|
+
process.argv = [
|
|
933
|
+
"bun",
|
|
934
|
+
"cadet",
|
|
935
|
+
"tunnel",
|
|
936
|
+
"--provider",
|
|
937
|
+
"ngrok",
|
|
938
|
+
"--foreground",
|
|
939
|
+
];
|
|
784
940
|
ensureTunnelEdgeMock.mockRejectedValue(
|
|
785
941
|
new Error(
|
|
786
942
|
"nginx is not installed, so the tunnel edge cannot start. " +
|
|
@@ -801,7 +957,14 @@ describe("tunnel edge targeting", () => {
|
|
|
801
957
|
});
|
|
802
958
|
|
|
803
959
|
test("rejects an unknown --provider with a stale-CLI hint", async () => {
|
|
804
|
-
process.argv = [
|
|
960
|
+
process.argv = [
|
|
961
|
+
"bun",
|
|
962
|
+
"cadet",
|
|
963
|
+
"tunnel",
|
|
964
|
+
"--provider",
|
|
965
|
+
"bogus",
|
|
966
|
+
"--foreground",
|
|
967
|
+
];
|
|
805
968
|
|
|
806
969
|
const { exited, errors } = await runTunnelExpectingExit1();
|
|
807
970
|
|
|
@@ -818,7 +981,14 @@ describe("tunnel edge targeting", () => {
|
|
|
818
981
|
try {
|
|
819
982
|
for (const provider of TUNNEL_PROVIDERS) {
|
|
820
983
|
writeLockfile(makeLocalEntry());
|
|
821
|
-
process.argv = [
|
|
984
|
+
process.argv = [
|
|
985
|
+
"bun",
|
|
986
|
+
"cadet",
|
|
987
|
+
"tunnel",
|
|
988
|
+
"--provider",
|
|
989
|
+
provider,
|
|
990
|
+
"--foreground",
|
|
991
|
+
];
|
|
822
992
|
|
|
823
993
|
const { exited, errors } = await runTunnelExpectingExit1();
|
|
824
994
|
|
|
@@ -841,6 +1011,7 @@ describe("tunnel edge targeting", () => {
|
|
|
841
1011
|
"ngrok",
|
|
842
1012
|
"--domain",
|
|
843
1013
|
"foo.ngrok.app",
|
|
1014
|
+
"--foreground",
|
|
844
1015
|
];
|
|
845
1016
|
|
|
846
1017
|
await runTunnelCapturingLogs();
|
|
@@ -862,6 +1033,7 @@ describe("tunnel edge targeting", () => {
|
|
|
862
1033
|
"cloudflare",
|
|
863
1034
|
"--domain",
|
|
864
1035
|
"foo.ngrok.app",
|
|
1036
|
+
"--foreground",
|
|
865
1037
|
];
|
|
866
1038
|
|
|
867
1039
|
const { exited, errors } = await runTunnelExpectingExit1();
|
|
@@ -887,6 +1059,7 @@ describe("tunnel edge targeting", () => {
|
|
|
887
1059
|
"--provider",
|
|
888
1060
|
"ngrok",
|
|
889
1061
|
"--clear-domain",
|
|
1062
|
+
"--foreground",
|
|
890
1063
|
];
|
|
891
1064
|
|
|
892
1065
|
const logs = await runTunnelCapturingLogs();
|
|
@@ -912,6 +1085,7 @@ describe("tunnel edge targeting", () => {
|
|
|
912
1085
|
"--domain",
|
|
913
1086
|
"foo.ngrok.app",
|
|
914
1087
|
"--clear-domain",
|
|
1088
|
+
"--foreground",
|
|
915
1089
|
];
|
|
916
1090
|
|
|
917
1091
|
const { exited, errors } = await runTunnelExpectingExit1();
|
|
@@ -929,6 +1103,7 @@ describe("tunnel edge targeting", () => {
|
|
|
929
1103
|
"--provider",
|
|
930
1104
|
"cloudflare",
|
|
931
1105
|
"--clear-domain",
|
|
1106
|
+
"--foreground",
|
|
932
1107
|
];
|
|
933
1108
|
|
|
934
1109
|
const { exited, errors } = await runTunnelExpectingExit1();
|
|
@@ -949,6 +1124,7 @@ describe("tunnel edge targeting", () => {
|
|
|
949
1124
|
"--provider",
|
|
950
1125
|
"ngrok",
|
|
951
1126
|
"--domain",
|
|
1127
|
+
"--foreground",
|
|
952
1128
|
];
|
|
953
1129
|
|
|
954
1130
|
const { exited, errors } = await runTunnelExpectingExit1();
|
|
@@ -961,7 +1137,14 @@ describe("tunnel edge targeting", () => {
|
|
|
961
1137
|
test("a not-yet-implemented provider error carries the stale-CLI hint", async () => {
|
|
962
1138
|
// `cadet` stays valid-but-unimplemented, so it hits this path rather
|
|
963
1139
|
// than the unknown-provider one.
|
|
964
|
-
process.argv = [
|
|
1140
|
+
process.argv = [
|
|
1141
|
+
"bun",
|
|
1142
|
+
"cadet",
|
|
1143
|
+
"tunnel",
|
|
1144
|
+
"--provider",
|
|
1145
|
+
"cadet",
|
|
1146
|
+
"--foreground",
|
|
1147
|
+
];
|
|
965
1148
|
|
|
966
1149
|
let err: Error | undefined;
|
|
967
1150
|
try {
|
|
@@ -1490,7 +1673,7 @@ describe("ngrok --domain spawn args", () => {
|
|
|
1490
1673
|
});
|
|
1491
1674
|
});
|
|
1492
1675
|
|
|
1493
|
-
describe("tunnel
|
|
1676
|
+
describe("tunnel background mode", () => {
|
|
1494
1677
|
const originalXdgConfigHome = process.env.XDG_CONFIG_HOME;
|
|
1495
1678
|
|
|
1496
1679
|
function makeFakeChild(pid: number): ChildProcess {
|
|
@@ -1512,13 +1695,22 @@ describe("tunnel --detach", () => {
|
|
|
1512
1695
|
): ChildProcess => makeFakeChild(9999),
|
|
1513
1696
|
);
|
|
1514
1697
|
|
|
1515
|
-
// spawnDetachedTunnel() scopes the log filename to its own (parent) pid,
|
|
1516
|
-
// which in-process is this test runner's pid.
|
|
1517
1698
|
function detachedLogPath(): string {
|
|
1518
|
-
return join(getLogDir(),
|
|
1699
|
+
return join(getLogDir(), "tunnel.log");
|
|
1519
1700
|
}
|
|
1520
1701
|
|
|
1521
1702
|
beforeAll(() => {
|
|
1703
|
+
// The edge-targeting describe's afterAll restores the REAL provider
|
|
1704
|
+
// modules; re-establish the fakes the foreground test here needs.
|
|
1705
|
+
mock.module("../lib/tunnels/ngrok", () => ({
|
|
1706
|
+
...realNgrok,
|
|
1707
|
+
runNgrokTunnel: runNgrokTunnelMock,
|
|
1708
|
+
}));
|
|
1709
|
+
mock.module("../lib/nginx-ingress.js", () => ({
|
|
1710
|
+
...realNginxIngress,
|
|
1711
|
+
ensureTunnelEdge: ensureTunnelEdgeMock,
|
|
1712
|
+
getNginxVersion: getNginxVersionMock,
|
|
1713
|
+
}));
|
|
1522
1714
|
mock.module("node:child_process", () => ({
|
|
1523
1715
|
...realChildProcess,
|
|
1524
1716
|
spawn: spawnMock,
|
|
@@ -1527,10 +1719,22 @@ describe("tunnel --detach", () => {
|
|
|
1527
1719
|
|
|
1528
1720
|
afterAll(() => {
|
|
1529
1721
|
mock.module("node:child_process", () => realChildProcess);
|
|
1722
|
+
mock.module("../lib/tunnels/ngrok", () => realNgrok);
|
|
1723
|
+
mock.module("../lib/nginx-ingress.js", () => realNginxIngress);
|
|
1530
1724
|
});
|
|
1531
1725
|
|
|
1532
1726
|
beforeEach(() => {
|
|
1533
1727
|
spawnMock.mockClear();
|
|
1728
|
+
runNgrokTunnelMock.mockReset();
|
|
1729
|
+
runNgrokTunnelMock.mockResolvedValue(
|
|
1730
|
+
fakeTunnelResult("https://test.example.ngrok.dev"),
|
|
1731
|
+
);
|
|
1732
|
+
ensureTunnelEdgeMock.mockReset();
|
|
1733
|
+
ensureTunnelEdgeMock.mockResolvedValue({
|
|
1734
|
+
port: EDGE_PORT,
|
|
1735
|
+
started: true,
|
|
1736
|
+
includesWebApp: true,
|
|
1737
|
+
});
|
|
1534
1738
|
const configHome = mkdtempSync(join(tmpdir(), "cadet-tunnel-xdg-"));
|
|
1535
1739
|
tempDirs.push(configHome);
|
|
1536
1740
|
process.env.XDG_CONFIG_HOME = configHome;
|
|
@@ -1548,15 +1752,8 @@ describe("tunnel --detach", () => {
|
|
|
1548
1752
|
}
|
|
1549
1753
|
});
|
|
1550
1754
|
|
|
1551
|
-
test("
|
|
1552
|
-
process.argv = [
|
|
1553
|
-
"bun",
|
|
1554
|
-
"cadet",
|
|
1555
|
-
"tunnel",
|
|
1556
|
-
"--provider",
|
|
1557
|
-
"ngrok",
|
|
1558
|
-
"--detach",
|
|
1559
|
-
];
|
|
1755
|
+
test("runs detached by default: re-invokes itself as a detached child and reports readiness", async () => {
|
|
1756
|
+
process.argv = ["bun", "cadet", "tunnel", "--provider", "ngrok"];
|
|
1560
1757
|
|
|
1561
1758
|
// Simulate the detached child writing its readiness line to the log file
|
|
1562
1759
|
// the moment it is spawned.
|
|
@@ -1575,8 +1772,10 @@ describe("tunnel --detach", () => {
|
|
|
1575
1772
|
expect(args).toContain("tunnel");
|
|
1576
1773
|
expect(args).toContain("--provider");
|
|
1577
1774
|
expect(args).toContain("ngrok");
|
|
1578
|
-
|
|
1579
|
-
|
|
1775
|
+
// The child runs the foreground path (it IS the background daemon); the
|
|
1776
|
+
// parent must not hand the default through or the child would daemonize
|
|
1777
|
+
// again.
|
|
1778
|
+
expect(args).toContain("--foreground");
|
|
1580
1779
|
expect(opts?.detached).toBe(true);
|
|
1581
1780
|
|
|
1582
1781
|
expect(logs).toContain("Tunnel established: https://foo.ngrok.app");
|
|
@@ -1589,32 +1788,25 @@ describe("tunnel --detach", () => {
|
|
|
1589
1788
|
expect(ensureTunnelEdgeMock).not.toHaveBeenCalled();
|
|
1590
1789
|
});
|
|
1591
1790
|
|
|
1592
|
-
test("
|
|
1593
|
-
process.argv = ["bun", "cadet", "tunnel", "--provider", "tailscale", "-d"];
|
|
1594
|
-
spawnMock.mockImplementationOnce(() => {
|
|
1595
|
-
appendFileSync(
|
|
1596
|
-
detachedLogPath(),
|
|
1597
|
-
"Tunnel established: https://tailnet.example.ts.net\n",
|
|
1598
|
-
);
|
|
1599
|
-
return makeFakeChild(1234);
|
|
1600
|
-
});
|
|
1601
|
-
|
|
1602
|
-
await runTunnelCapturingLogs();
|
|
1603
|
-
|
|
1604
|
-
const [, args] = spawnMock.mock.calls[0];
|
|
1605
|
-
expect(args).not.toContain("-d");
|
|
1606
|
-
expect(args).not.toContain("--detach");
|
|
1607
|
-
});
|
|
1608
|
-
|
|
1609
|
-
test("reports an early child exit instead of hanging", async () => {
|
|
1791
|
+
test("--foreground runs the tunnel in this process instead of a detached child", async () => {
|
|
1610
1792
|
process.argv = [
|
|
1611
1793
|
"bun",
|
|
1612
1794
|
"cadet",
|
|
1613
1795
|
"tunnel",
|
|
1614
1796
|
"--provider",
|
|
1615
1797
|
"ngrok",
|
|
1616
|
-
"--
|
|
1798
|
+
"--foreground",
|
|
1617
1799
|
];
|
|
1800
|
+
|
|
1801
|
+
await runTunnelCapturingLogs();
|
|
1802
|
+
|
|
1803
|
+
expect(spawnMock).not.toHaveBeenCalled();
|
|
1804
|
+
expect(ensureTunnelEdgeMock).toHaveBeenCalled();
|
|
1805
|
+
expect(runNgrokTunnelMock).toHaveBeenCalled();
|
|
1806
|
+
});
|
|
1807
|
+
|
|
1808
|
+
test("reports an early child exit instead of hanging", async () => {
|
|
1809
|
+
process.argv = ["bun", "cadet", "tunnel", "--provider", "ngrok"];
|
|
1618
1810
|
spawnMock.mockImplementationOnce(() => {
|
|
1619
1811
|
const child = makeFakeChild(4242);
|
|
1620
1812
|
// Listeners attach synchronously right after spawn() returns; defer the
|
|
@@ -1631,14 +1823,7 @@ describe("tunnel --detach", () => {
|
|
|
1631
1823
|
});
|
|
1632
1824
|
|
|
1633
1825
|
test("an adopted ngrok tunnel gets an accurate stop message, not a false kill claim", async () => {
|
|
1634
|
-
process.argv = [
|
|
1635
|
-
"bun",
|
|
1636
|
-
"cadet",
|
|
1637
|
-
"tunnel",
|
|
1638
|
-
"--provider",
|
|
1639
|
-
"ngrok",
|
|
1640
|
-
"--detach",
|
|
1641
|
-
];
|
|
1826
|
+
process.argv = ["bun", "cadet", "tunnel", "--provider", "ngrok"];
|
|
1642
1827
|
spawnMock.mockImplementationOnce(() => {
|
|
1643
1828
|
appendFileSync(
|
|
1644
1829
|
detachedLogPath(),
|