@juspay/neurolink 10.8.11 → 10.8.12
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/CHANGELOG.md +6 -0
- package/dist/cli/commands/proxy.d.ts +20 -1
- package/dist/cli/commands/proxy.js +73 -3
- package/dist/lib/proxy/updateState.d.ts +1 -1
- package/dist/lib/proxy/updateState.js +18 -1
- package/dist/lib/types/cli.d.ts +2 -0
- package/dist/lib/types/proxy.d.ts +9 -0
- package/dist/proxy/updateState.d.ts +1 -1
- package/dist/proxy/updateState.js +18 -1
- package/dist/types/cli.d.ts +2 -0
- package/dist/types/proxy.d.ts +9 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
## [10.8.12](https://github.com/juspay/neurolink/compare/v10.8.11...v10.8.12) (2026-08-04)
|
|
2
|
+
|
|
3
|
+
### Bug Fixes
|
|
4
|
+
|
|
5
|
+
- **(proxy):** report updater activation state truthfully ([d9ea21b](https://github.com/juspay/neurolink/commit/d9ea21b817d292f4354ef653480f06d38917229e))
|
|
6
|
+
|
|
1
7
|
## [10.8.11](https://github.com/juspay/neurolink/compare/v10.8.10...v10.8.11) (2026-08-04)
|
|
2
8
|
|
|
3
9
|
### Bug Fixes
|
|
@@ -11,8 +11,27 @@
|
|
|
11
11
|
*/
|
|
12
12
|
import type { CommandModule } from "yargs";
|
|
13
13
|
import type { Hono } from "hono";
|
|
14
|
-
import type { AccountAllowlist, LoadedProxyConfig, ModelRouterInterface, ProxyGuardArgs, ProxyNeurolinkRuntime, ProxyStartArgs, ProxyStartStrategy, ProxyStatusArgs, ProxyTelemetryArgs, ProxyReadinessState } from "../../lib/types/index.js";
|
|
14
|
+
import type { AccountAllowlist, LoadedProxyConfig, ModelRouterInterface, ProxyGuardArgs, ProxyNeurolinkRuntime, ProxyStartArgs, ProxyStartStrategy, ProxySupervisorState, ProxyStatusArgs, ProxyTelemetryArgs, ProxyReadinessState } from "../../lib/types/index.js";
|
|
15
15
|
import { ProxyRuntimeConfigStore } from "../../lib/proxy/runtimeConfig.js";
|
|
16
|
+
/**
|
|
17
|
+
* Drop a supervisor `version` that is not a string.
|
|
18
|
+
*
|
|
19
|
+
* `StateFileManager.load()` is a bare `JSON.parse(content) as T` — it validates
|
|
20
|
+
* nothing. A state file written by a different build, or half-written during a
|
|
21
|
+
* crash, can carry any JSON type here, and every status renderer interpolates
|
|
22
|
+
* the field straight into `v${...}`. Coercing at the single load boundary keeps
|
|
23
|
+
* a non-string from reaching the output as "v[object Object]".
|
|
24
|
+
*/
|
|
25
|
+
export declare function normalizeSupervisorState(state: ProxySupervisorState | null): ProxySupervisorState | null;
|
|
26
|
+
/**
|
|
27
|
+
* Whether a rolling handoff can actually occur.
|
|
28
|
+
*
|
|
29
|
+
* A live supervisor PID alone is not enough: a supervisor from a build
|
|
30
|
+
* predating rolling state leaves `rolling` absent, and calling that a handoff
|
|
31
|
+
* makes both `/status` clients and the CLI wait for an activation that will
|
|
32
|
+
* never come. Gate on the capability, not on the process.
|
|
33
|
+
*/
|
|
34
|
+
export declare function isRollingHandoffCapable(state: ProxySupervisorState | null, isRunning?: (pid: number) => boolean): boolean;
|
|
16
35
|
/**
|
|
17
36
|
* Best-effort check that a pid actually belongs to a neurolink proxy process,
|
|
18
37
|
* so a stale/recycled supervisor pid is never mistaken for a live supervisor
|
|
@@ -81,8 +81,42 @@ function clearProxyState() {
|
|
|
81
81
|
function saveProxySupervisorState(state) {
|
|
82
82
|
proxySupervisorStateManager.save(state);
|
|
83
83
|
}
|
|
84
|
+
/**
|
|
85
|
+
* Drop a supervisor `version` that is not a string.
|
|
86
|
+
*
|
|
87
|
+
* `StateFileManager.load()` is a bare `JSON.parse(content) as T` — it validates
|
|
88
|
+
* nothing. A state file written by a different build, or half-written during a
|
|
89
|
+
* crash, can carry any JSON type here, and every status renderer interpolates
|
|
90
|
+
* the field straight into `v${...}`. Coercing at the single load boundary keeps
|
|
91
|
+
* a non-string from reaching the output as "v[object Object]".
|
|
92
|
+
*/
|
|
93
|
+
export function normalizeSupervisorState(state) {
|
|
94
|
+
if (!state) {
|
|
95
|
+
return null;
|
|
96
|
+
}
|
|
97
|
+
return typeof state.version === "string" || state.version === undefined
|
|
98
|
+
? state
|
|
99
|
+
: { ...state, version: undefined };
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Whether a rolling handoff can actually occur.
|
|
103
|
+
*
|
|
104
|
+
* A live supervisor PID alone is not enough: a supervisor from a build
|
|
105
|
+
* predating rolling state leaves `rolling` absent, and calling that a handoff
|
|
106
|
+
* makes both `/status` clients and the CLI wait for an activation that will
|
|
107
|
+
* never come. Gate on the capability, not on the process.
|
|
108
|
+
*/
|
|
109
|
+
export function isRollingHandoffCapable(state, isRunning = isProcessRunning) {
|
|
110
|
+
if (!state) {
|
|
111
|
+
return false;
|
|
112
|
+
}
|
|
113
|
+
// Structural, not just non-null: the same unvalidated `as T` load that lets
|
|
114
|
+
// `version` be an object lets `rolling` be a string.
|
|
115
|
+
const hasRollingState = typeof state.rolling === "object" && state.rolling !== null;
|
|
116
|
+
return isRunning(state.pid) && hasRollingState;
|
|
117
|
+
}
|
|
84
118
|
function loadProxySupervisorState() {
|
|
85
|
-
return proxySupervisorStateManager.load();
|
|
119
|
+
return normalizeSupervisorState(proxySupervisorStateManager.load());
|
|
86
120
|
}
|
|
87
121
|
function clearProxySupervisorState() {
|
|
88
122
|
proxySupervisorStateManager.clear();
|
|
@@ -1556,6 +1590,7 @@ export async function createProxyStartApp(params) {
|
|
|
1556
1590
|
: undefined;
|
|
1557
1591
|
const runtimeState = loadProxyState();
|
|
1558
1592
|
const supervisorState = loadProxySupervisorState();
|
|
1593
|
+
const rollingSupervisorRunning = isRollingHandoffCapable(supervisorState);
|
|
1559
1594
|
const updateState = loadUpdateState();
|
|
1560
1595
|
const cooldowns = await loadAccountCooldowns();
|
|
1561
1596
|
const storedAccountKeys = new Set();
|
|
@@ -1779,6 +1814,7 @@ export async function createProxyStartApp(params) {
|
|
|
1779
1814
|
autoUpdate: {
|
|
1780
1815
|
enabled: isProxyAutoUpdateEnabled(),
|
|
1781
1816
|
supervisorPid: supervisorState?.pid ?? null,
|
|
1817
|
+
supervisorVersion: supervisorState?.version ?? null,
|
|
1782
1818
|
rolling: supervisorState?.rolling ?? null,
|
|
1783
1819
|
updaterPid: activeUpdaterPid ?? null,
|
|
1784
1820
|
updaterRunning: activeUpdaterPid
|
|
@@ -1786,7 +1822,16 @@ export async function createProxyStartApp(params) {
|
|
|
1786
1822
|
: false,
|
|
1787
1823
|
liveVersion: PROXY_VERSION,
|
|
1788
1824
|
latestVersion: updateState?.lastCheckVersion || null,
|
|
1825
|
+
lastDetectedVersion: updateState?.lastCheckVersion || null,
|
|
1826
|
+
installedVersion: updateState?.installedVersion ??
|
|
1827
|
+
updateState?.lastUpdateVersion ??
|
|
1828
|
+
null,
|
|
1829
|
+
activatedVersion: PROXY_VERSION,
|
|
1830
|
+
pendingActivationVersion: updateState?.pendingRestartVersion ?? null,
|
|
1789
1831
|
pendingRestartVersion: updateState?.pendingRestartVersion ?? null,
|
|
1832
|
+
activationMode: rollingSupervisorRunning
|
|
1833
|
+
? "rolling-handoff"
|
|
1834
|
+
: "restart",
|
|
1790
1835
|
deferredUpdate: updateState?.deferredUpdate ?? null,
|
|
1791
1836
|
lastCheckAt: updateState?.lastCheckAt ?? null,
|
|
1792
1837
|
lastUpdateAt: updateState?.lastUpdateAt ?? null,
|
|
@@ -2426,6 +2471,7 @@ async function runLaunchdProxySupervisor(argv, spinner) {
|
|
|
2426
2471
|
host,
|
|
2427
2472
|
port,
|
|
2428
2473
|
startTime: supervisorStartedAt,
|
|
2474
|
+
version: PROXY_VERSION,
|
|
2429
2475
|
updaterPid: currentUpdaterPid,
|
|
2430
2476
|
rolling: snapshot,
|
|
2431
2477
|
});
|
|
@@ -2850,11 +2896,18 @@ export const proxyStatusCommand = {
|
|
|
2850
2896
|
autoUpdateEnabled: isProxyAutoUpdateEnabled(),
|
|
2851
2897
|
workerVersion: null,
|
|
2852
2898
|
supervisorPid: null,
|
|
2899
|
+
supervisorVersion: supervisorState?.version ?? null,
|
|
2853
2900
|
supervisorRunning: false,
|
|
2854
2901
|
rolling: null,
|
|
2855
2902
|
updaterPid: null,
|
|
2856
2903
|
updaterRunning: false,
|
|
2857
2904
|
latestVersion: updateState?.lastCheckVersion || null,
|
|
2905
|
+
lastDetectedVersion: updateState?.lastCheckVersion || null,
|
|
2906
|
+
installedVersion: updateState?.installedVersion ??
|
|
2907
|
+
updateState?.lastUpdateVersion ??
|
|
2908
|
+
null,
|
|
2909
|
+
activatedVersion: supervisorState?.rolling.active?.version ?? null,
|
|
2910
|
+
pendingActivationVersion: updateState?.pendingRestartVersion ?? null,
|
|
2858
2911
|
pendingRestartVersion: updateState?.pendingRestartVersion ?? null,
|
|
2859
2912
|
deferredUpdate: updateState?.deferredUpdate ?? null,
|
|
2860
2913
|
lastUpdateFailure: updateState?.lastFailure ?? null,
|
|
@@ -2904,6 +2957,7 @@ export const proxyStatusCommand = {
|
|
|
2904
2957
|
servingState?.lastConfigReloadError ?? null;
|
|
2905
2958
|
status.supervisorPid = supervisorPid ?? null;
|
|
2906
2959
|
status.supervisorRunning = supervisorRunning;
|
|
2960
|
+
status.supervisorVersion = supervisorState?.version ?? null;
|
|
2907
2961
|
status.rolling = supervisorState?.rolling ?? null;
|
|
2908
2962
|
status.updaterPid =
|
|
2909
2963
|
supervisorState?.updaterPid ?? servingState?.updaterPid ?? null;
|
|
@@ -2927,6 +2981,7 @@ export const proxyStatusCommand = {
|
|
|
2927
2981
|
typeof statusData.version === "string"
|
|
2928
2982
|
? statusData.version
|
|
2929
2983
|
: null;
|
|
2984
|
+
status.activatedVersion = status.workerVersion;
|
|
2930
2985
|
if (typeof liveConfig?.generation === "number") {
|
|
2931
2986
|
status.configGeneration = liveConfig.generation;
|
|
2932
2987
|
}
|
|
@@ -2959,6 +3014,9 @@ export const proxyStatusCommand = {
|
|
|
2959
3014
|
if (status.supervisorPid) {
|
|
2960
3015
|
logger.always(` ${chalk.bold("Supervisor:")} ${status.supervisorRunning ? chalk.cyan(status.supervisorPid) : chalk.red(`${status.supervisorPid} (not running)`)}`);
|
|
2961
3016
|
}
|
|
3017
|
+
if (status.supervisorVersion) {
|
|
3018
|
+
logger.always(` ${chalk.bold("Supervisor version:")} ${chalk.cyan(`v${status.supervisorVersion}`)}`);
|
|
3019
|
+
}
|
|
2962
3020
|
if (status.workerVersion) {
|
|
2963
3021
|
logger.always(` ${chalk.bold("Version:")} ${chalk.cyan(`v${status.workerVersion}`)}`);
|
|
2964
3022
|
}
|
|
@@ -2977,8 +3035,14 @@ export const proxyStatusCommand = {
|
|
|
2977
3035
|
logger.always(` ${chalk.bold("Started:")} ${chalk.cyan(status.startTime)}`);
|
|
2978
3036
|
logger.always(` ${chalk.bold("Uptime:")} ${chalk.cyan(formatUptime(status.uptime ?? 0))}`);
|
|
2979
3037
|
logger.always(` ${chalk.bold("Auto-update:")} ${status.autoUpdateEnabled ? chalk.green(status.updaterRunning ? `enabled (PID ${status.updaterPid})` : "enabled (worker unavailable)") : chalk.yellow("disabled")}`);
|
|
2980
|
-
if (status.
|
|
2981
|
-
|
|
3038
|
+
if (status.pendingActivationVersion) {
|
|
3039
|
+
// A live supervisor PID alone does NOT mean rolling handoff is
|
|
3040
|
+
// available: a supervisor from a build predating rolling state leaves
|
|
3041
|
+
// `rolling` absent, and calling that a handoff tells the operator to
|
|
3042
|
+
// wait for an activation that will never come. Gate on the capability,
|
|
3043
|
+
// not on the process.
|
|
3044
|
+
const rollingCapable = status.supervisorRunning && status.rolling !== null;
|
|
3045
|
+
logger.always(` ${chalk.bold(rollingCapable ? "Pending handoff:" : "Pending restart:")} ${chalk.yellow(`v${status.pendingActivationVersion} installed; ${rollingCapable ? "rolling activation pending" : "restart pending"}`)}`);
|
|
2982
3046
|
}
|
|
2983
3047
|
if (status.rolling?.candidate) {
|
|
2984
3048
|
logger.always(` ${chalk.bold("Handoff:")} ${chalk.yellow(`preparing v${status.rolling.candidate.expectedVersion} (PID ${status.rolling.candidate.pid})`)}`);
|
|
@@ -2995,6 +3059,12 @@ export const proxyStatusCommand = {
|
|
|
2995
3059
|
if (status.latestVersion) {
|
|
2996
3060
|
logger.always(` ${chalk.bold("Latest:")} ${chalk.cyan(`v${status.latestVersion}`)}`);
|
|
2997
3061
|
}
|
|
3062
|
+
if (status.installedVersion) {
|
|
3063
|
+
logger.always(` ${chalk.bold("Installed:")} ${chalk.cyan(`v${status.installedVersion}`)}`);
|
|
3064
|
+
}
|
|
3065
|
+
if (status.activatedVersion) {
|
|
3066
|
+
logger.always(` ${chalk.bold("Activated:")} ${chalk.cyan(`v${status.activatedVersion}`)}`);
|
|
3067
|
+
}
|
|
2998
3068
|
if (status.lastUpdateFailure) {
|
|
2999
3069
|
logger.always(` ${chalk.bold("Update error:")} ${chalk.red(`${status.lastUpdateFailure.stage}: ${status.lastUpdateFailure.message}`)}`);
|
|
3000
3070
|
}
|
|
@@ -48,7 +48,7 @@ export declare function suppressVersion(version: string, reason: string, stateFi
|
|
|
48
48
|
* @param stateFilePath - Override path for testing
|
|
49
49
|
*/
|
|
50
50
|
export declare function recordSuccessfulUpdate(version: string, stateFilePath?: string): void;
|
|
51
|
-
/** Record that package
|
|
51
|
+
/** Record that the package was validated but live activation is still pending. */
|
|
52
52
|
export declare function recordUpdateInstalled(version: string, stateFilePath?: string): void;
|
|
53
53
|
/** Abandon a matching installed version so the next cycle may reinstall it. */
|
|
54
54
|
export declare function abandonPendingUpdate(version: string, stateFilePath?: string): boolean;
|
|
@@ -87,6 +87,7 @@ export function getDefaultUpdateState() {
|
|
|
87
87
|
lastCheckAt: new Date(0).toISOString(),
|
|
88
88
|
lastCheckVersion: "",
|
|
89
89
|
suppressedVersions: {},
|
|
90
|
+
installedVersion: null,
|
|
90
91
|
lastUpdateAt: null,
|
|
91
92
|
lastUpdateVersion: null,
|
|
92
93
|
pendingRestartVersion: null,
|
|
@@ -124,6 +125,20 @@ export function loadUpdateState(stateFilePath) {
|
|
|
124
125
|
...getDefaultUpdateState(),
|
|
125
126
|
...candidate,
|
|
126
127
|
suppressedVersions: candidate.suppressedVersions ?? {},
|
|
128
|
+
// Backfill order matters for state files written before `installedVersion`
|
|
129
|
+
// existed. Back then `recordUpdateInstalled()` set ONLY
|
|
130
|
+
// `pendingRestartVersion`, leaving `lastUpdateVersion` on the previously
|
|
131
|
+
// activated build — so a validated-but-not-yet-running update lives in
|
|
132
|
+
// `pendingRestartVersion` and is the newer of the two. Reading
|
|
133
|
+
// `lastUpdateVersion` first would report the superseded version as
|
|
134
|
+
// installed and re-offer an update that is already on disk.
|
|
135
|
+
installedVersion: typeof candidate.installedVersion === "string"
|
|
136
|
+
? candidate.installedVersion
|
|
137
|
+
: typeof candidate.pendingRestartVersion === "string"
|
|
138
|
+
? candidate.pendingRestartVersion
|
|
139
|
+
: typeof candidate.lastUpdateVersion === "string"
|
|
140
|
+
? candidate.lastUpdateVersion
|
|
141
|
+
: null,
|
|
127
142
|
pendingRestartVersion: typeof candidate.pendingRestartVersion === "string"
|
|
128
143
|
? candidate.pendingRestartVersion
|
|
129
144
|
: null,
|
|
@@ -208,15 +223,17 @@ export function recordSuccessfulUpdate(version, stateFilePath) {
|
|
|
208
223
|
const state = loadUpdateState(stateFilePath) ?? getDefaultUpdateState();
|
|
209
224
|
state.lastUpdateAt = new Date().toISOString();
|
|
210
225
|
state.lastUpdateVersion = version;
|
|
226
|
+
state.installedVersion = version;
|
|
211
227
|
state.pendingRestartVersion = null;
|
|
212
228
|
state.deferredUpdate = null;
|
|
213
229
|
state.lastFailure = null;
|
|
214
230
|
delete state.suppressedVersions[version];
|
|
215
231
|
saveUpdateState(state, stateFilePath);
|
|
216
232
|
}
|
|
217
|
-
/** Record that package
|
|
233
|
+
/** Record that the package was validated but live activation is still pending. */
|
|
218
234
|
export function recordUpdateInstalled(version, stateFilePath) {
|
|
219
235
|
const state = loadUpdateState(stateFilePath) ?? getDefaultUpdateState();
|
|
236
|
+
state.installedVersion = version;
|
|
220
237
|
state.pendingRestartVersion = version;
|
|
221
238
|
state.lastFailure = null;
|
|
222
239
|
saveUpdateState(state, stateFilePath);
|
package/dist/lib/types/cli.d.ts
CHANGED
|
@@ -1724,6 +1724,15 @@ export type UpdateState = {
|
|
|
1724
1724
|
lastCheckAt: string;
|
|
1725
1725
|
lastCheckVersion: string;
|
|
1726
1726
|
suppressedVersions: Record<string, SuppressedVersion>;
|
|
1727
|
+
/**
|
|
1728
|
+
* Last package version whose stable trampoline was successfully validated.
|
|
1729
|
+
*
|
|
1730
|
+
* Optional because `UpdateState` is part of the published type surface and a
|
|
1731
|
+
* required addition would break every downstream object literal — and because
|
|
1732
|
+
* state files written before this field existed legitimately omit it.
|
|
1733
|
+
* `loadUpdateState()` always materializes it, so runtime readers see a value.
|
|
1734
|
+
*/
|
|
1735
|
+
installedVersion?: string | null;
|
|
1727
1736
|
lastUpdateAt: string | null;
|
|
1728
1737
|
lastUpdateVersion: string | null;
|
|
1729
1738
|
/** Installed by the updater but not yet confirmed as the running version. */
|
|
@@ -48,7 +48,7 @@ export declare function suppressVersion(version: string, reason: string, stateFi
|
|
|
48
48
|
* @param stateFilePath - Override path for testing
|
|
49
49
|
*/
|
|
50
50
|
export declare function recordSuccessfulUpdate(version: string, stateFilePath?: string): void;
|
|
51
|
-
/** Record that package
|
|
51
|
+
/** Record that the package was validated but live activation is still pending. */
|
|
52
52
|
export declare function recordUpdateInstalled(version: string, stateFilePath?: string): void;
|
|
53
53
|
/** Abandon a matching installed version so the next cycle may reinstall it. */
|
|
54
54
|
export declare function abandonPendingUpdate(version: string, stateFilePath?: string): boolean;
|
|
@@ -87,6 +87,7 @@ export function getDefaultUpdateState() {
|
|
|
87
87
|
lastCheckAt: new Date(0).toISOString(),
|
|
88
88
|
lastCheckVersion: "",
|
|
89
89
|
suppressedVersions: {},
|
|
90
|
+
installedVersion: null,
|
|
90
91
|
lastUpdateAt: null,
|
|
91
92
|
lastUpdateVersion: null,
|
|
92
93
|
pendingRestartVersion: null,
|
|
@@ -124,6 +125,20 @@ export function loadUpdateState(stateFilePath) {
|
|
|
124
125
|
...getDefaultUpdateState(),
|
|
125
126
|
...candidate,
|
|
126
127
|
suppressedVersions: candidate.suppressedVersions ?? {},
|
|
128
|
+
// Backfill order matters for state files written before `installedVersion`
|
|
129
|
+
// existed. Back then `recordUpdateInstalled()` set ONLY
|
|
130
|
+
// `pendingRestartVersion`, leaving `lastUpdateVersion` on the previously
|
|
131
|
+
// activated build — so a validated-but-not-yet-running update lives in
|
|
132
|
+
// `pendingRestartVersion` and is the newer of the two. Reading
|
|
133
|
+
// `lastUpdateVersion` first would report the superseded version as
|
|
134
|
+
// installed and re-offer an update that is already on disk.
|
|
135
|
+
installedVersion: typeof candidate.installedVersion === "string"
|
|
136
|
+
? candidate.installedVersion
|
|
137
|
+
: typeof candidate.pendingRestartVersion === "string"
|
|
138
|
+
? candidate.pendingRestartVersion
|
|
139
|
+
: typeof candidate.lastUpdateVersion === "string"
|
|
140
|
+
? candidate.lastUpdateVersion
|
|
141
|
+
: null,
|
|
127
142
|
pendingRestartVersion: typeof candidate.pendingRestartVersion === "string"
|
|
128
143
|
? candidate.pendingRestartVersion
|
|
129
144
|
: null,
|
|
@@ -208,15 +223,17 @@ export function recordSuccessfulUpdate(version, stateFilePath) {
|
|
|
208
223
|
const state = loadUpdateState(stateFilePath) ?? getDefaultUpdateState();
|
|
209
224
|
state.lastUpdateAt = new Date().toISOString();
|
|
210
225
|
state.lastUpdateVersion = version;
|
|
226
|
+
state.installedVersion = version;
|
|
211
227
|
state.pendingRestartVersion = null;
|
|
212
228
|
state.deferredUpdate = null;
|
|
213
229
|
state.lastFailure = null;
|
|
214
230
|
delete state.suppressedVersions[version];
|
|
215
231
|
saveUpdateState(state, stateFilePath);
|
|
216
232
|
}
|
|
217
|
-
/** Record that package
|
|
233
|
+
/** Record that the package was validated but live activation is still pending. */
|
|
218
234
|
export function recordUpdateInstalled(version, stateFilePath) {
|
|
219
235
|
const state = loadUpdateState(stateFilePath) ?? getDefaultUpdateState();
|
|
236
|
+
state.installedVersion = version;
|
|
220
237
|
state.pendingRestartVersion = version;
|
|
221
238
|
state.lastFailure = null;
|
|
222
239
|
saveUpdateState(state, stateFilePath);
|
package/dist/types/cli.d.ts
CHANGED
package/dist/types/proxy.d.ts
CHANGED
|
@@ -1724,6 +1724,15 @@ export type UpdateState = {
|
|
|
1724
1724
|
lastCheckAt: string;
|
|
1725
1725
|
lastCheckVersion: string;
|
|
1726
1726
|
suppressedVersions: Record<string, SuppressedVersion>;
|
|
1727
|
+
/**
|
|
1728
|
+
* Last package version whose stable trampoline was successfully validated.
|
|
1729
|
+
*
|
|
1730
|
+
* Optional because `UpdateState` is part of the published type surface and a
|
|
1731
|
+
* required addition would break every downstream object literal — and because
|
|
1732
|
+
* state files written before this field existed legitimately omit it.
|
|
1733
|
+
* `loadUpdateState()` always materializes it, so runtime readers see a value.
|
|
1734
|
+
*/
|
|
1735
|
+
installedVersion?: string | null;
|
|
1727
1736
|
lastUpdateAt: string | null;
|
|
1728
1737
|
lastUpdateVersion: string | null;
|
|
1729
1738
|
/** Installed by the updater but not yet confirmed as the running version. */
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@juspay/neurolink",
|
|
3
|
-
"version": "10.8.
|
|
3
|
+
"version": "10.8.12",
|
|
4
4
|
"packageManager": "pnpm@10.15.1",
|
|
5
5
|
"description": "TypeScript AI SDK with 24+ LLM providers behind one consistent API. MCP-native (connect any MCP server), voice TTS/STT/realtime, RAG, agents, memory, context compaction. OpenAI · Anthropic · Gemini · Bedrock · Azure · Ollama · DeepSeek · NVIDIA NIM and more.",
|
|
6
6
|
"author": {
|