@volter/tunnel 1.1.0 → 1.2.0
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/client/tunnel-client.ts +45 -3
- package/package.json +1 -1
package/client/tunnel-client.ts
CHANGED
|
@@ -73,10 +73,26 @@ interface TunnelRequest {
|
|
|
73
73
|
body: string | null;
|
|
74
74
|
}
|
|
75
75
|
|
|
76
|
+
interface RateWindow {
|
|
77
|
+
limit: number;
|
|
78
|
+
remaining: number;
|
|
79
|
+
reset: number;
|
|
80
|
+
}
|
|
81
|
+
|
|
76
82
|
interface TunnelRegistered {
|
|
77
83
|
type: 'registered';
|
|
78
84
|
tunnelId: string;
|
|
79
85
|
url: string;
|
|
86
|
+
/** Metering snapshot for this account (present when the relay meters usage). */
|
|
87
|
+
account?: { slug: string; day: RateWindow; month: RateWindow; level: 'ok' | 'warn' | 'exceeded' };
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/** Pushed by the relay when the account's usage level changes (ok→warn→exceeded). */
|
|
91
|
+
interface TunnelQuota {
|
|
92
|
+
type: 'quota';
|
|
93
|
+
level: 'ok' | 'warn' | 'exceeded';
|
|
94
|
+
day: RateWindow;
|
|
95
|
+
month: RateWindow;
|
|
80
96
|
}
|
|
81
97
|
|
|
82
98
|
interface TunnelWsUpgrade {
|
|
@@ -117,7 +133,8 @@ type TunnelMessage =
|
|
|
117
133
|
| TunnelWsMessage
|
|
118
134
|
| TunnelWsClose
|
|
119
135
|
| TunnelRequestAbort
|
|
120
|
-
| TunnelError
|
|
136
|
+
| TunnelError
|
|
137
|
+
| TunnelQuota;
|
|
121
138
|
|
|
122
139
|
// ============================================================================
|
|
123
140
|
// Safe WebSocket close helpers
|
|
@@ -392,8 +409,13 @@ export function createTunnel({
|
|
|
392
409
|
port,
|
|
393
410
|
tunnelId: msg.tunnelId,
|
|
394
411
|
url: msg.url,
|
|
412
|
+
account: msg.account?.slug,
|
|
413
|
+
dayRemaining: msg.account?.day.remaining,
|
|
414
|
+
dayLimit: msg.account?.day.limit,
|
|
395
415
|
},
|
|
396
|
-
|
|
416
|
+
msg.account
|
|
417
|
+
? `Tunnel registered: localhost:${port} → ${msg.url} (${msg.account.slug}: ${msg.account.day.remaining}/${msg.account.day.limit} credits today)`
|
|
418
|
+
: `Tunnel registered: localhost:${port} → ${msg.url}`
|
|
397
419
|
);
|
|
398
420
|
onRegistered({
|
|
399
421
|
url: msg.url,
|
|
@@ -411,6 +433,21 @@ export function createTunnel({
|
|
|
411
433
|
});
|
|
412
434
|
}
|
|
413
435
|
|
|
436
|
+
if (msg.type === 'quota') {
|
|
437
|
+
const line = `Tunnel quota ${msg.level}: ${msg.day.remaining}/${msg.day.limit} credits remaining today`;
|
|
438
|
+
const ctx = {
|
|
439
|
+
component: 'tunnel_client',
|
|
440
|
+
action: 'quota',
|
|
441
|
+
level: msg.level,
|
|
442
|
+
dayRemaining: msg.day.remaining,
|
|
443
|
+
dayLimit: msg.day.limit,
|
|
444
|
+
monthRemaining: msg.month.remaining,
|
|
445
|
+
};
|
|
446
|
+
if (msg.level === 'ok') log.info(ctx, line);
|
|
447
|
+
else log.warn(ctx, line);
|
|
448
|
+
return;
|
|
449
|
+
}
|
|
450
|
+
|
|
414
451
|
if (msg.type === 'request') {
|
|
415
452
|
const localReq = forwardRequest(port, localHost, msg, ws, activeRequests, async (err) => {
|
|
416
453
|
// On ECONNREFUSED, re-resolve loopback and retry once
|
|
@@ -845,8 +882,13 @@ if (import.meta.main) {
|
|
|
845
882
|
process.exit(1);
|
|
846
883
|
}
|
|
847
884
|
|
|
885
|
+
// Default to the Cloudflare Workers + Durable Objects relay. The old Fly relay
|
|
886
|
+
// (vgit-tunnels.volterapp.com) returns HTTP 200 instead of 101 on HTTP/2
|
|
887
|
+
// WebSocket upgrades, which breaks browser-based flows (e.g. QA proofs).
|
|
848
888
|
const host =
|
|
849
|
-
flag('host') ||
|
|
889
|
+
flag('host') ||
|
|
890
|
+
process.env.TUNNEL_SERVER_URL ||
|
|
891
|
+
'https://volter-tunnel.aaron-0ed.workers.dev';
|
|
850
892
|
const secret = process.env.TUNNEL_SECRET;
|
|
851
893
|
const tunnelId = flag('tunnel-id');
|
|
852
894
|
const authNotRequired = args.includes('--auth-not-required');
|
package/package.json
CHANGED