0
Fork 0
mirror of https://github.com/logto-io/logto.git synced 2024-12-30 20:33:54 -05:00

refactor(tunnel): split tunnel cli and make it a standalone package (#6512)

This commit is contained in:
Charles Zhao 2024-08-23 23:08:35 +08:00 committed by GitHub
parent 83a72dc3a5
commit 1e35d1afb4
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
16 changed files with 276 additions and 79 deletions

View file

@ -1,27 +1,35 @@
---
"@logto/cli": minor
"@logto/tunnel": 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.
#### Installation
```bash
npm i @logto/tunnel -g
```
#### Usage
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
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
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
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/`.
@ -30,4 +38,4 @@ Finally, run your application and set its endpoint in Logto config to the tunnel
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.
Refer to [Logto tunnel documentation](https://docs.logto.dev/docs/references/tunnel-cli/) for more details.

View file

@ -7,7 +7,7 @@ const config: UserConfig = {
extends: ['@commitlint/config-conventional'],
rules: {
'type-enum': [2, 'always', [...conventional.rules['type-enum'][2], 'api', 'release']],
'scope-enum': [2, 'always', ['connector', 'console', 'core', 'demo-app', 'test', 'phrases', 'schemas', 'shared', 'experience', 'deps', 'deps-dev', 'cli', 'toolkit', 'cloud', 'app-insights', 'elements', 'translate']],
'scope-enum': [2, 'always', ['connector', 'console', 'core', 'demo-app', 'test', 'phrases', 'schemas', 'shared', 'experience', 'deps', 'deps-dev', 'cli', 'toolkit', 'cloud', 'app-insights', 'elements', 'translate', 'tunnel']],
// Slightly increase the tolerance to allow the appending PR number
...(isCi && { 'header-max-length': [2, 'always', 110] }),
'body-max-line-length': [2, 'always', 110],

View file

@ -53,9 +53,7 @@
"dotenv": "^16.4.5",
"got": "^14.0.0",
"hpagent": "^1.2.0",
"http-proxy-middleware": "^3.0.0",
"inquirer": "^9.0.0",
"mime": "^4.0.4",
"nanoid": "^5.0.1",
"ora": "^8.0.1",
"p-limit": "^6.0.0",

View file

@ -6,7 +6,6 @@ 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 tunnel from './commands/tunnel/index.js';
import { packageJson } from './package-json.js';
import { cliConfig, ConfigKey, consoleLog } from './utils.js';
@ -47,7 +46,6 @@ void yargs(hideBin(process.argv))
.command(install)
.command(database)
.command(connector)
.command(tunnel)
.demandCommand(1)
.showHelpOnFail(false, `Specify ${chalk.green('--help')} for available options`)
.strict()

1
packages/tunnel/.gitignore vendored Normal file
View file

@ -0,0 +1 @@
src/package-json.ts

3
packages/tunnel/bin/index.js Executable file
View file

@ -0,0 +1,3 @@
#!/usr/bin/env node
// eslint-disable-next-line import/no-unassigned-import
import '../lib/index.js';

View file

@ -0,0 +1,76 @@
{
"name": "@logto/tunnel",
"version": "0.0.0",
"description": "A CLI tool that creates tunnel service to Logto Cloud for local development.",
"author": "Silverhand Inc. <contact@silverhand.io>",
"homepage": "https://github.com/logto-io/logto#readme",
"license": "MPL-2.0",
"type": "module",
"publishConfig": {
"access": "public"
},
"main": "lib/index.js",
"bin": {
"logto-tunnel": "bin/index.js"
},
"files": [
"bin",
"lib"
],
"repository": {
"type": "git",
"url": "git+https://github.com/logto-io/logto.git"
},
"scripts": {
"precommit": "lint-staged",
"prepare:package-json": "node -p \"'export const packageJson = ' + JSON.stringify(require('./package.json'), undefined, 2) + ';'\" > src/package-json.ts",
"build": "rm -rf lib && pnpm prepare:package-json && tsc -p tsconfig.build.json",
"dev": "tsc -p tsconfig.build.json --watch --preserveWatchOutput --incremental",
"start": "node .",
"start:dev": "pnpm build && node .",
"lint": "eslint --ext .ts src",
"lint:report": "pnpm lint --format json --output-file report.json",
"test": "vitest src",
"test:ci": "pnpm run test --silent --coverage",
"prepack": "pnpm build"
},
"engines": {
"node": "^20.9.0"
},
"bugs": {
"url": "https://github.com/logto-io/logto/issues"
},
"dependencies": {
"@logto/core-kit": "workspace:^",
"@logto/shared": "workspace:^",
"@silverhand/essentials": "^2.9.1",
"chalk": "^5.3.0",
"dotenv": "^16.4.5",
"http-proxy-middleware": "^3.0.0",
"mime": "^4.0.4",
"yargs": "^17.6.0",
"zod": "^3.23.8"
},
"devDependencies": {
"@silverhand/eslint-config": "6.0.1",
"@silverhand/ts-config": "6.0.0",
"@types/node": "^20.9.5",
"@types/yargs": "^17.0.13",
"@vitest/coverage-v8": "^2.0.0",
"eslint": "^8.56.0",
"lint-staged": "^15.0.0",
"prettier": "^3.0.0",
"typescript": "^5.5.3",
"vitest": "^2.0.0"
},
"eslintConfig": {
"extends": "@silverhand",
"rules": {
"no-console": "error"
},
"ignorePatterns": [
"src/package-json.ts"
]
},
"prettier": "@silverhand/eslint-config/.prettierrc"
}

View file

@ -5,7 +5,7 @@ import { conditional } from '@silverhand/essentials';
import chalk from 'chalk';
import type { CommandModule } from 'yargs';
import { consoleLog } from '../../utils.js';
import { consoleLog } from '../utils.js';
import { type TunnelCommandArgs } from './types.js';
import {
@ -17,11 +17,10 @@ import {
} from './utils.js';
const tunnel: CommandModule<unknown, TunnelCommandArgs> = {
command: ['tunnel'],
command: ['$0'],
describe: 'Command for Logto tunnel',
builder: (yargs) =>
yargs
.options({
yargs.options({
'experience-uri': {
alias: ['uri'],
describe: 'The URI of your custom sign-in experience page.',
@ -39,20 +38,16 @@ const tunnel: CommandModule<unknown, TunnelCommandArgs> = {
},
port: {
alias: 'p',
describe:
'The port number where the tunnel service 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,
},
verbose: {
alias: 'v',
describe: 'Show verbose output.',
type: 'boolean',
default: false,
},
})
.global('e')
.hide('db'),
}),
handler: async ({ 'experience-uri': url, 'experience-path': path, endpoint, port, verbose }) => {
checkExperienceInput(url, path);
@ -116,9 +111,7 @@ const tunnel: CommandModule<unknown, TunnelCommandArgs> = {
${chalk.bold(`${serviceUrl.href}callback/<connector-id>`)}
${chalk.green('➜')} ${chalk.gray(`Press ${chalk.white('Ctrl+C')} to stop the tunnel service.`)}
${chalk.green('➜')} ${chalk.gray(
`Use ${chalk.white('-v')} or ${chalk.white('--verbose')} to print verbose output.`
)}
${chalk.green('➜')} ${chalk.gray(`Use ${chalk.white('--verbose')} to print verbose output.`)}
`
);
});
@ -129,7 +122,7 @@ const tunnel: CommandModule<unknown, TunnelCommandArgs> = {
startServer(port + 1);
return;
}
consoleLog.fatal(`Tunnel server failed to start. ${error.message}`);
consoleLog.fatal(`Tunnel service failed to start. ${error.message}`);
});
};

