Skip to content

fix(developer): ngrok upgrade#15626

Open
mcdurdin wants to merge 2 commits intomasterfrom
fix/developer/15625-ngrok-upgrade
Open

fix(developer): ngrok upgrade#15626
mcdurdin wants to merge 2 commits intomasterfrom
fix/developer/15625-ngrok-upgrade

Conversation

@mcdurdin
Copy link
Member

@mcdurdin mcdurdin commented Feb 25, 2026

The existing ngrok package is no longer maintained, so this PR switches to @ngrok/ngrok. However, this means a number of deployment changes, as the new module uses a node binary module rather than a standalone executable, and the path to the module is assumed to be on the Node search path.

The new module also requires VC++ redistributable, so installation of that has been added to the Server Options dialog.

Use of ngrok with Keyman Developer Server should be in theory possible with non-Windows platforms with this change, if the user installs the appropriate @ngrok binary package (e.g. @ngrok/ngrok-darwin-universal) globally before starting the server.

  • cherry-pick to 18

Fixes: #15625
Build-bot: skip release:developer

User Testing

  • TEST_NGROK: On a clean virtual machine, install Keyman Developer, and enable Ngrok through the Server Options dialog box in Keyman Developer. Verify that ngrok is working correctly by trying to open the ngrok hosted version of the Server pages through Tools/Server/Open {url} in Browser.

@github-project-automation github-project-automation bot moved this to Todo in Keyman Feb 25, 2026
@keymanapp-test-bot keymanapp-test-bot bot added the user-test-missing User tests have not yet been defined for the PR label Feb 25, 2026
@keymanapp-test-bot
Copy link

keymanapp-test-bot bot commented Feb 25, 2026

User Test Results

Test specification and instructions

  • TEST_NGROK (OPEN)
Results Template
# Test Results

* **TEST_NGROK (OPEN):** notes

Test Artifacts

@keymanapp-test-bot keymanapp-test-bot bot added this to the A19S23 milestone Feb 25, 2026
@mcdurdin mcdurdin force-pushed the fix/developer/15625-ngrok-upgrade branch from a3b9712 to 5ba298c Compare February 25, 2026 13:58
The existing ngrok package is no longer maintained, so this commit
switches to @ngrok/ngrok. However, this means a number of deployment
changes, as the new module uses a node binary module rather than a
standalone executable, and the path to the module is assumed to be on
the Node search path.

The new module also requires VC++ redistributable, so installation of
that has been added to the Server Options dialog.

Use of ngrok with Keyman Developer Server should be in theory possible
with non-Windows platforms with this change, if the user installs the
appropriate @ngrok binary package (e.g. @ngrok/ngrok-darwin-universal)
globally before starting the server.

Fixes: #15625
Build-bot: skip release:developer
@mcdurdin mcdurdin force-pushed the fix/developer/15625-ngrok-upgrade branch from 5ba298c to 7d8e397 Compare February 26, 2026 09:07
@keymanapp-test-bot keymanapp-test-bot bot added has-user-test user-test-required User tests have not been completed labels Feb 26, 2026
@mcdurdin mcdurdin marked this pull request as ready for review February 26, 2026 09:15
@keymanapp-test-bot keymanapp-test-bot bot removed the user-test-missing User tests have not yet been defined for the PR label Feb 26, 2026
Comment on lines -55 to -58
# See https://github.com/bubenshchykov/ngrok/issues/254, https://github.com/bubenshchykov/ngrok/pull/255
# TODO: this is horrible; is there a way we can avoid this?
rm -f "$KEYMAN_ROOT"/node_modules/ngrok/bin/ngrok
rm -f "$KEYMAN_ROOT"/node_modules/ngrok/bin/ngrok.exe
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is no longer required with the new ngrok module

mcdurdin added a commit that referenced this pull request Feb 26, 2026
The existing ngrok package is no longer maintained, so this commit
switches to @ngrok/ngrok. However, this means a number of deployment
changes, as the new module uses a node binary module rather than a
standalone executable, and the path to the module is assumed to be on
the Node search path.

The new module also requires VC++ redistributable, so installation of
that has been added to the Server Options dialog.

Use of ngrok with Keyman Developer Server should be in theory possible
with non-Windows platforms with this change, if the user installs the
appropriate @ngrok binary package (e.g. @ngrok/ngrok-darwin-universal)
globally before starting the server.

