vibelet 1.0.0 → 1.0.2
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/bin/vibelet.mjs +173 -0
- package/dist/index.cjs +45 -45
- package/package.json +1 -1
package/bin/vibelet.mjs
CHANGED
|
@@ -586,6 +586,7 @@ async function stopRunningDaemon(backend) {
|
|
|
586
586
|
}
|
|
587
587
|
|
|
588
588
|
function createCompactPairingPayload(pairingPayload) {
|
|
589
|
+
const connections = normalizePairingConnections(pairingPayload);
|
|
589
590
|
const compactPayload = {
|
|
590
591
|
t: 'vp',
|
|
591
592
|
d: pairingPayload.daemonId,
|
|
@@ -596,9 +597,170 @@ function createCompactPairingPayload(pairingPayload) {
|
|
|
596
597
|
e: pairingPayload.expiresAt,
|
|
597
598
|
};
|
|
598
599
|
if (pairingPayload.fallbackHosts) compactPayload.f = pairingPayload.fallbackHosts;
|
|
600
|
+
if (connections.length > 0) {
|
|
601
|
+
compactPayload.o = connections.map((target) => [
|
|
602
|
+
target.kind,
|
|
603
|
+
target.host,
|
|
604
|
+
target.port,
|
|
605
|
+
target.source,
|
|
606
|
+
target.stability,
|
|
607
|
+
]);
|
|
608
|
+
}
|
|
599
609
|
return compactPayload;
|
|
600
610
|
}
|
|
601
611
|
|
|
612
|
+
function normalizeHostValue(host) {
|
|
613
|
+
if (typeof host !== 'string') {
|
|
614
|
+
return '';
|
|
615
|
+
}
|
|
616
|
+
return host.trim().replace(/\.$/, '').toLowerCase();
|
|
617
|
+
}
|
|
618
|
+
|
|
619
|
+
function isIpv4Host(host) {
|
|
620
|
+
const parts = host.split('.');
|
|
621
|
+
return parts.length === 4 && parts.every((part) => /^\d+$/.test(part) && Number(part) >= 0 && Number(part) <= 255);
|
|
622
|
+
}
|
|
623
|
+
|
|
624
|
+
function isTailscaleHost(host) {
|
|
625
|
+
if (host.endsWith('.ts.net')) {
|
|
626
|
+
return true;
|
|
627
|
+
}
|
|
628
|
+
if (!isIpv4Host(host)) {
|
|
629
|
+
return false;
|
|
630
|
+
}
|
|
631
|
+
const [first, second] = host.split('.').map(Number);
|
|
632
|
+
return first === 100 && second >= 64 && second <= 127;
|
|
633
|
+
}
|
|
634
|
+
|
|
635
|
+
function isLocalNetworkHost(host) {
|
|
636
|
+
if (host.endsWith('.local')) {
|
|
637
|
+
return true;
|
|
638
|
+
}
|
|
639
|
+
if (!isIpv4Host(host)) {
|
|
640
|
+
return false;
|
|
641
|
+
}
|
|
642
|
+
const [first, second] = host.split('.').map(Number);
|
|
643
|
+
return first === 10
|
|
644
|
+
|| (first === 172 && second >= 16 && second <= 31)
|
|
645
|
+
|| (first === 192 && second === 168);
|
|
646
|
+
}
|
|
647
|
+
|
|
648
|
+
function isQuickTunnelHost(host) {
|
|
649
|
+
return host.endsWith('.trycloudflare.com');
|
|
650
|
+
}
|
|
651
|
+
|
|
652
|
+
function buildLegacyConnection(host, port, isPrimary) {
|
|
653
|
+
if (isQuickTunnelHost(host)) {
|
|
654
|
+
return {
|
|
655
|
+
kind: 'relay',
|
|
656
|
+
host,
|
|
657
|
+
port,
|
|
658
|
+
source: 'quick_tunnel',
|
|
659
|
+
stability: 'ephemeral',
|
|
660
|
+
};
|
|
661
|
+
}
|
|
662
|
+
if (isTailscaleHost(host)) {
|
|
663
|
+
return {
|
|
664
|
+
kind: 'direct',
|
|
665
|
+
host,
|
|
666
|
+
port,
|
|
667
|
+
source: 'tailscale',
|
|
668
|
+
stability: 'stable',
|
|
669
|
+
};
|
|
670
|
+
}
|
|
671
|
+
if (isLocalNetworkHost(host)) {
|
|
672
|
+
return {
|
|
673
|
+
kind: 'direct',
|
|
674
|
+
host,
|
|
675
|
+
port,
|
|
676
|
+
source: 'local_network',
|
|
677
|
+
stability: 'stable',
|
|
678
|
+
};
|
|
679
|
+
}
|
|
680
|
+
return {
|
|
681
|
+
kind: 'direct',
|
|
682
|
+
host,
|
|
683
|
+
port,
|
|
684
|
+
source: isPrimary ? 'configured_host' : 'fallback',
|
|
685
|
+
stability: 'stable',
|
|
686
|
+
};
|
|
687
|
+
}
|
|
688
|
+
|
|
689
|
+
function normalizePairingConnections(pairingPayload) {
|
|
690
|
+
const explicitConnections = Array.isArray(pairingPayload.connections)
|
|
691
|
+
? pairingPayload.connections
|
|
692
|
+
.filter((target) => (
|
|
693
|
+
target
|
|
694
|
+
&& typeof target.host === 'string'
|
|
695
|
+
&& Number.isFinite(target.port)
|
|
696
|
+
&& typeof target.source === 'string'
|
|
697
|
+
&& typeof target.stability === 'string'
|
|
698
|
+
))
|
|
699
|
+
.map((target) => ({
|
|
700
|
+
kind: target.kind === 'relay' ? 'relay' : 'direct',
|
|
701
|
+
host: normalizeHostValue(target.host),
|
|
702
|
+
port: Math.floor(Number(target.port)),
|
|
703
|
+
source: target.source,
|
|
704
|
+
stability: target.stability,
|
|
705
|
+
}))
|
|
706
|
+
.filter((target) => target.host && target.port > 0)
|
|
707
|
+
: [];
|
|
708
|
+
|
|
709
|
+
const dedupe = (targets) => {
|
|
710
|
+
const seen = new Set();
|
|
711
|
+
return targets.filter((target) => {
|
|
712
|
+
const key = `${target.host}:${target.port}`;
|
|
713
|
+
if (seen.has(key)) {
|
|
714
|
+
return false;
|
|
715
|
+
}
|
|
716
|
+
seen.add(key);
|
|
717
|
+
return true;
|
|
718
|
+
});
|
|
719
|
+
};
|
|
720
|
+
|
|
721
|
+
if (explicitConnections.length > 0) {
|
|
722
|
+
return dedupe(explicitConnections);
|
|
723
|
+
}
|
|
724
|
+
|
|
725
|
+
const canonicalHost = normalizeHostValue(pairingPayload.canonicalHost) || 'localhost';
|
|
726
|
+
const port = Number.isFinite(pairingPayload.port) && pairingPayload.port > 0
|
|
727
|
+
? Math.floor(Number(pairingPayload.port))
|
|
728
|
+
: 9876;
|
|
729
|
+
const fallbackHosts = Array.isArray(pairingPayload.fallbackHosts)
|
|
730
|
+
? pairingPayload.fallbackHosts
|
|
731
|
+
.map((host) => normalizeHostValue(host))
|
|
732
|
+
.filter((host) => host && host !== canonicalHost)
|
|
733
|
+
: [];
|
|
734
|
+
|
|
735
|
+
return dedupe([
|
|
736
|
+
buildLegacyConnection(canonicalHost, port, true),
|
|
737
|
+
...fallbackHosts.map((host) => buildLegacyConnection(host, port, false)),
|
|
738
|
+
]);
|
|
739
|
+
}
|
|
740
|
+
|
|
741
|
+
function formatConnectionSourceLabel(source) {
|
|
742
|
+
switch (source) {
|
|
743
|
+
case 'configured_relay':
|
|
744
|
+
return 'Custom Relay';
|
|
745
|
+
case 'quick_tunnel':
|
|
746
|
+
return 'Quick Tunnel';
|
|
747
|
+
case 'configured_host':
|
|
748
|
+
return 'Manual Host';
|
|
749
|
+
case 'tailscale':
|
|
750
|
+
return 'Tailscale';
|
|
751
|
+
case 'local_network':
|
|
752
|
+
return 'LAN';
|
|
753
|
+
case 'fallback':
|
|
754
|
+
default:
|
|
755
|
+
return 'Fallback';
|
|
756
|
+
}
|
|
757
|
+
}
|
|
758
|
+
|
|
759
|
+
function formatConnectionSummary(target) {
|
|
760
|
+
const stabilityLabel = target.stability === 'ephemeral' ? 'ephemeral' : 'stable';
|
|
761
|
+
return `${target.host}:${target.port} [${formatConnectionSourceLabel(target.source)}, ${stabilityLabel}]`;
|
|
762
|
+
}
|
|
763
|
+
|
|
602
764
|
async function printPairingQr(pairingPayload) {
|
|
603
765
|
const payload = JSON.stringify(createCompactPairingPayload(pairingPayload));
|
|
604
766
|
mkdirSync(vibeletDir, { recursive: true });
|
|
@@ -622,12 +784,23 @@ async function printPairingQr(pairingPayload) {
|
|
|
622
784
|
async function printPairingSummary(existingHealth = null) {
|
|
623
785
|
const health = existingHealth ?? await waitForHealth();
|
|
624
786
|
const pairingPayload = await postJson('/pair/open');
|
|
787
|
+
const connections = normalizePairingConnections(pairingPayload);
|
|
788
|
+
const [preferredConnection, ...otherConnections] = connections;
|
|
625
789
|
|
|
626
790
|
process.stdout.write(`Vibelet daemon is ready.\n\n`);
|
|
627
791
|
process.stdout.write(`Device: ${health.displayName}\n`);
|
|
628
792
|
process.stdout.write(`Daemon ID: ${health.daemonId}\n`);
|
|
629
793
|
process.stdout.write(`Host: ${pairingPayload.canonicalHost}\n`);
|
|
630
794
|
process.stdout.write(`Port: ${pairingPayload.port}\n`);
|
|
795
|
+
if (preferredConnection) {
|
|
796
|
+
process.stdout.write(`Preferred path: ${formatConnectionSummary(preferredConnection)}\n`);
|
|
797
|
+
}
|
|
798
|
+
if (otherConnections.length > 0) {
|
|
799
|
+
process.stdout.write(`Other paths:\n`);
|
|
800
|
+
otherConnections.forEach((target) => {
|
|
801
|
+
process.stdout.write(` - ${formatConnectionSummary(target)}\n`);
|
|
802
|
+
});
|
|
803
|
+
}
|
|
631
804
|
process.stdout.write(`Paired devices: ${health.pairedDevices}\n`);
|
|
632
805
|
await printPairingQr(pairingPayload);
|
|
633
806
|
}
|