@push.rocks/smartvpn 2.3.1 → 2.4.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/dist_rust/smartvpn_daemon_linux_amd64_musl +0 -0
- package/dist_rust/smartvpn_daemon_linux_amd64_musl.tsrust-build.json +5 -5
- package/dist_rust/smartvpn_daemon_linux_arm64_musl +0 -0
- package/dist_rust/smartvpn_daemon_linux_arm64_musl.tsrust-build.json +5 -5
- package/dist_ts/00_commitinfo_data.js +3 -3
- package/dist_ts/smartvpn.classes.vpnclient.d.ts +8 -1
- package/dist_ts/smartvpn.classes.vpnclient.js +20 -5
- package/dist_ts/smartvpn.interfaces.d.ts +22 -0
- package/package.json +6 -6
- package/readme.md +20 -1
- package/ts/00_commitinfo_data.ts +3 -3
- package/ts/smartvpn.classes.vpnclient.ts +22 -4
- package/ts/smartvpn.interfaces.ts +17 -0
|
Binary file
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"format": "tsrust.build-provenance.v2",
|
|
3
|
-
"binarySha256": "
|
|
3
|
+
"binarySha256": "83e952eba6fa08fe0e4e34a2a29c133d5777eecbc60f269e67ec8ea0d7a8f55c",
|
|
4
4
|
"buildInfo": {
|
|
5
5
|
"projectName": "@push.rocks/smartvpn",
|
|
6
|
-
"projectVersion": "2.
|
|
7
|
-
"gitCommit": "
|
|
6
|
+
"projectVersion": "2.4.0",
|
|
7
|
+
"gitCommit": "f1b6c5bc99f76c52bdfeee01fc3c7655c301de37",
|
|
8
8
|
"gitDirty": false,
|
|
9
|
-
"builtAt": "2026-09-
|
|
10
|
-
"tsrustVersion": "1.
|
|
9
|
+
"builtAt": "2026-09-28T08:27:27.717Z",
|
|
10
|
+
"tsrustVersion": "1.15.1",
|
|
11
11
|
"binary": "smartvpn_daemon",
|
|
12
12
|
"target": "linux_amd64_musl"
|
|
13
13
|
}
|
|
Binary file
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"format": "tsrust.build-provenance.v2",
|
|
3
|
-
"binarySha256": "
|
|
3
|
+
"binarySha256": "5189ed1c065c805727c6a1927465bf4decfa769854f6ad2e3a4ed2b0d00cccdc",
|
|
4
4
|
"buildInfo": {
|
|
5
5
|
"projectName": "@push.rocks/smartvpn",
|
|
6
|
-
"projectVersion": "2.
|
|
7
|
-
"gitCommit": "
|
|
6
|
+
"projectVersion": "2.4.0",
|
|
7
|
+
"gitCommit": "f1b6c5bc99f76c52bdfeee01fc3c7655c301de37",
|
|
8
8
|
"gitDirty": false,
|
|
9
|
-
"builtAt": "2026-09-
|
|
10
|
-
"tsrustVersion": "1.
|
|
9
|
+
"builtAt": "2026-09-28T08:29:27.183Z",
|
|
10
|
+
"tsrustVersion": "1.15.1",
|
|
11
11
|
"binary": "smartvpn_daemon",
|
|
12
12
|
"target": "linux_arm64_musl"
|
|
13
13
|
}
|
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
* autocreated commitinfo by @push.rocks/commitinfo
|
|
3
3
|
*/
|
|
4
4
|
export const commitinfo = {
|
|
5
|
-
name:
|
|
6
|
-
version:
|
|
7
|
-
description:
|
|
5
|
+
name: '@push.rocks/smartvpn',
|
|
6
|
+
version: '2.4.0',
|
|
7
|
+
description: 'A VPN solution with TypeScript control plane and Rust data plane daemon'
|
|
8
8
|
};
|
|
9
9
|
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiMDBfY29tbWl0aW5mb19kYXRhLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vdHMvMDBfY29tbWl0aW5mb19kYXRhLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOztHQUVHO0FBQ0gsTUFBTSxDQUFDLE1BQU0sVUFBVSxHQUFHO0lBQ3hCLElBQUksRUFBRSxzQkFBc0I7SUFDNUIsT0FBTyxFQUFFLE9BQU87SUFDaEIsV0FBVyxFQUFFLHlFQUF5RTtDQUN2RixDQUFBIn0=
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as plugins from './smartvpn.plugins.js';
|
|
2
|
-
import type { IVpnClientOptions, IVpnClientConfig, IVpnStatus, IVpnStatistics, IVpnConnectionQuality, IVpnMtuInfo, IVpnConnectionResult, IVpnManagedRuntime, IVpnManagedSessionConfig, IVpnManagedSession } from './smartvpn.interfaces.js';
|
|
2
|
+
import type { IVpnClientOptions, IVpnClientConfig, IVpnStatus, IVpnStatistics, IVpnConnectionQuality, IVpnMtuInfo, IVpnConnectionResult, IVpnManagedRuntime, IVpnManagedSessionConfig, IVpnManagedSessionRenewal, IVpnManagedSession } from './smartvpn.interfaces.js';
|
|
3
3
|
/**
|
|
4
4
|
* VPN Client — manages a smartvpn daemon in client mode.
|
|
5
5
|
*/
|
|
@@ -30,7 +30,14 @@ export declare class VpnClient extends plugins.events.EventEmitter {
|
|
|
30
30
|
* This generation cannot forward again. Disconnect then closes its kernel owner. */
|
|
31
31
|
stopManagedForwarding(generation: string): Promise<IVpnManagedSession>;
|
|
32
32
|
inspectManagedSession(generation: string): Promise<IVpnManagedSession>;
|
|
33
|
+
/** Move the live generation's native lease in place, without teardown. The renewal
|
|
34
|
+
* must name the exact authority the generation authenticated under. A rejected
|
|
35
|
+
* renewal leaves the lease in force unchanged; a lapsed lease is never revived,
|
|
36
|
+
* so authenticate a new generation instead. The hub follows its own expiry from
|
|
37
|
+
* the managed network snapshot (SmartVPN hub 2.3.1 or later keeps the session). */
|
|
38
|
+
renewManagedSession(generation: string, renewal: IVpnManagedSessionRenewal): Promise<IVpnManagedSession>;
|
|
33
39
|
private sessionCommand;
|
|
40
|
+
private requireSessionGeneration;
|
|
34
41
|
private checkObservation;
|
|
35
42
|
/**
|
|
36
43
|
* Start the daemon bridge (spawn or connect).
|
|
@@ -104,17 +104,32 @@ export class VpnClient extends plugins.events.EventEmitter {
|
|
|
104
104
|
inspectManagedSession(generation) {
|
|
105
105
|
return this.sessionCommand('inspectManagedSession', generation);
|
|
106
106
|
}
|
|
107
|
+
/** Move the live generation's native lease in place, without teardown. The renewal
|
|
108
|
+
* must name the exact authority the generation authenticated under. A rejected
|
|
109
|
+
* renewal leaves the lease in force unchanged; a lapsed lease is never revived,
|
|
110
|
+
* so authenticate a new generation instead. The hub follows its own expiry from
|
|
111
|
+
* the managed network snapshot (SmartVPN hub 2.3.1 or later keeps the session). */
|
|
112
|
+
async renewManagedSession(generation, renewal) {
|
|
113
|
+
this.requireSessionGeneration(generation);
|
|
114
|
+
const epoch = this.bridgeEpoch;
|
|
115
|
+
const result = await this.bridge.sendCommand('renewManagedSession', { generation, renewal });
|
|
116
|
+
this.checkSession(result, epoch, generation);
|
|
117
|
+
return result;
|
|
118
|
+
}
|
|
107
119
|
async sessionCommand(method, generation) {
|
|
120
|
+
this.requireSessionGeneration(generation);
|
|
121
|
+
const epoch = this.bridgeEpoch;
|
|
122
|
+
const result = await this.bridge.sendCommand(method, { generation });
|
|
123
|
+
this.checkSession(result, epoch, generation);
|
|
124
|
+
return result;
|
|
125
|
+
}
|
|
126
|
+
requireSessionGeneration(generation) {
|
|
108
127
|
if (typeof generation !== 'string' || !/^[a-f0-9]{32}$/.test(generation)) {
|
|
109
128
|
throw new Error('Managed session generation must be a native 128-bit identifier');
|
|
110
129
|
}
|
|
111
130
|
if (generation === this.invalidatedSessionGeneration || generation === this.retiredSessionGeneration) {
|
|
112
131
|
throw new Error('Managed session observation is unavailable');
|
|
113
132
|
}
|
|
114
|
-
const epoch = this.bridgeEpoch;
|
|
115
|
-
const result = await this.bridge.sendCommand(method, { generation });
|
|
116
|
-
this.checkSession(result, epoch, generation);
|
|
117
|
-
return result;
|
|
118
133
|
}
|
|
119
134
|
checkObservation(runtime, epoch, generation) {
|
|
120
135
|
if (epoch !== this.bridgeEpoch || runtime.generation === this.lastInvalidatedGeneration
|
|
@@ -201,4 +216,4 @@ export class VpnClient extends plugins.events.EventEmitter {
|
|
|
201
216
|
return this.bridge.running;
|
|
202
217
|
}
|
|
203
218
|
}
|
|
204
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
219
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic21hcnR2cG4uY2xhc3Nlcy52cG5jbGllbnQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi90cy9zbWFydHZwbi5jbGFzc2VzLnZwbmNsaWVudC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEtBQUssT0FBTyxNQUFNLHVCQUF1QixDQUFDO0FBQ2pELE9BQU8sRUFBRSxTQUFTLEVBQUUsTUFBTSxpQ0FBaUMsQ0FBQztBQWtCNUQ7O0dBRUc7QUFDSCxNQUFNLE9BQU8sU0FBVSxTQUFRLE9BQU8sQ0FBQyxNQUFNLENBQUMsWUFBWTtJQVd4RCxZQUFZLE9BQTBCO1FBQ3BDLEtBQUssRUFBRSxDQUFDO1FBVEYsZ0JBQVcsR0FBRyxDQUFDLENBQUM7UUFVdEIsSUFBSSxDQUFDLE9BQU8sR0FBRyxPQUFPLENBQUM7UUFDdkIsSUFBSSxDQUFDLE1BQU0sR0FBRyxJQUFJLFNBQVMsQ0FBcUI7WUFDOUMsU0FBUyxFQUFFLE9BQU8sQ0FBQyxTQUFTO1lBQzVCLElBQUksRUFBRSxRQUFRO1lBQ2Qsa0JBQWtCLEVBQUUsT0FBTyxDQUFDLGtCQUFrQjtTQUMvQyxDQUFDLENBQUM7UUFFSCx3QkFBd0I7UUFDeEIsSUFBSSxDQUFDLE1BQU0sQ0FBQyxFQUFFLENBQUMsY0FBYyxFQUFFLEdBQUcsRUFBRTtZQUNsQyxJQUFJLENBQUMsZ0JBQWdCLENBQUMsK0JBQStCLENBQUMsQ0FBQztRQUN6RCxDQUFDLENBQUMsQ0FBQztRQUNILElBQUksQ0FBQyxNQUFNLENBQUMsRUFBRSxDQUFDLE1BQU0sRUFBRSxDQUFDLElBQW1CLEVBQUUsTUFBcUIsRUFBRSxFQUFFO1lBQ3BFLElBQUksQ0FBQyxnQkFBZ0IsQ0FBQyxzQkFBc0IsQ0FBQyxDQUFDO1lBQzlDLElBQUksQ0FBQyxJQUFJLENBQUMsTUFBTSxFQUFFLEVBQUUsSUFBSSxFQUFFLE1BQU0sRUFBRSxDQUFDLENBQUM7UUFDdEMsQ0FBQyxDQUFDLENBQUM7UUFDSCxJQUFJLENBQUMsTUFBTSxDQUFD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
|
|
@@ -437,6 +437,13 @@ export type TVpnClientCommands = {
|
|
|
437
437
|
};
|
|
438
438
|
result: IVpnManagedSession;
|
|
439
439
|
};
|
|
440
|
+
renewManagedSession: {
|
|
441
|
+
params: {
|
|
442
|
+
generation: string;
|
|
443
|
+
renewal: IVpnManagedSessionRenewal;
|
|
444
|
+
};
|
|
445
|
+
result: IVpnManagedSession;
|
|
446
|
+
};
|
|
440
447
|
connect: {
|
|
441
448
|
params: {
|
|
442
449
|
config: IVpnClientConfig;
|
|
@@ -710,6 +717,18 @@ export interface IVpnManagedSessionConfig {
|
|
|
710
717
|
deadlineBoottimeMs: number;
|
|
711
718
|
};
|
|
712
719
|
}
|
|
720
|
+
/** Moves a live generation's native lease in place. The identity fields must equal
|
|
721
|
+
* the ones the generation authenticated under; a changed credential requires a new
|
|
722
|
+
* session. The lease follows the authentication rules: same boot, future, at most
|
|
723
|
+
* fifteen minutes away. A later or nearer deadline replaces the one in force; a
|
|
724
|
+
* lease whose deadline already passed is final and never revived. */
|
|
725
|
+
export interface IVpnManagedSessionRenewal {
|
|
726
|
+
serverUrl: string;
|
|
727
|
+
serverPublicKey: string;
|
|
728
|
+
clientPublicKey: string;
|
|
729
|
+
managedNetwork: IManagedNetworkBinding;
|
|
730
|
+
lease: IVpnManagedSessionConfig['lease'];
|
|
731
|
+
}
|
|
713
732
|
/** Authentication returns the full validated assignment and planned exclusive
|
|
714
733
|
* TUN name before creating a device or route. Kernel policy remains caller-owned. */
|
|
715
734
|
export interface IVpnManagedSessionPlan {
|
|
@@ -739,6 +758,9 @@ export interface IVpnManagedSession {
|
|
|
739
758
|
* disabled. A stopped TUN stays owned until disconnect() joins deletion, or an
|
|
740
759
|
* owned stdio process is joined by stop(). Socket stop() does not delete it. */
|
|
741
760
|
runtime: IVpnManagedRuntime | null;
|
|
761
|
+
/** The native lease currently in force. `plan.lease` stays the lease the
|
|
762
|
+
* generation authenticated under; renewal moves only this one. */
|
|
763
|
+
lease: IVpnManagedSessionConfig['lease'];
|
|
742
764
|
}
|
|
743
765
|
/** Stopped means the complete packet I/O future ended; retired means the native
|
|
744
766
|
* session owner ended. Neither proves namespace-wide cleanup, conntrack drain,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@push.rocks/smartvpn",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.4.0",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "A VPN solution with TypeScript control plane and Rust data plane daemon",
|
|
6
6
|
"type": "module",
|
|
@@ -28,11 +28,11 @@
|
|
|
28
28
|
"@push.rocks/smartrust": "^2.1.0"
|
|
29
29
|
},
|
|
30
30
|
"devDependencies": {
|
|
31
|
-
"@git.zone/tsbuild": "^
|
|
32
|
-
"@git.zone/tsrun": "^
|
|
33
|
-
"@git.zone/tsrust": "^1.
|
|
34
|
-
"@git.zone/tstest": "^6.
|
|
35
|
-
"@types/node": "^26.
|
|
31
|
+
"@git.zone/tsbuild": "^5.0.0",
|
|
32
|
+
"@git.zone/tsrun": "^3.0.1",
|
|
33
|
+
"@git.zone/tsrust": "^1.15.1",
|
|
34
|
+
"@git.zone/tstest": "^6.3.2",
|
|
35
|
+
"@types/node": "^26.6.2"
|
|
36
36
|
},
|
|
37
37
|
"files": [
|
|
38
38
|
"ts/**/*",
|
package/readme.md
CHANGED
|
@@ -168,7 +168,26 @@ absolute `CLOCK_BOOTTIME` deadline, future and no more than fifteen minutes away
|
|
|
168
168
|
The caller derives this conservative deadline from its independently qualified
|
|
169
169
|
authority; SmartVPN does not turn wall-clock credentials into trusted time.
|
|
170
170
|
Native expiry interrupts the whole packet I/O future, including blocked writes,
|
|
171
|
-
and remains effective across suspend.
|
|
171
|
+
and remains effective across suspend.
|
|
172
|
+
|
|
173
|
+
`renewManagedSession(generation, renewal)` moves a live generation's lease in place,
|
|
174
|
+
without teardown, in the authenticated, prepared or forwarding phase. The renewal
|
|
175
|
+
names `serverUrl`, `serverPublicKey`, `clientPublicKey` and `managedNetwork`; they
|
|
176
|
+
must equal the values the generation authenticated under, because a changed
|
|
177
|
+
credential requires a new session. It carries no private key. Its `lease` follows
|
|
178
|
+
the authentication rules: the same boot, a future deadline, at most fifteen minutes
|
|
179
|
+
away. A later deadline extends the lease and a nearer one re-arms it. A rejected
|
|
180
|
+
renewal leaves the lease in force unchanged. A lease whose deadline has already
|
|
181
|
+
passed is final: packet I/O stops at that deadline, a late renewal rejects, and
|
|
182
|
+
the caller authenticates a new generation. `plan.lease` never changes; every
|
|
183
|
+
session observation reports the lease in force as `lease`.
|
|
184
|
+
|
|
185
|
+
The native lease is only the node's half. The hub ends a session at the node's
|
|
186
|
+
`expiresAt` from its own managed snapshot, so the controller renews that expiry
|
|
187
|
+
by reconciling a snapshot that changes only `expiresAt`. A hub running SmartVPN
|
|
188
|
+
2.3.1 or later keeps the live session through that reconcile; an older hub drains
|
|
189
|
+
it. Renew both halves before the nearer of the two deadlines. Renewal adds no
|
|
190
|
+
message between client and hub, so a 2.4 client works with any 2.3.x hub.
|
|
172
191
|
|
|
173
192
|
Register `managed-session-state`, `managed-session-invalidated` and
|
|
174
193
|
`managed-runtime-invalidated` listeners before
|
package/ts/00_commitinfo_data.ts
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* autocreated commitinfo by @push.rocks/commitinfo
|
|
3
3
|
*/
|
|
4
4
|
export const commitinfo = {
|
|
5
|
-
name:
|
|
6
|
-
version:
|
|
7
|
-
description:
|
|
5
|
+
name: '@push.rocks/smartvpn',
|
|
6
|
+
version: '2.4.0',
|
|
7
|
+
description: 'A VPN solution with TypeScript control plane and Rust data plane daemon'
|
|
8
8
|
}
|
|
@@ -11,6 +11,7 @@ import type {
|
|
|
11
11
|
IVpnManagedRuntime,
|
|
12
12
|
IVpnManagedRuntimeInvalidation,
|
|
13
13
|
IVpnManagedSessionConfig,
|
|
14
|
+
IVpnManagedSessionRenewal,
|
|
14
15
|
IVpnManagedSession,
|
|
15
16
|
IVpnManagedSessionEvent,
|
|
16
17
|
TVpnClientCommands,
|
|
@@ -135,18 +136,35 @@ export class VpnClient extends plugins.events.EventEmitter {
|
|
|
135
136
|
return this.sessionCommand('inspectManagedSession', generation);
|
|
136
137
|
}
|
|
137
138
|
|
|
139
|
+
/** Move the live generation's native lease in place, without teardown. The renewal
|
|
140
|
+
* must name the exact authority the generation authenticated under. A rejected
|
|
141
|
+
* renewal leaves the lease in force unchanged; a lapsed lease is never revived,
|
|
142
|
+
* so authenticate a new generation instead. The hub follows its own expiry from
|
|
143
|
+
* the managed network snapshot (SmartVPN hub 2.3.1 or later keeps the session). */
|
|
144
|
+
public async renewManagedSession(generation: string, renewal: IVpnManagedSessionRenewal): Promise<IVpnManagedSession> {
|
|
145
|
+
this.requireSessionGeneration(generation);
|
|
146
|
+
const epoch = this.bridgeEpoch;
|
|
147
|
+
const result = await this.bridge.sendCommand('renewManagedSession', { generation, renewal });
|
|
148
|
+
this.checkSession(result, epoch, generation);
|
|
149
|
+
return result;
|
|
150
|
+
}
|
|
151
|
+
|
|
138
152
|
private async sessionCommand(method: 'prepareManagedTunnel' | 'enableManagedForwarding'
|
|
139
153
|
| 'stopManagedForwarding' | 'inspectManagedSession', generation: string): Promise<IVpnManagedSession> {
|
|
154
|
+
this.requireSessionGeneration(generation);
|
|
155
|
+
const epoch = this.bridgeEpoch;
|
|
156
|
+
const result = await this.bridge.sendCommand(method, { generation });
|
|
157
|
+
this.checkSession(result, epoch, generation);
|
|
158
|
+
return result;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
private requireSessionGeneration(generation: string): void {
|
|
140
162
|
if (typeof generation !== 'string' || !/^[a-f0-9]{32}$/.test(generation)) {
|
|
141
163
|
throw new Error('Managed session generation must be a native 128-bit identifier');
|
|
142
164
|
}
|
|
143
165
|
if (generation === this.invalidatedSessionGeneration || generation === this.retiredSessionGeneration) {
|
|
144
166
|
throw new Error('Managed session observation is unavailable');
|
|
145
167
|
}
|
|
146
|
-
const epoch = this.bridgeEpoch;
|
|
147
|
-
const result = await this.bridge.sendCommand(method, { generation });
|
|
148
|
-
this.checkSession(result, epoch, generation);
|
|
149
|
-
return result;
|
|
150
168
|
}
|
|
151
169
|
|
|
152
170
|
private checkObservation(runtime: IVpnManagedRuntime, epoch: number, generation?: string): void {
|
|
@@ -496,6 +496,7 @@ export type TVpnClientCommands = {
|
|
|
496
496
|
enableManagedForwarding: { params: { generation: string }; result: IVpnManagedSession };
|
|
497
497
|
stopManagedForwarding: { params: { generation: string }; result: IVpnManagedSession };
|
|
498
498
|
inspectManagedSession: { params: { generation: string }; result: IVpnManagedSession };
|
|
499
|
+
renewManagedSession: { params: { generation: string; renewal: IVpnManagedSessionRenewal }; result: IVpnManagedSession };
|
|
499
500
|
connect: { params: { config: IVpnClientConfig }; result: IVpnConnectionResult };
|
|
500
501
|
inspectManagedRuntime: { params: { generation: string }; result: IVpnManagedRuntime };
|
|
501
502
|
disconnect: { params: Record<string, never>; result: void };
|
|
@@ -627,6 +628,19 @@ export interface IVpnManagedSessionConfig {
|
|
|
627
628
|
lease: { bootId: string; deadlineBoottimeMs: number };
|
|
628
629
|
}
|
|
629
630
|
|
|
631
|
+
/** Moves a live generation's native lease in place. The identity fields must equal
|
|
632
|
+
* the ones the generation authenticated under; a changed credential requires a new
|
|
633
|
+
* session. The lease follows the authentication rules: same boot, future, at most
|
|
634
|
+
* fifteen minutes away. A later or nearer deadline replaces the one in force; a
|
|
635
|
+
* lease whose deadline already passed is final and never revived. */
|
|
636
|
+
export interface IVpnManagedSessionRenewal {
|
|
637
|
+
serverUrl: string;
|
|
638
|
+
serverPublicKey: string;
|
|
639
|
+
clientPublicKey: string;
|
|
640
|
+
managedNetwork: IManagedNetworkBinding;
|
|
641
|
+
lease: IVpnManagedSessionConfig['lease'];
|
|
642
|
+
}
|
|
643
|
+
|
|
630
644
|
/** Authentication returns the full validated assignment and planned exclusive
|
|
631
645
|
* TUN name before creating a device or route. Kernel policy remains caller-owned. */
|
|
632
646
|
export interface IVpnManagedSessionPlan {
|
|
@@ -654,6 +668,9 @@ export interface IVpnManagedSession {
|
|
|
654
668
|
* disabled. A stopped TUN stays owned until disconnect() joins deletion, or an
|
|
655
669
|
* owned stdio process is joined by stop(). Socket stop() does not delete it. */
|
|
656
670
|
runtime: IVpnManagedRuntime | null;
|
|
671
|
+
/** The native lease currently in force. `plan.lease` stays the lease the
|
|
672
|
+
* generation authenticated under; renewal moves only this one. */
|
|
673
|
+
lease: IVpnManagedSessionConfig['lease'];
|
|
657
674
|
}
|
|
658
675
|
|
|
659
676
|
/** Stopped means the complete packet I/O future ended; retired means the native
|