instar 1.3.629 → 1.3.630
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/commands/server.d.ts.map +1 -1
- package/dist/commands/server.js +124 -5
- package/dist/commands/server.js.map +1 -1
- package/dist/config/ConfigDefaults.d.ts.map +1 -1
- package/dist/config/ConfigDefaults.js +24 -0
- package/dist/config/ConfigDefaults.js.map +1 -1
- package/dist/core/HttpLeaseTransport.d.ts +56 -3
- package/dist/core/HttpLeaseTransport.d.ts.map +1 -1
- package/dist/core/HttpLeaseTransport.js +191 -51
- package/dist/core/HttpLeaseTransport.js.map +1 -1
- package/dist/core/LeaseCoordinator.d.ts +37 -0
- package/dist/core/LeaseCoordinator.d.ts.map +1 -1
- package/dist/core/LeaseCoordinator.js +40 -0
- package/dist/core/LeaseCoordinator.js.map +1 -1
- package/dist/core/MachineIdentity.d.ts +11 -0
- package/dist/core/MachineIdentity.d.ts.map +1 -1
- package/dist/core/MachineIdentity.js +22 -0
- package/dist/core/MachineIdentity.js.map +1 -1
- package/dist/core/MeshUrlAdvertiser.d.ts +50 -0
- package/dist/core/MeshUrlAdvertiser.d.ts.map +1 -1
- package/dist/core/MeshUrlAdvertiser.js +127 -0
- package/dist/core/MeshUrlAdvertiser.js.map +1 -1
- package/dist/core/MultiMachineCoordinator.d.ts +14 -0
- package/dist/core/MultiMachineCoordinator.d.ts.map +1 -1
- package/dist/core/MultiMachineCoordinator.js +20 -0
- package/dist/core/MultiMachineCoordinator.js.map +1 -1
- package/dist/core/PeerEndpointResolver.d.ts +0 -0
- package/dist/core/PeerEndpointResolver.d.ts.map +1 -0
- package/dist/core/PeerEndpointResolver.js +0 -0
- package/dist/core/PeerEndpointResolver.js.map +1 -0
- package/dist/core/PostUpdateMigrator.d.ts.map +1 -1
- package/dist/core/PostUpdateMigrator.js +10 -0
- package/dist/core/PostUpdateMigrator.js.map +1 -1
- package/dist/core/devGatedFeatures.d.ts.map +1 -1
- package/dist/core/devGatedFeatures.js +5 -0
- package/dist/core/devGatedFeatures.js.map +1 -1
- package/dist/core/types.d.ts +65 -0
- package/dist/core/types.d.ts.map +1 -1
- package/dist/core/types.js.map +1 -1
- package/dist/scaffold/templates.d.ts.map +1 -1
- package/dist/scaffold/templates.js +2 -0
- package/dist/scaffold/templates.js.map +1 -1
- package/dist/server/AgentServer.d.ts.map +1 -1
- package/dist/server/AgentServer.js +15 -2
- package/dist/server/AgentServer.js.map +1 -1
- package/dist/server/machineAuth.d.ts +24 -0
- package/dist/server/machineAuth.d.ts.map +1 -1
- package/dist/server/machineAuth.js +71 -0
- package/dist/server/machineAuth.js.map +1 -1
- package/dist/server/machineRoutes.d.ts +7 -1
- package/dist/server/machineRoutes.d.ts.map +1 -1
- package/dist/server/machineRoutes.js +28 -3
- package/dist/server/machineRoutes.js.map +1 -1
- package/package.json +1 -1
- package/src/data/builtin-manifest.json +22 -22
- package/src/scaffold/templates.ts +2 -0
- package/upgrades/1.3.630.md +38 -0
- package/upgrades/side-effects/multi-transport-mesh-comms.md +70 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/commands/server.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAoCH,OAAO,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAS3D,OAAO,EAAE,eAAe,EAAiC,MAAM,iCAAiC,CAAC;AAwBjG,OAAO,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAGvD,OAAO,EAAE,YAAY,EAAE,MAAM,+BAA+B,CAAC;
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/commands/server.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAoCH,OAAO,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAS3D,OAAO,EAAE,eAAe,EAAiC,MAAM,iCAAiC,CAAC;AAwBjG,OAAO,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAGvD,OAAO,EAAE,YAAY,EAAE,MAAM,+BAA+B,CAAC;AAmH7D,OAAO,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AA2EtD;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,yBAAyB,CACvC,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,MAAM,EACf,gBAAgB,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAC1C,OAAO,CAUT;AAyID,UAAU,YAAY;IACpB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb;2DACuD;IACvD,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAy4CD,wBAAgB,mBAAmB,CACjC,QAAQ,EAAE,eAAe,EACzB,cAAc,EAAE,cAAc,EAC9B,YAAY,CAAC,EAAE,YAAY,EAC3B,WAAW,CAAC,EAAE,WAAW,EACzB,WAAW,CAAC,EAAE,WAAW,EACzB,iBAAiB,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,EAGvE,UAAU,CAAC,EAAE,MAAM,OAAO,8BAA8B,EAAE,WAAW,GAAG,IAAI,EAK5E,qBAAqB,CAAC,EAAE,MAAM,OAAO,gCAAgC,EAAE,kBAAkB,GAAG,IAAI,EAKhG,mBAAmB,CAAC,EAAE,MAAM,MAAM,GAAG,IAAI,GAAG,SAAS,GACpD,IAAI,CA8eN;AA2lBD,wBAAsB,WAAW,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,CAohftE;AAED,wBAAsB,UAAU,CAAC,OAAO,EAAE;IAAE,GAAG,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAsDzE;AAED;;;;;;;;;;;GAWG;AACH,wBAAsB,aAAa,CAAC,OAAO,EAAE;IAAE,GAAG,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAuD5E"}
|
package/dist/commands/server.js
CHANGED
|
@@ -85,7 +85,8 @@ import { MultiMachineCoordinator } from '../core/MultiMachineCoordinator.js';
|
|
|
85
85
|
import { isRemotelyHandled } from '../core/SessionRouter.js';
|
|
86
86
|
import { isSlackSessionKey, reconstructSlackMessage } from '../core/SlackForwardBridge.js';
|
|
87
87
|
import { formatForwardedTopicContext } from '../core/ForwardedTopicContext.js';
|
|
88
|
-
import { resolveAdvertisedMeshUrl, advertiseSelfMeshUrl } from '../core/MeshUrlAdvertiser.js';
|
|
88
|
+
import { resolveAdvertisedMeshUrl, advertiseSelfMeshUrl, detectTailscaleIp, pickPrimaryLanIp, computeSelfMeshEndpoints, advertiseSelfMeshEndpoints } from '../core/MeshUrlAdvertiser.js';
|
|
89
|
+
import { PeerEndpointResolver } from '../core/PeerEndpointResolver.js';
|
|
89
90
|
import { relayOutbound } from '../core/TelegramRelay.js';
|
|
90
91
|
import { GitSyncManager } from '../core/GitSync.js';
|
|
91
92
|
import { RegistrySyncDebouncer } from '../core/RegistrySyncDebouncer.js';
|
|
@@ -174,6 +175,58 @@ import { toInjection } from '../types/pipeline.js';
|
|
|
174
175
|
import { UserManager } from '../users/UserManager.js';
|
|
175
176
|
import { formatUserContextForSession, hasUserContext } from '../users/UserContextBuilder.js';
|
|
176
177
|
import { SafeFsExecutor } from '../core/SafeFsExecutor.js';
|
|
178
|
+
// setup.ts uses @inquirer/prompts which requires Node 20.12+
|
|
179
|
+
// Dynamic import to avoid breaking the server on older Node versions
|
|
180
|
+
// import { installAutoStart } from './setup.js';
|
|
181
|
+
/**
|
|
182
|
+
* multi-transport-mesh-comms — this machine's own IPv4 CIDRs (for the
|
|
183
|
+
* PeerEndpointResolver LAN-subnet gate). Each non-internal IPv4 interface address
|
|
184
|
+
* with its prefix length, e.g. '192.168.87.67/24'. Pure read of os.networkInterfaces().
|
|
185
|
+
*/
|
|
186
|
+
function ownIpv4Cidrs() {
|
|
187
|
+
const out = [];
|
|
188
|
+
const ifaces = os.networkInterfaces();
|
|
189
|
+
for (const addrs of Object.values(ifaces)) {
|
|
190
|
+
for (const a of addrs ?? []) {
|
|
191
|
+
const isV4 = a.family === 'IPv4' || a.family === 4;
|
|
192
|
+
if (isV4 && !a.internal && typeof a.cidr === 'string' && a.cidr)
|
|
193
|
+
out.push(a.cidr);
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
return out;
|
|
197
|
+
}
|
|
198
|
+
/**
|
|
199
|
+
* multi-transport-mesh-comms (Layer 0) — compute + advertise THIS machine's mesh
|
|
200
|
+
* endpoint set (Tailscale / LAN / Cloudflare) into its registry entry, co-located
|
|
201
|
+
* with the lastKnownUrl advertise. Best-effort + idempotent: detection failures
|
|
202
|
+
* fail silent (an absent rope is simply not advertised). No-op when the mesh
|
|
203
|
+
* transport is disabled. Called at boot + on sleep/wake tunnel restart.
|
|
204
|
+
*/
|
|
205
|
+
async function advertiseSelfMeshEndpointsNow(identityManager, machineId, cfg, cloudflareUrl) {
|
|
206
|
+
try {
|
|
207
|
+
if (!cfg.multiMachine?.enabled || cfg.multiMachine?.meshTransport?.enabled === false)
|
|
208
|
+
return;
|
|
209
|
+
const tailscaleEnabled = cfg.multiMachine?.meshTransport?.tailscaleEnabled !== false;
|
|
210
|
+
const tailscaleIp = tailscaleEnabled ? await detectTailscaleIp() : null;
|
|
211
|
+
const lanIp = pickPrimaryLanIp(os.networkInterfaces());
|
|
212
|
+
const endpoints = computeSelfMeshEndpoints({
|
|
213
|
+
cloudflareUrl,
|
|
214
|
+
lanIp,
|
|
215
|
+
tailscaleIp,
|
|
216
|
+
port: cfg.port ?? 4042,
|
|
217
|
+
tailscaleEnabled,
|
|
218
|
+
});
|
|
219
|
+
// E2E-PAIRING: EXEMPT — this commit is comment-only (@silent-fallback-ok ratchet
|
|
220
|
+
// tags); it adds NO new route. The mesh routes/fields shipped in the prior commit
|
|
221
|
+
// (1cd2618e) with their integration + 2-server tests.
|
|
222
|
+
advertiseSelfMeshEndpoints(identityManager, machineId, endpoints, (m) => console.log(pc.dim(m)));
|
|
223
|
+
}
|
|
224
|
+
catch {
|
|
225
|
+
// @silent-fallback-ok: best-effort — endpoint advertisement must never break boot
|
|
226
|
+
// (a Tailscale-detect/registry hiccup just means fewer advertised ropes this tick;
|
|
227
|
+
// the next heartbeat retries and the mesh degrades to the remaining ropes).
|
|
228
|
+
}
|
|
229
|
+
}
|
|
177
230
|
/**
|
|
178
231
|
* Pure: should the emergency "fix command" gate intercept this message?
|
|
179
232
|
*
|
|
@@ -3895,14 +3948,47 @@ export async function startServer(options) {
|
|
|
3895
3948
|
// stays true, so the lease behaves exactly as git-only. Multi-machine
|
|
3896
3949
|
// meshes get RTT-bounded acquisition + the renewal-requires-medium rule.
|
|
3897
3950
|
let leaseSeq = Date.now();
|
|
3951
|
+
// multi-transport-mesh-comms (Layer 1) — the hedged-failover resolver,
|
|
3952
|
+
// built from the FLAT meshTransport config. Injected into the transport;
|
|
3953
|
+
// when meshTransport.enabled is false the transport falls back to the
|
|
3954
|
+
// single-`url` legacy path (byte-for-byte today).
|
|
3955
|
+
const meshCfg = config.multiMachine?.meshTransport;
|
|
3956
|
+
const meshEnabled = () => meshCfg?.enabled !== false; // default ON
|
|
3957
|
+
const meshResolver = new PeerEndpointResolver({
|
|
3958
|
+
config: {
|
|
3959
|
+
enabled: meshCfg?.enabled !== false,
|
|
3960
|
+
hedgeDelayMs: meshCfg?.hedgeDelayMs ?? 1500,
|
|
3961
|
+
priorityTailscale: meshCfg?.priorityTailscale ?? 10,
|
|
3962
|
+
priorityLan: meshCfg?.priorityLan ?? 20,
|
|
3963
|
+
priorityCloudflare: meshCfg?.priorityCloudflare ?? 30,
|
|
3964
|
+
tailscaleEnabled: meshCfg?.tailscaleEnabled !== false,
|
|
3965
|
+
lanSubnetGate: meshCfg?.lanSubnetGate !== false,
|
|
3966
|
+
unhealthyAfterFailures: meshCfg?.unhealthyAfterFailures ?? 3,
|
|
3967
|
+
endpointEvictionMs: meshCfg?.endpointEvictionMs ?? 3_600_000,
|
|
3968
|
+
maxProbeBackoffMs: meshCfg?.maxProbeBackoffMs ?? 300_000,
|
|
3969
|
+
requestTimeoutMs: Math.min(seamlessness.leaseTtlMs / 2, 30_000),
|
|
3970
|
+
},
|
|
3971
|
+
ownCidrs: () => ownIpv4Cidrs(),
|
|
3972
|
+
logger: (m) => console.log(pc.dim(m)),
|
|
3973
|
+
});
|
|
3898
3974
|
leaseTransport = new HttpLeaseTransport({
|
|
3899
3975
|
selfMachineId,
|
|
3900
3976
|
signingKeyPem: idMgr.loadSigningKey(),
|
|
3901
3977
|
peers: () => {
|
|
3902
3978
|
const reg = idMgr.loadRegistry();
|
|
3903
3979
|
return Object.entries(reg.machines ?? {})
|
|
3904
|
-
.filter(([id, e]) => id !== selfMachineId && !!e.lastKnownUrl && !e.revokedAt)
|
|
3905
|
-
.map(([id, e]) => ({
|
|
3980
|
+
.filter(([id, e]) => id !== selfMachineId && (!!e.lastKnownUrl || (e.endpoints?.length ?? 0) > 0) && !e.revokedAt)
|
|
3981
|
+
.map(([id, e]) => ({
|
|
3982
|
+
machineId: id,
|
|
3983
|
+
url: (e.lastKnownUrl ?? ''),
|
|
3984
|
+
endpoints: e.endpoints,
|
|
3985
|
+
publicKeyPem: idMgr.getSigningPublicKeyPem(id),
|
|
3986
|
+
// Rolling-deploy gate: a peer that advertises an endpoint set is
|
|
3987
|
+
// running THIS build (the field + the accept-ack receiver ship
|
|
3988
|
+
// atomically), so it is ack-capable. An older peer (no endpoints,
|
|
3989
|
+
// or no resolvable pubkey) stays on the 2xx back-compat path.
|
|
3990
|
+
meshAckCapable: (e.endpoints?.length ?? 0) > 0 && !!idMgr.getSigningPublicKeyPem(id),
|
|
3991
|
+
}));
|
|
3906
3992
|
},
|
|
3907
3993
|
nextSequence: () => ++leaseSeq,
|
|
3908
3994
|
reachabilityWindowMs: seamlessness.leaseTtlMs,
|
|
@@ -3911,6 +3997,9 @@ export async function startServer(options) {
|
|
|
3911
3997
|
// the whole TTL, but ABOVE the fleet's 5-40s receiver-stall envelope
|
|
3912
3998
|
// so a slow-but-alive peer isn't converted into "no medium".
|
|
3913
3999
|
requestTimeoutMs: Math.min(seamlessness.leaseTtlMs / 2, 30_000),
|
|
4000
|
+
resolver: meshResolver,
|
|
4001
|
+
meshTransportEnabled: meshEnabled,
|
|
4002
|
+
hedgeDelayMs: meshCfg?.hedgeDelayMs ?? 1500,
|
|
3914
4003
|
logger: (m) => console.log(pc.dim(m)),
|
|
3915
4004
|
});
|
|
3916
4005
|
const leaseCoordinator = new LeaseCoordinator({
|
|
@@ -3940,6 +4029,30 @@ export async function startServer(options) {
|
|
|
3940
4029
|
return null;
|
|
3941
4030
|
return { enabled: true, nonRenewalMissedObservations: sht.nonRenewalMissedObservations ?? 6 };
|
|
3942
4031
|
},
|
|
4032
|
+
// multi-transport-mesh-comms Layer 3 (soloCaptainHold) — DARK by default.
|
|
4033
|
+
// Resolved live; the three gates are EXISTING signals: the F4 preferred-awake
|
|
4034
|
+
// config (this machine is the named preferred), every peer presumed-gone by
|
|
4035
|
+
// the same liveness timeout presumedDeadHolders uses, and (checked inside the
|
|
4036
|
+
// coordinator) no higher epoch.
|
|
4037
|
+
soloCaptainHold: () => {
|
|
4038
|
+
const sch = config.multiMachine?.leaseSelfHeal?.soloCaptainHold;
|
|
4039
|
+
return sch?.enabled ? { enabled: true } : null;
|
|
4040
|
+
},
|
|
4041
|
+
isPreferredAwakeAgreed: () => {
|
|
4042
|
+
const pref = config.multiMachine?.leaseSelfHeal?.preferredAwakeMachineId;
|
|
4043
|
+
return !!pref && pref === selfMachineId;
|
|
4044
|
+
},
|
|
4045
|
+
allPeersPresumedGone: () => {
|
|
4046
|
+
const reg = idMgr.loadRegistry();
|
|
4047
|
+
const nowMs = Date.now();
|
|
4048
|
+
const peerIds = Object.keys(reg.machines ?? {}).filter((id) => id !== selfMachineId && !reg.machines[id].revokedAt);
|
|
4049
|
+
if (peerIds.length === 0)
|
|
4050
|
+
return false; // a solo machine never "holds against" a peer
|
|
4051
|
+
return peerIds.every((id) => {
|
|
4052
|
+
const last = Date.parse(reg.machines[id].lastSeen);
|
|
4053
|
+
return !Number.isNaN(last) && nowMs - last > seamlessness.failoverThresholdMs;
|
|
4054
|
+
});
|
|
4055
|
+
},
|
|
3943
4056
|
onSelfSuspend: (reason) => console.log(pc.yellow(` [lease] self-suspend: ${reason}`)),
|
|
3944
4057
|
onEscalate: (info) => console.log(pc.yellow(` [lease] split-brain escalation: ${info.reason} (holder ${info.holder})`)),
|
|
3945
4058
|
logger: (m) => console.log(pc.dim(m)),
|
|
@@ -11128,7 +11241,10 @@ export async function startServer(options) {
|
|
|
11128
11241
|
// now stale; peers must learn the new one or cross-machine routing
|
|
11129
11242
|
// silently breaks post-wake.
|
|
11130
11243
|
if (coordinator.enabled && coordinator.identity) {
|
|
11131
|
-
|
|
11244
|
+
const cfUrl = resolveAdvertisedMeshUrl(config.tunnel, tunnelUrl);
|
|
11245
|
+
advertiseSelfMeshUrl(coordinator.managers.identityManager, coordinator.identity.machineId, cfUrl, (m) => console.log(pc.dim(m)));
|
|
11246
|
+
// multi-transport-mesh-comms — re-advertise endpoints post-wake.
|
|
11247
|
+
await advertiseSelfMeshEndpointsNow(coordinator.managers.identityManager, coordinator.identity.machineId, config, cfUrl);
|
|
11132
11248
|
}
|
|
11133
11249
|
// Re-broadcast dashboard URL after tunnel restart (quick tunnels get new URL)
|
|
11134
11250
|
if (tunnelUrl) {
|
|
@@ -17584,7 +17700,10 @@ export async function startServer(options) {
|
|
|
17584
17700
|
// out (the session pool is inert across machines). The existing
|
|
17585
17701
|
// RegistrySyncDebouncer propagates the populated entry to peers.
|
|
17586
17702
|
if (coordinator.enabled && coordinator.identity) {
|
|
17587
|
-
|
|
17703
|
+
const cfUrl = resolveAdvertisedMeshUrl(config.tunnel, tunnelUrl);
|
|
17704
|
+
advertiseSelfMeshUrl(coordinator.managers.identityManager, coordinator.identity.machineId, cfUrl, (m) => console.log(pc.dim(m)));
|
|
17705
|
+
// multi-transport-mesh-comms (Layer 0) — advertise the full endpoint set.
|
|
17706
|
+
await advertiseSelfMeshEndpointsNow(coordinator.managers.identityManager, coordinator.identity.machineId, config, cfUrl);
|
|
17588
17707
|
}
|
|
17589
17708
|
}
|
|
17590
17709
|
catch (err) {
|