View file

@ -10,7 +10,7 @@ import { createProxyMiddleware, responseInterceptor } from 'http-proxy-middlewar
import { type OnProxyEvent } from 'http-proxy-middleware/dist/types.js';
import mime from 'mime';
import { consoleLog } from '../../utils.js';
import { consoleLog } from '../utils.js';
import { type LogtoResponseHandler } from './types.js';

View file

@ -0,0 +1,38 @@
import chalk from 'chalk';
import dotenv from 'dotenv';
import yargs from 'yargs';
import { hideBin } from 'yargs/helpers';
import tunnel from './commands/index.js';
import { packageJson } from './package-json.js';
import { consoleLog } from './utils.js';
void yargs(hideBin(process.argv))
.version(false)
.option('env', {
alias: ['e', 'env-file'],
describe: 'The path to your `.env` file',
type: 'string',
})
.option('version', {
alias: 'v',
describe: 'Print CLI version',
type: 'boolean',
})
.middleware(({ env }) => {
dotenv.config({ path: env });
})
.middleware(({ version }) => {
if (version) {
consoleLog.plain(packageJson.name + ' v' + packageJson.version);
// eslint-disable-next-line unicorn/no-process-exit
process.exit(0);
}
}, true)
.command(tunnel)
.showHelpOnFail(false, `Specify ${chalk.green('--help')} for available options`)
.strict()
.parserConfiguration({
'dot-notation': false,
})
.parse();

