0
Fork 0
mirror of https://github.com/logto-io/logto.git synced 2024-12-16 20:26:19 -05:00

refactor(cli): rename proxy cli to tunnel (#6442)

This commit is contained in:
Charles Zhao 2024-08-14 11:45:14 +08:00 committed by GitHub
parent ff6b304bac
commit 976558af9c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 59 additions and 22 deletions

View file

@ -0,0 +1,33 @@
---
"@logto/cli": minor
---
add new cli command to setup Logto tunnel service for developing and debugging custom ui on your local machine
This command will establish a tunnel service between the following 3 entities: Logto cloud auth services, your application, and your custom sign-in UI.
Assuming you have a custom sign-in page running on `http://localhost:4000`, then you can execute the command this way:
```bash
logto tunnel --endpoint https://<tenant-id>.logto.app --port 9000 --experience-uri http://localhost:4000
```
Or if you don't have your custom UI pages hosted on a dev server, you can use the `--experience-path` option to specify the path to your static files:
```bash
logto tunnel --endpoint https://<tenant-id>.logto.app --port 9000 --experience-path /path/to/your/custom/ui
```
This command also works if you have enabled custom domain in your Logto tenant. E.g.:
```bash
logto tunnel --endpoint https://your-custom-domain.com --port 9000 --experience-path /path/to/your/custom/ui
```
This should set up the tunnel and it will be running on your local machine at `http://localhost:9000/`.
Finally, run your application and set its endpoint in Logto config to the tunnel address `http://localhost:9000/` instead.
If all set up correctly, when you click the "sign-in" button in your application, you should be navigated to your custom sign-in page instead of Logto's built-in UI, along with valid session (cookies) that allows you to further interact with Logto experience API.
Refer to the [documentation](https://docs.logto.dev/docs/references/using-cli/tunnel/) for more details.

View file

@ -7,7 +7,7 @@ import type { CommandModule } from 'yargs';
import { consoleLog } from '../../utils.js';
import { type ProxyCommandArgs } from './types.js';
import { type TunnelCommandArgs } from './types.js';
import {
checkExperienceInput,
createLogtoResponseHandler,
@ -16,9 +16,9 @@ import {
isLogtoRequestPath,
} from './utils.js';
const proxy: CommandModule<unknown, ProxyCommandArgs> = {
command: ['proxy'],
describe: 'Command for Logto proxy',
const tunnel: CommandModule<unknown, TunnelCommandArgs> = {
command: ['tunnel'],
describe: 'Command for Logto tunnel',
builder: (yargs) =>
yargs
.options({
@ -40,7 +40,8 @@ const proxy: CommandModule<unknown, ProxyCommandArgs> = {
},
port: {
alias: 'p',
describe: 'The port number where the proxy server will be running on. Defaults to 9000.',
describe:
'The port number where the tunnel service will be running on. Defaults to 9000.',
type: 'number',
default: 9000,
},
@ -59,7 +60,7 @@ const proxy: CommandModule<unknown, ProxyCommandArgs> = {
consoleLog.fatal('A valid Logto endpoint URI must be provided.');
}
const logtoEndpointUrl = new URL(endpoint);
const proxyUrl = new URL(`http://localhost:${port}`);
const tunnelServiceUrl = new URL(`http://localhost:${port}`);
const proxyLogtoRequest = createProxy(
logtoEndpointUrl.href,
@ -69,7 +70,7 @@ const proxy: CommandModule<unknown, ProxyCommandArgs> = {
request,
response,
logtoEndpointUrl,
proxyUrl,
tunnelServiceUrl,
verbose,
})
);
@ -81,7 +82,7 @@ const proxy: CommandModule<unknown, ProxyCommandArgs> = {
consoleLog.info(`Incoming request: ${chalk.blue(request.method, request.url)}`);
}
// Proxy the requests to Logto endpoint
// Tunneling the requests to Logto endpoint
if (isLogtoRequestPath(request.url)) {
void proxyLogtoRequest(request, response);
return;
@ -98,9 +99,9 @@ const proxy: CommandModule<unknown, ProxyCommandArgs> = {
});
server.listen(port, () => {
consoleLog.info(`Proxy server is running on ${chalk.blue(proxyUrl.href)}`);
consoleLog.info(`Logto tunnel is running on ${chalk.blue(tunnelServiceUrl.href)}`);
});
},
};
export default proxy;
export default tunnel;

View file

@ -1,6 +1,6 @@
import type * as http from 'node:http';
export type ProxyCommandArgs = {
export type TunnelCommandArgs = {
'experience-uri'?: string;
'experience-path'?: string;
endpoint?: string;
@ -8,11 +8,11 @@ export type ProxyCommandArgs = {
verbose: boolean;
};
export type ProxyResponseHandler = {
export type LogtoResponseHandler = {
proxyResponse: http.IncomingMessage;
request: http.IncomingMessage;
response: http.ServerResponse;
logtoEndpointUrl: URL;
proxyUrl: URL;
tunnelServiceUrl: URL;
verbose: boolean;
};

View file

@ -12,7 +12,7 @@ import mime from 'mime';
import { consoleLog } from '../../utils.js';
import { type ProxyResponseHandler } from './types.js';
import { type LogtoResponseHandler } from './types.js';
export const createProxy = (targetUrl: string, onProxyResponse?: OnProxyEvent['proxyRes']) => {
const hasResponseHandler = Boolean(onProxyResponse);
@ -65,7 +65,7 @@ export const createStaticFileProxy =
/**
* Intercept the response from Logto endpoint and replace Logto endpoint URLs in the response with the
* proxy URL. The string replace happens in the following cases:
* tunnel service URL. The string replace happens in the following cases:
* - The response is a redirect response, and the `location` property in response header may contain Logto
* endpoint URI.
* - The response body is JSON, which consists of properties such as `**_endpoint` and `redirectTo`. These
@ -80,13 +80,13 @@ export const createLogtoResponseHandler = async ({
request,
response,
logtoEndpointUrl,
proxyUrl,
tunnelServiceUrl,
verbose,
}: ProxyResponseHandler) => {
}: LogtoResponseHandler) => {
const { location } = proxyResponse.headers;
if (location) {
// eslint-disable-next-line @silverhand/fp/no-mutation
proxyResponse.headers.location = location.replace(logtoEndpointUrl.href, proxyUrl.href);
proxyResponse.headers.location = location.replace(logtoEndpointUrl.href, tunnelServiceUrl.href);
}
void responseInterceptor(async (responseBuffer, proxyResponse) => {
@ -96,7 +96,10 @@ export const createLogtoResponseHandler = async ({
}
if (proxyResponse.headers['content-type']?.includes('text/html')) {
return responseBody.replace(`action="${logtoEndpointUrl.href}`, `action="${proxyUrl.href}`);
return responseBody.replace(
`action="${logtoEndpointUrl.href}`,
`action="${tunnelServiceUrl.href}`
);
}
if (proxyResponse.headers['content-type']?.includes('application/json')) {
@ -106,7 +109,7 @@ export const createLogtoResponseHandler = async ({
const updatedEntries: Array<[string, unknown]> = Object.entries(jsonData).map(
([key, value]) => {
if ((key === 'redirectTo' || key.endsWith('_endpoint')) && typeof value === 'string') {
return [key, value.replace(logtoEndpointUrl.href, proxyUrl.href)];
return [key, value.replace(logtoEndpointUrl.href, tunnelServiceUrl.href)];
}
return [key, value];
}

View file

@ -6,8 +6,8 @@ import { hideBin } from 'yargs/helpers';
import connector from './commands/connector/index.js';
import database from './commands/database/index.js';
import install from './commands/install/index.js';
import proxy from './commands/proxy/index.js';
import translate from './commands/translate/index.js';
import tunnel from './commands/tunnel/index.js';
import { packageJson } from './package-json.js';
import { cliConfig, ConfigKey, consoleLog } from './utils.js';
@ -49,7 +49,7 @@ void yargs(hideBin(process.argv))
.command(database)
.command(connector)
.command(translate)
.command(proxy)
.command(tunnel)
.demandCommand(1)
.showHelpOnFail(false, `Specify ${chalk.green('--help')} for available options`)
.strict()