Fixes: #15625
Build-bot: skip release:developer
Cherry-pick-of: #15626
Test-bot: skip
Copy link
Contributor

@ermshiperete ermshiperete left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ngrokBinPath and ngrokControlPort in config.ts seem to be unused now.


function TfrmServerOptions.RedistInstallerPath: string;
begin
Result := TServerDebugAPI.ServerBinPath + SVCRedistExeFilename;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need a path separator?

Comment on lines +128 to +148
let started = false;
const listener = await ngrok.forward({
proto: 'http',
addr: configuration.port,
authtoken: configuration.ngrokToken,
onLogEvent: (msg: string) => {
if(options.ngrokLog) {
console.log(chalk.cyan(('\n'+msg).split('\n').join('\n[ngrok] ').trim()));
}
},
onStatusChange: (state: string) => {
if(state == 'connected' && started) {
// We only announce reconnection after initial start
configuration.ngrokEndpoint = listener.url();
console.log(chalk.blueBright('ngrok tunnel reconnected at %s'), configuration.ngrokEndpoint);
} else if(state == 'closed') {
configuration.ngrokEndpoint = '';
console.log(chalk.blueBright('ngrok tunnel closed'));
}
}
});
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Identified by devin.ai:

Unhandled exception in startNGrok crashes the entire server

If ngrok.forward() throws an exception (e.g., invalid auth token, network error, binary load failure), the error propagates through startNGrokrun() → top-level, crashing the entire Keyman Developer Server process.

Root Cause

In the new code at developer/src/server/src/index.ts:128-148, the ngrok.forward() call is not wrapped in a try-catch:

const listener = await ngrok.forward({
  proto: 'http',
  addr: configuration.port,
  ...
});

This is called via await startNGrok() at line 101 inside run(), which itself is awaited at line 30. The top-level catch at line 31-34 captures to Sentry and re-throws, terminating the process.

In the old code, ngrok was started inside an un-awaited IIFE (async function() { ... })(), meaning ngrok errors were fire-and-forget and would not crash the server. The server would continue running without ngrok.

With the new code, any ngrok startup failure (wrong auth token, missing binary, network issues) kills the entire server, preventing all keyboard testing functionality even for local use.

Impact: Users with misconfigured ngrok settings (e.g., invalid token, missing dependencies) will be unable to start Keyman Developer Server at all, even though ngrok is an optional feature.


let started = false;
const listener = await ngrok.forward({
proto: 'http',
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

From devin.ai:

proto field passed to ngrok.forward() is documented as ignored/unused

At developer/src/server/src/index.ts:129, the proto: 'http' option is passed to ngrok.forward(). Looking at the @ngrok/ngrok v1.7.0 type definitions, proto is listed as an optional string property in the Config interface but the new @ngrok/ngrok SDK defaults to HTTPS scheme. The old ngrok package used proto: 'http' to mean 'create an HTTP tunnel'. In the new SDK, the equivalent would be scheme: 'HTTP' if you want HTTP specifically. With proto: 'http', the SDK may still default to HTTPS, which should still work correctly (it creates an HTTPS public URL forwarding to local HTTP). Not a bug, but the proto field may not be doing what the developer expects.

}
});
started = true;
configuration.ngrokEndpoint = listener.url();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
configuration.ngrokEndpoint = listener.url();
configuration.ngrokEndpoint = listener.url() ?? '';

Copy link
Contributor

@darcywong00 darcywong00 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just a few maintenance questions

Comment on lines +84 to +86
// Note, we manually update the version of ngrok as required in subsequent
// releases, rather than trying to handle a potentially moving target
SNgrokVersion = 'v1.7.0';
Copy link
Contributor

@darcywong00 darcywong00 Feb 27, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should match package.json, right?

Should we add ngrok as an external component in minimum-versions.inc.sh?

// releases, rather than trying to handle a potentially moving target
SNgrokVersion = 'v1.7.0';
SUrlNgrokDownload = 'https://github.com/ngrok/ngrok-javascript/releases/download/'+SNgrokVersion+'/ngrok.win32-ia32-msvc.node';
SNgrokNodeModuleFilename = 'ngrok-win32-ia32-msvc.node';
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a filename limitation where we couldn't use ngrok.win32-ia32-msvc.node and then include that in the SUrlNgrokDownload path?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

Status: Todo

Development

Successfully merging this pull request may close these issues.

bug(developer): upgrading ngrok to 3.36.1 results in NgrokClientError: invalid tunnel configuration

3 participants