View file

@ -0,0 +1,13 @@
import { ConsoleLog } from '@logto/shared';
// The explicit type annotation is required to make `.fatal()`
// works correctly without `return`:
//
// ```ts
// const foo: number | undefined;
// consoleLog.fatal();
// typeof foo // Still `number | undefined` without explicit type annotation
// ```
//
// For now I have no idea why.
export const consoleLog: ConsoleLog = new ConsoleLog();

View file

@ -0,0 +1,4 @@
{
"extends": "./tsconfig",
"include": ["src"],
}

View file

@ -0,0 +1,10 @@
{
"extends": "@silverhand/ts-config/tsconfig.base",
"compilerOptions": {
"outDir": "lib",
"types": ["node"]
},
"include": [
"src"
]
}

View file

@ -124,15 +124,9 @@ importers:
hpagent:
specifier: ^1.2.0
version: 1.2.0
http-proxy-middleware:
specifier: ^3.0.0
version: 3.0.0
inquirer:
specifier: ^9.0.0
version: 9.1.4
mime:
specifier: ^4.0.4
version: 4.0.4
nanoid:
specifier: ^5.0.1
version: 5.0.1
@ -3905,6 +3899,67 @@ importers:
specifier: ^3.0.0
version: 3.0.0
packages/tunnel:
dependencies:
'@logto/core-kit':
specifier: workspace:^
version: link:../toolkit/core-kit
'@logto/shared':
specifier: workspace:^
version: link:../shared
'@silverhand/essentials':
specifier: ^2.9.1
version: 2.9.1
chalk:
specifier: ^5.3.0
version: 5.3.0
dotenv:
specifier: ^16.4.5
version: 16.4.5
http-proxy-middleware:
specifier: ^3.0.0
version: 3.0.0
mime:
specifier: ^4.0.4
version: 4.0.4
yargs:
specifier: ^17.6.0
version: 17.7.2
zod:
specifier: ^3.23.8
version: 3.23.8
devDependencies:
'@silverhand/eslint-config':
specifier: 6.0.1
version: 6.0.1(eslint@8.57.0)(prettier@3.0.0)(typescript@5.5.3)
'@silverhand/ts-config':
specifier: 6.0.0
version: 6.0.0(typescript@5.5.3)
'@types/node':
specifier: ^20.9.5
version: 20.12.7
'@types/yargs':
specifier: ^17.0.13
version: 17.0.13
'@vitest/coverage-v8':
specifier: ^2.0.0
version: 2.0.0(vitest@2.0.0(@types/node@20.12.7)(happy-dom@14.12.3)(jsdom@20.0.2)(lightningcss@1.25.1)(sass@1.77.8))
eslint:
specifier: ^8.56.0
version: 8.57.0
lint-staged:
specifier: ^15.0.0
version: 15.0.2
prettier:
specifier: ^3.0.0
version: 3.0.0
typescript:
specifier: ^5.5.3
version: 5.5.3
vitest:
specifier: ^2.0.0
version: 2.0.0(@types/node@20.12.7)(happy-dom@14.12.3)(jsdom@20.0.2)(lightningcss@1.25.1)(sass@1.77.8)
packages:
'@75lb/deep-merge@1.1.1':
@ -13567,10 +13622,10 @@ snapshots:
'@babel/helper-compilation-targets': 7.23.6
'@babel/helper-module-transforms': 7.23.3(@babel/core@7.24.4)
'@babel/helpers': 7.24.4
'@babel/parser': 7.24.4
'@babel/parser': 7.24.8
'@babel/template': 7.24.0
'@babel/traverse': 7.24.1
'@babel/types': 7.24.0
'@babel/types': 7.24.9
convert-source-map: 2.0.0
debug: 4.3.5
gensync: 1.0.0-beta.2
@ -13601,7 +13656,7 @@ snapshots:
'@babel/generator@7.20.4':
dependencies:
'@babel/types': 7.24.0
'@babel/types': 7.24.9
'@jridgewell/gen-mapping': 0.3.5
jsesc: 2.5.2
@ -13614,7 +13669,7 @@ snapshots:
'@babel/generator@7.24.4':
dependencies:
'@babel/types': 7.24.0
'@babel/types': 7.24.9
'@jridgewell/gen-mapping': 0.3.5
'@jridgewell/trace-mapping': 0.3.25
jsesc: 2.5.2
@ -13644,7 +13699,7 @@ snapshots:
'@babel/helper-function-name@7.23.0':
dependencies:
'@babel/template': 7.24.0
'@babel/types': 7.24.0
'@babel/types': 7.24.9
'@babel/helper-function-name@7.24.7':
dependencies:
@ -13653,7 +13708,7 @@ snapshots:
'@babel/helper-hoist-variables@7.22.5':
dependencies:
'@babel/types': 7.24.0
'@babel/types': 7.24.9
'@babel/helper-hoist-variables@7.24.7':
dependencies:
@ -13661,7 +13716,7 @@ snapshots:
'@babel/helper-module-imports@7.24.3':
dependencies:
'@babel/types': 7.24.0
'@babel/types': 7.24.9
'@babel/helper-module-imports@7.24.7':
dependencies:
@ -13677,7 +13732,7 @@ snapshots:
'@babel/helper-module-imports': 7.24.3
'@babel/helper-simple-access': 7.22.5
'@babel/helper-split-export-declaration': 7.22.6
'@babel/helper-validator-identifier': 7.22.20
'@babel/helper-validator-identifier': 7.24.7
'@babel/helper-module-transforms@7.24.9(@babel/core@7.24.9)':
dependencies:
@ -13696,7 +13751,7 @@ snapshots:
'@babel/helper-simple-access@7.22.5':
dependencies:
'@babel/types': 7.24.0
'@babel/types': 7.24.9
'@babel/helper-simple-access@7.24.7':
dependencies:
@ -13707,7 +13762,7 @@ snapshots:
'@babel/helper-split-export-declaration@7.22.6':
dependencies:
'@babel/types': 7.24.0
'@babel/types': 7.24.9
'@babel/helper-split-export-declaration@7.24.7':
dependencies:
@ -13729,7 +13784,7 @@ snapshots:
dependencies:
'@babel/template': 7.24.0
'@babel/traverse': 7.24.1
'@babel/types': 7.24.0
'@babel/types': 7.24.9
transitivePeerDependencies:
- supports-color
@ -13861,14 +13916,14 @@ snapshots:
'@babel/template@7.18.10':
dependencies:
'@babel/code-frame': 7.22.5
'@babel/parser': 7.24.4
'@babel/types': 7.24.0
'@babel/parser': 7.24.8
'@babel/types': 7.24.9
'@babel/template@7.24.0':
dependencies:
'@babel/code-frame': 7.24.2
'@babel/parser': 7.24.4
'@babel/types': 7.24.0
'@babel/parser': 7.24.8
'@babel/types': 7.24.9
'@babel/template@7.24.7':
dependencies:
@ -13884,8 +13939,8 @@ snapshots:
'@babel/helper-function-name': 7.23.0
'@babel/helper-hoist-variables': 7.22.5
'@babel/helper-split-export-declaration': 7.22.6
'@babel/parser': 7.24.4
'@babel/types': 7.24.0
'@babel/parser': 7.24.8
'@babel/types': 7.24.9
debug: 4.3.5
globals: 11.12.0
transitivePeerDependencies:
@ -14349,7 +14404,7 @@ snapshots:
'@eslint/eslintrc@2.1.4':
dependencies:
ajv: 6.12.6
debug: 4.3.4
debug: 4.3.5
espree: 9.6.1
globals: 13.20.0
ignore: 5.3.1
@ -15865,8 +15920,8 @@ snapshots:
'@types/babel__core@7.1.19':
dependencies:
'@babel/parser': 7.24.4
'@babel/types': 7.24.0
'@babel/parser': 7.24.8
'@babel/types': 7.24.9
'@types/babel__generator': 7.6.4
'@types/babel__template': 7.4.1
'@types/babel__traverse': 7.18.2
@ -16889,7 +16944,7 @@ snapshots:
babel-plugin-jest-hoist@29.6.3:
dependencies:
'@babel/template': 7.18.10
'@babel/types': 7.24.0
'@babel/types': 7.24.9
'@types/babel__core': 7.1.19
'@types/babel__traverse': 7.18.2
@ -19630,7 +19685,7 @@ snapshots:
istanbul-lib-instrument@5.2.1:
dependencies:
'@babel/core': 7.24.4
'@babel/parser': 7.24.4
'@babel/parser': 7.24.8
'@istanbuljs/schema': 0.1.3
istanbul-lib-coverage: 3.2.2
semver: 6.3.1
@ -19640,7 +19695,7 @@ snapshots:
istanbul-lib-instrument@6.0.1:
dependencies:
'@babel/core': 7.24.4
'@babel/parser': 7.24.4
'@babel/parser': 7.24.8
'@istanbuljs/schema': 0.1.3
istanbul-lib-coverage: 3.2.2
semver: 7.6.0