@logto/cli 1.19.0 → 1.20.0
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/lib/commands/database/seed/tables.js +2 -1
- package/lib/index.js +0 -4
- package/lib/package-json.d.ts +1 -8
- package/lib/package-json.js +4 -11
- package/lib/utils.d.ts +0 -1
- package/lib/utils.js +1 -19
- package/package.json +4 -11
- package/lib/commands/proxy/index.d.ts +0 -4
- package/lib/commands/proxy/index.js +0 -80
- package/lib/commands/proxy/types.d.ts +0 -16
- package/lib/commands/proxy/types.js +0 -1
- package/lib/commands/proxy/utils.d.ts +0 -27
- package/lib/commands/proxy/utils.js +0 -123
- package/lib/commands/translate/create.d.ts +0 -8
- package/lib/commands/translate/create.js +0 -37
- package/lib/commands/translate/index.d.ts +0 -3
- package/lib/commands/translate/index.js +0 -27
- package/lib/commands/translate/list-tags.d.ts +0 -3
- package/lib/commands/translate/list-tags.js +0 -19
- package/lib/commands/translate/openai.d.ts +0 -11
- package/lib/commands/translate/openai.js +0 -73
- package/lib/commands/translate/prompts.d.ts +0 -18
- package/lib/commands/translate/prompts.js +0 -48
- package/lib/commands/translate/sync-keys/index.d.ts +0 -13
- package/lib/commands/translate/sync-keys/index.js +0 -73
- package/lib/commands/translate/sync-keys/utils.d.ts +0 -57
- package/lib/commands/translate/sync-keys/utils.js +0 -295
- package/lib/commands/translate/sync.d.ts +0 -10
- package/lib/commands/translate/sync.js +0 -44
- package/lib/commands/translate/utils.d.ts +0 -14
- package/lib/commands/translate/utils.js +0 -130
|
@@ -103,7 +103,8 @@ export const seedTables = async (connection, latestTimestamp, isCloud) => {
|
|
|
103
103
|
await assignScopesToRole(connection, adminTenantId, applicationRole.id, ...cloudAdditionalScopes
|
|
104
104
|
.filter(({ name }) => name === CloudScope.SendSms ||
|
|
105
105
|
name === CloudScope.SendEmail ||
|
|
106
|
-
name === CloudScope.FetchCustomJwt
|
|
106
|
+
name === CloudScope.FetchCustomJwt ||
|
|
107
|
+
name === CloudScope.ReportSubscriptionUpdates)
|
|
107
108
|
.map(({ id }) => id));
|
|
108
109
|
await Promise.all([
|
|
109
110
|
seedLegacyManagementApiUserRole(connection),
|
package/lib/index.js
CHANGED
|
@@ -5,8 +5,6 @@ import { hideBin } from 'yargs/helpers';
|
|
|
5
5
|
import connector from './commands/connector/index.js';
|
|
6
6
|
import database from './commands/database/index.js';
|
|
7
7
|
import install from './commands/install/index.js';
|
|
8
|
-
import proxy from './commands/proxy/index.js';
|
|
9
|
-
import translate from './commands/translate/index.js';
|
|
10
8
|
import { packageJson } from './package-json.js';
|
|
11
9
|
import { cliConfig, ConfigKey, consoleLog } from './utils.js';
|
|
12
10
|
void yargs(hideBin(process.argv))
|
|
@@ -44,8 +42,6 @@ void yargs(hideBin(process.argv))
|
|
|
44
42
|
.command(install)
|
|
45
43
|
.command(database)
|
|
46
44
|
.command(connector)
|
|
47
|
-
.command(translate)
|
|
48
|
-
.command(proxy)
|
|
49
45
|
.demandCommand(1)
|
|
50
46
|
.showHelpOnFail(false, `Specify ${chalk.green('--help')} for available options`)
|
|
51
47
|
.strict()
|
package/lib/package-json.d.ts
CHANGED
|
@@ -41,9 +41,6 @@ export declare const packageJson: {
|
|
|
41
41
|
dependencies: {
|
|
42
42
|
"@logto/connector-kit": string;
|
|
43
43
|
"@logto/core-kit": string;
|
|
44
|
-
"@logto/language-kit": string;
|
|
45
|
-
"@logto/phrases": string;
|
|
46
|
-
"@logto/phrases-experience": string;
|
|
47
44
|
"@logto/schemas": string;
|
|
48
45
|
"@logto/shared": string;
|
|
49
46
|
"@silverhand/essentials": string;
|
|
@@ -53,19 +50,14 @@ export declare const packageJson: {
|
|
|
53
50
|
dotenv: string;
|
|
54
51
|
got: string;
|
|
55
52
|
hpagent: string;
|
|
56
|
-
"http-proxy-middleware": string;
|
|
57
53
|
inquirer: string;
|
|
58
|
-
mime: string;
|
|
59
54
|
nanoid: string;
|
|
60
55
|
ora: string;
|
|
61
56
|
"p-limit": string;
|
|
62
|
-
"p-queue": string;
|
|
63
57
|
"p-retry": string;
|
|
64
58
|
"pg-protocol": string;
|
|
65
|
-
roarr: string;
|
|
66
59
|
semver: string;
|
|
67
60
|
tar: string;
|
|
68
|
-
typescript: string;
|
|
69
61
|
yargs: string;
|
|
70
62
|
zod: string;
|
|
71
63
|
};
|
|
@@ -84,6 +76,7 @@ export declare const packageJson: {
|
|
|
84
76
|
"lint-staged": string;
|
|
85
77
|
prettier: string;
|
|
86
78
|
sinon: string;
|
|
79
|
+
typescript: string;
|
|
87
80
|
vitest: string;
|
|
88
81
|
};
|
|
89
82
|
eslintConfig: {
|
package/lib/package-json.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
export const packageJson = {
|
|
2
2
|
"name": "@logto/cli",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.20.0",
|
|
4
4
|
"description": "Logto CLI.",
|
|
5
5
|
"author": "Silverhand Inc. <contact@silverhand.io>",
|
|
6
6
|
"homepage": "https://github.com/logto-io/logto#readme",
|
|
@@ -44,10 +44,7 @@ export const packageJson = {
|
|
|
44
44
|
"dependencies": {
|
|
45
45
|
"@logto/connector-kit": "workspace:^4.0.0",
|
|
46
46
|
"@logto/core-kit": "workspace:^2.5.0",
|
|
47
|
-
"@logto/
|
|
48
|
-
"@logto/phrases": "workspace:^1.13.0",
|
|
49
|
-
"@logto/phrases-experience": "workspace:^1.7.0",
|
|
50
|
-
"@logto/schemas": "workspace:1.19.0",
|
|
47
|
+
"@logto/schemas": "workspace:1.20.0",
|
|
51
48
|
"@logto/shared": "workspace:^3.1.1",
|
|
52
49
|
"@silverhand/essentials": "^2.9.1",
|
|
53
50
|
"@silverhand/slonik": "31.0.0-beta.2",
|
|
@@ -56,19 +53,14 @@ export const packageJson = {
|
|
|
56
53
|
"dotenv": "^16.4.5",
|
|
57
54
|
"got": "^14.0.0",
|
|
58
55
|
"hpagent": "^1.2.0",
|
|
59
|
-
"http-proxy-middleware": "^3.0.0",
|
|
60
56
|
"inquirer": "^9.0.0",
|
|
61
|
-
"mime": "^4.0.4",
|
|
62
57
|
"nanoid": "^5.0.1",
|
|
63
58
|
"ora": "^8.0.1",
|
|
64
59
|
"p-limit": "^6.0.0",
|
|
65
|
-
"p-queue": "^8.0.0",
|
|
66
60
|
"p-retry": "^6.0.0",
|
|
67
61
|
"pg-protocol": "^1.6.0",
|
|
68
|
-
"roarr": "^7.11.0",
|
|
69
62
|
"semver": "^7.3.8",
|
|
70
63
|
"tar": "^7.0.0",
|
|
71
|
-
"typescript": "^5.5.3",
|
|
72
64
|
"yargs": "^17.6.0",
|
|
73
65
|
"zod": "^3.23.8"
|
|
74
66
|
},
|
|
@@ -82,11 +74,12 @@ export const packageJson = {
|
|
|
82
74
|
"@types/tar": "^6.1.12",
|
|
83
75
|
"@types/yargs": "^17.0.13",
|
|
84
76
|
"@vitest/coverage-v8": "^2.0.0",
|
|
85
|
-
"@withtyped/server": "^0.
|
|
77
|
+
"@withtyped/server": "^0.14.0",
|
|
86
78
|
"eslint": "^8.56.0",
|
|
87
79
|
"lint-staged": "^15.0.0",
|
|
88
80
|
"prettier": "^3.0.0",
|
|
89
81
|
"sinon": "^18.0.0",
|
|
82
|
+
"typescript": "^5.5.3",
|
|
90
83
|
"vitest": "^2.0.0"
|
|
91
84
|
},
|
|
92
85
|
"eslintConfig": {
|
package/lib/utils.d.ts
CHANGED
package/lib/utils.js
CHANGED
|
@@ -1,9 +1,8 @@
|
|
|
1
|
-
import { execSync
|
|
1
|
+
import { execSync } from 'node:child_process';
|
|
2
2
|
import { createWriteStream, existsSync } from 'node:fs';
|
|
3
3
|
import { readdir, readFile } from 'node:fs/promises';
|
|
4
4
|
import { createRequire } from 'node:module';
|
|
5
5
|
import path from 'node:path';
|
|
6
|
-
import { promisify } from 'node:util';
|
|
7
6
|
import { ConsoleLog } from '@logto/shared';
|
|
8
7
|
import { assert, conditional, conditionalString } from '@silverhand/essentials';
|
|
9
8
|
import chalk from 'chalk';
|
|
@@ -186,20 +185,3 @@ export const getConnectorPackagesFromDirectory = async (directory) => {
|
|
|
186
185
|
}));
|
|
187
186
|
return rawPackages.filter((packageInfo) => typeof packageInfo.name === 'string');
|
|
188
187
|
};
|
|
189
|
-
const execPromise = promisify(execFile);
|
|
190
|
-
export const lintLocaleFiles = async (
|
|
191
|
-
/** Logto instance path */
|
|
192
|
-
instancePath,
|
|
193
|
-
/** Target package name, ignore to lint both `phrases` and `phrases-experience` packages */
|
|
194
|
-
packageName) => {
|
|
195
|
-
const spinner = ora({
|
|
196
|
-
text: 'Running `eslint --fix` for locales',
|
|
197
|
-
}).start();
|
|
198
|
-
const targetPackages = packageName ? [packageName] : ['phrases', 'phrases-experience'];
|
|
199
|
-
await Promise.all(targetPackages.map(async (packageName) => {
|
|
200
|
-
const phrasesPath = path.join(instancePath, 'packages', packageName);
|
|
201
|
-
const localesPath = path.join(phrasesPath, 'src/locales');
|
|
202
|
-
await execPromise('pnpm', ['eslint', '--ext', '.ts', path.relative(phrasesPath, localesPath), '--fix'], { cwd: phrasesPath });
|
|
203
|
-
}));
|
|
204
|
-
spinner.succeed('Ran `eslint --fix` for locales');
|
|
205
|
-
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@logto/cli",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.20.0",
|
|
4
4
|
"description": "Logto CLI.",
|
|
5
5
|
"author": "Silverhand Inc. <contact@silverhand.io>",
|
|
6
6
|
"homepage": "https://github.com/logto-io/logto#readme",
|
|
@@ -30,10 +30,7 @@
|
|
|
30
30
|
"dependencies": {
|
|
31
31
|
"@logto/connector-kit": "^4.0.0",
|
|
32
32
|
"@logto/core-kit": "^2.5.0",
|
|
33
|
-
"@logto/
|
|
34
|
-
"@logto/phrases": "^1.13.0",
|
|
35
|
-
"@logto/phrases-experience": "^1.7.0",
|
|
36
|
-
"@logto/schemas": "1.19.0",
|
|
33
|
+
"@logto/schemas": "1.20.0",
|
|
37
34
|
"@logto/shared": "^3.1.1",
|
|
38
35
|
"@silverhand/essentials": "^2.9.1",
|
|
39
36
|
"@silverhand/slonik": "31.0.0-beta.2",
|
|
@@ -42,19 +39,14 @@
|
|
|
42
39
|
"dotenv": "^16.4.5",
|
|
43
40
|
"got": "^14.0.0",
|
|
44
41
|
"hpagent": "^1.2.0",
|
|
45
|
-
"http-proxy-middleware": "^3.0.0",
|
|
46
42
|
"inquirer": "^9.0.0",
|
|
47
|
-
"mime": "^4.0.4",
|
|
48
43
|
"nanoid": "^5.0.1",
|
|
49
44
|
"ora": "^8.0.1",
|
|
50
45
|
"p-limit": "^6.0.0",
|
|
51
|
-
"p-queue": "^8.0.0",
|
|
52
46
|
"p-retry": "^6.0.0",
|
|
53
47
|
"pg-protocol": "^1.6.0",
|
|
54
|
-
"roarr": "^7.11.0",
|
|
55
48
|
"semver": "^7.3.8",
|
|
56
49
|
"tar": "^7.0.0",
|
|
57
|
-
"typescript": "^5.5.3",
|
|
58
50
|
"yargs": "^17.6.0",
|
|
59
51
|
"zod": "^3.23.8"
|
|
60
52
|
},
|
|
@@ -68,11 +60,12 @@
|
|
|
68
60
|
"@types/tar": "^6.1.12",
|
|
69
61
|
"@types/yargs": "^17.0.13",
|
|
70
62
|
"@vitest/coverage-v8": "^2.0.0",
|
|
71
|
-
"@withtyped/server": "^0.
|
|
63
|
+
"@withtyped/server": "^0.14.0",
|
|
72
64
|
"eslint": "^8.56.0",
|
|
73
65
|
"lint-staged": "^15.0.0",
|
|
74
66
|
"prettier": "^3.0.0",
|
|
75
67
|
"sinon": "^18.0.0",
|
|
68
|
+
"typescript": "^5.5.3",
|
|
76
69
|
"vitest": "^2.0.0"
|
|
77
70
|
},
|
|
78
71
|
"eslintConfig": {
|
|
@@ -1,80 +0,0 @@
|
|
|
1
|
-
import http from 'node:http';
|
|
2
|
-
import { isValidUrl } from '@logto/core-kit';
|
|
3
|
-
import { conditional } from '@silverhand/essentials';
|
|
4
|
-
import chalk from 'chalk';
|
|
5
|
-
import { consoleLog } from '../../utils.js';
|
|
6
|
-
import { checkExperienceInput, createLogtoResponseHandler, createProxy, createStaticFileProxy, isLogtoRequestPath, } from './utils.js';
|
|
7
|
-
const proxy = {
|
|
8
|
-
command: ['proxy'],
|
|
9
|
-
describe: 'Command for Logto proxy',
|
|
10
|
-
builder: (yargs) => yargs
|
|
11
|
-
.options({
|
|
12
|
-
'experience-uri': {
|
|
13
|
-
alias: ['x'],
|
|
14
|
-
describe: 'The URI of your custom sign-in experience page.',
|
|
15
|
-
type: 'string',
|
|
16
|
-
},
|
|
17
|
-
'experience-path': {
|
|
18
|
-
alias: ['xp'],
|
|
19
|
-
describe: 'The local folder path of your custom sign-in experience assets.',
|
|
20
|
-
type: 'string',
|
|
21
|
-
},
|
|
22
|
-
endpoint: {
|
|
23
|
-
alias: 'ep',
|
|
24
|
-
describe: 'Logto endpoint URI, which can be found in Logto Console. E.g.: https://<tenant-id>.logto.app/',
|
|
25
|
-
type: 'string',
|
|
26
|
-
},
|
|
27
|
-
port: {
|
|
28
|
-
alias: 'p',
|
|
29
|
-
describe: 'The port number where the proxy server will be running on. Defaults to 9000.',
|
|
30
|
-
type: 'number',
|
|
31
|
-
default: 9000,
|
|
32
|
-
},
|
|
33
|
-
verbose: {
|
|
34
|
-
alias: 'v',
|
|
35
|
-
describe: 'Show verbose output.',
|
|
36
|
-
type: 'boolean',
|
|
37
|
-
default: false,
|
|
38
|
-
},
|
|
39
|
-
})
|
|
40
|
-
.global('e'),
|
|
41
|
-
handler: async ({ 'experience-uri': url, 'experience-path': path, endpoint, port, verbose }) => {
|
|
42
|
-
checkExperienceInput(url, path);
|
|
43
|
-
if (!endpoint || !isValidUrl(endpoint)) {
|
|
44
|
-
consoleLog.fatal('A valid Logto endpoint URI must be provided.');
|
|
45
|
-
}
|
|
46
|
-
const logtoEndpointUrl = new URL(endpoint);
|
|
47
|
-
const proxyUrl = new URL(`http://localhost:${port}`);
|
|
48
|
-
const proxyLogtoRequest = createProxy(logtoEndpointUrl.href, async (proxyResponse, request, response) => createLogtoResponseHandler({
|
|
49
|
-
proxyResponse,
|
|
50
|
-
request,
|
|
51
|
-
response,
|
|
52
|
-
logtoEndpointUrl,
|
|
53
|
-
proxyUrl,
|
|
54
|
-
verbose,
|
|
55
|
-
}));
|
|
56
|
-
const proxyExperienceServerRequest = conditional(url && createProxy(url));
|
|
57
|
-
const proxyExperienceStaticFileRequest = conditional(path && createStaticFileProxy(path));
|
|
58
|
-
const server = http.createServer((request, response) => {
|
|
59
|
-
if (verbose) {
|
|
60
|
-
consoleLog.info(`Incoming request: ${chalk.blue(request.method, request.url)}`);
|
|
61
|
-
}
|
|
62
|
-
// Proxy the requests to Logto endpoint
|
|
63
|
-
if (isLogtoRequestPath(request.url)) {
|
|
64
|
-
void proxyLogtoRequest(request, response);
|
|
65
|
-
return;
|
|
66
|
-
}
|
|
67
|
-
if (proxyExperienceServerRequest) {
|
|
68
|
-
void proxyExperienceServerRequest(request, response);
|
|
69
|
-
return;
|
|
70
|
-
}
|
|
71
|
-
if (proxyExperienceStaticFileRequest) {
|
|
72
|
-
void proxyExperienceStaticFileRequest(request, response);
|
|
73
|
-
}
|
|
74
|
-
});
|
|
75
|
-
server.listen(port, () => {
|
|
76
|
-
consoleLog.info(`Proxy server is running on ${chalk.blue(proxyUrl.href)}`);
|
|
77
|
-
});
|
|
78
|
-
},
|
|
79
|
-
};
|
|
80
|
-
export default proxy;
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
import type * as http from 'node:http';
|
|
2
|
-
export type ProxyCommandArgs = {
|
|
3
|
-
'experience-uri'?: string;
|
|
4
|
-
'experience-path'?: string;
|
|
5
|
-
endpoint?: string;
|
|
6
|
-
port: number;
|
|
7
|
-
verbose: boolean;
|
|
8
|
-
};
|
|
9
|
-
export type ProxyResponseHandler = {
|
|
10
|
-
proxyResponse: http.IncomingMessage;
|
|
11
|
-
request: http.IncomingMessage;
|
|
12
|
-
response: http.ServerResponse;
|
|
13
|
-
logtoEndpointUrl: URL;
|
|
14
|
-
proxyUrl: URL;
|
|
15
|
-
verbose: boolean;
|
|
16
|
-
};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
import type http from 'node:http';
|
|
2
|
-
import { type OnProxyEvent } from 'http-proxy-middleware/dist/types.js';
|
|
3
|
-
import { type ProxyResponseHandler } from './types.js';
|
|
4
|
-
export declare const createProxy: (targetUrl: string, onProxyResponse?: OnProxyEvent["proxyRes"]) => import("http-proxy-middleware").RequestHandler<http.IncomingMessage, http.ServerResponse<http.IncomingMessage>, (err?: any) => void>;
|
|
5
|
-
export declare const createStaticFileProxy: (staticPath: string) => (request: http.IncomingMessage, response: http.ServerResponse) => Promise<void>;
|
|
6
|
-
/**
|
|
7
|
-
* Intercept the response from Logto endpoint and replace Logto endpoint URLs in the response with the
|
|
8
|
-
* proxy URL. The string replace happens in the following cases:
|
|
9
|
-
* - The response is a redirect response, and the `location` property in response header may contain Logto
|
|
10
|
-
* endpoint URI.
|
|
11
|
-
* - The response body is JSON, which consists of properties such as `**_endpoint` and `redirectTo`. These
|
|
12
|
-
* properties may contain Logto endpoint URI.
|
|
13
|
-
* - The response is HTML content that contains a form. The form action URL may contain Logto endpoint URI.
|
|
14
|
-
*
|
|
15
|
-
* Note: the `issuer` and `jwks_uri` properties in the `/oidc/.well-known` response should not be replaced,
|
|
16
|
-
* even they also contain the Logto endpoint URI.
|
|
17
|
-
*/
|
|
18
|
-
export declare const createLogtoResponseHandler: ({ proxyResponse, request, response, logtoEndpointUrl, proxyUrl, verbose, }: ProxyResponseHandler) => Promise<void>;
|
|
19
|
-
export declare const checkExperienceInput: (url?: string, staticPath?: string) => void;
|
|
20
|
-
/**
|
|
21
|
-
* Check if the request path is a Logto request path.
|
|
22
|
-
* @example isLogtoRequestPath('/oidc/.well-known/openid-configuration') // true
|
|
23
|
-
* @example isLogtoRequestPath('/oidc/auth') // true
|
|
24
|
-
* @example isLogtoRequestPath('/api/interaction/submit') // true
|
|
25
|
-
* @example isLogtoRequestPath('/consent') // true
|
|
26
|
-
*/
|
|
27
|
-
export declare const isLogtoRequestPath: (requestPath?: string) => boolean;
|
|
@@ -1,123 +0,0 @@
|
|
|
1
|
-
import { existsSync } from 'node:fs';
|
|
2
|
-
import fs from 'node:fs/promises';
|
|
3
|
-
import path from 'node:path';
|
|
4
|
-
import { isValidUrl } from '@logto/core-kit';
|
|
5
|
-
import { conditional, trySafe } from '@silverhand/essentials';
|
|
6
|
-
import chalk from 'chalk';
|
|
7
|
-
import { createProxyMiddleware, responseInterceptor } from 'http-proxy-middleware';
|
|
8
|
-
import mime from 'mime';
|
|
9
|
-
import { consoleLog } from '../../utils.js';
|
|
10
|
-
export const createProxy = (targetUrl, onProxyResponse) => {
|
|
11
|
-
const hasResponseHandler = Boolean(onProxyResponse);
|
|
12
|
-
return createProxyMiddleware({
|
|
13
|
-
target: targetUrl,
|
|
14
|
-
changeOrigin: true,
|
|
15
|
-
selfHandleResponse: hasResponseHandler,
|
|
16
|
-
...conditional(hasResponseHandler && {
|
|
17
|
-
on: {
|
|
18
|
-
proxyRes: onProxyResponse,
|
|
19
|
-
error: (error) => {
|
|
20
|
-
consoleLog.error(chalk.red(error));
|
|
21
|
-
},
|
|
22
|
-
},
|
|
23
|
-
}),
|
|
24
|
-
});
|
|
25
|
-
};
|
|
26
|
-
const index = 'index.html';
|
|
27
|
-
const indexContentType = 'text/html; charset=utf-8';
|
|
28
|
-
const noCache = 'no-cache, no-store, must-revalidate';
|
|
29
|
-
const maxAgeSevenDays = 'max-age=604_800_000';
|
|
30
|
-
export const createStaticFileProxy = (staticPath) => async (request, response) => {
|
|
31
|
-
if (!request.url) {
|
|
32
|
-
response.writeHead(400).end();
|
|
33
|
-
return;
|
|
34
|
-
}
|
|
35
|
-
if (request.method === 'HEAD' || request.method === 'GET') {
|
|
36
|
-
const fallBackToIndex = !isFileAssetPath(request.url);
|
|
37
|
-
const requestPath = path.join(staticPath, fallBackToIndex ? index : request.url);
|
|
38
|
-
try {
|
|
39
|
-
const content = await fs.readFile(requestPath, 'utf8');
|
|
40
|
-
response.setHeader('cache-control', fallBackToIndex ? noCache : maxAgeSevenDays);
|
|
41
|
-
response.setHeader('content-type', getMimeType(request.url));
|
|
42
|
-
response.writeHead(200);
|
|
43
|
-
response.end(content);
|
|
44
|
-
}
|
|
45
|
-
catch (error) {
|
|
46
|
-
consoleLog.error(chalk.red(error));
|
|
47
|
-
response.setHeader('content-type', getMimeType(request.url));
|
|
48
|
-
response.writeHead(existsSync(request.url) ? 500 : 404);
|
|
49
|
-
response.end();
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
};
|
|
53
|
-
/**
|
|
54
|
-
* Intercept the response from Logto endpoint and replace Logto endpoint URLs in the response with the
|
|
55
|
-
* proxy URL. The string replace happens in the following cases:
|
|
56
|
-
* - The response is a redirect response, and the `location` property in response header may contain Logto
|
|
57
|
-
* endpoint URI.
|
|
58
|
-
* - The response body is JSON, which consists of properties such as `**_endpoint` and `redirectTo`. These
|
|
59
|
-
* properties may contain Logto endpoint URI.
|
|
60
|
-
* - The response is HTML content that contains a form. The form action URL may contain Logto endpoint URI.
|
|
61
|
-
*
|
|
62
|
-
* Note: the `issuer` and `jwks_uri` properties in the `/oidc/.well-known` response should not be replaced,
|
|
63
|
-
* even they also contain the Logto endpoint URI.
|
|
64
|
-
*/
|
|
65
|
-
export const createLogtoResponseHandler = async ({ proxyResponse, request, response, logtoEndpointUrl, proxyUrl, verbose, }) => {
|
|
66
|
-
const { location } = proxyResponse.headers;
|
|
67
|
-
if (location) {
|
|
68
|
-
// eslint-disable-next-line @silverhand/fp/no-mutation
|
|
69
|
-
proxyResponse.headers.location = location.replace(logtoEndpointUrl.href, proxyUrl.href);
|
|
70
|
-
}
|
|
71
|
-
void responseInterceptor(async (responseBuffer, proxyResponse) => {
|
|
72
|
-
const responseBody = responseBuffer.toString();
|
|
73
|
-
if (verbose) {
|
|
74
|
-
consoleLog.info(`Response received: ${chalk.green(responseBody)}`);
|
|
75
|
-
}
|
|
76
|
-
if (proxyResponse.headers['content-type']?.includes('text/html')) {
|
|
77
|
-
return responseBody.replace(`action="${logtoEndpointUrl.href}`, `action="${proxyUrl.href}`);
|
|
78
|
-
}
|
|
79
|
-
if (proxyResponse.headers['content-type']?.includes('application/json')) {
|
|
80
|
-
const jsonData = trySafe(() => JSON.parse(responseBody));
|
|
81
|
-
if (jsonData && typeof jsonData === 'object') {
|
|
82
|
-
const updatedEntries = Object.entries(jsonData).map(([key, value]) => {
|
|
83
|
-
if ((key === 'redirectTo' || key.endsWith('_endpoint')) && typeof value === 'string') {
|
|
84
|
-
return [key, value.replace(logtoEndpointUrl.href, proxyUrl.href)];
|
|
85
|
-
}
|
|
86
|
-
return [key, value];
|
|
87
|
-
});
|
|
88
|
-
return JSON.stringify(Object.fromEntries(updatedEntries));
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
return responseBody;
|
|
92
|
-
})(proxyResponse, request, response);
|
|
93
|
-
};
|
|
94
|
-
export const checkExperienceInput = (url, staticPath) => {
|
|
95
|
-
if (staticPath && url) {
|
|
96
|
-
consoleLog.fatal('Only one of the experience URI or path can be provided.');
|
|
97
|
-
}
|
|
98
|
-
if (!staticPath && !url) {
|
|
99
|
-
consoleLog.fatal('Either a sign-in experience URI or local path must be provided.');
|
|
100
|
-
}
|
|
101
|
-
if (url && !isValidUrl(url)) {
|
|
102
|
-
consoleLog.fatal('A valid sign-in experience URI must be provided. E.g.: http://localhost:4000');
|
|
103
|
-
}
|
|
104
|
-
if (staticPath && !existsSync(path.join(staticPath, index))) {
|
|
105
|
-
consoleLog.fatal('The provided path does not contain a valid index.html file.');
|
|
106
|
-
}
|
|
107
|
-
};
|
|
108
|
-
/**
|
|
109
|
-
* Check if the request path is a Logto request path.
|
|
110
|
-
* @example isLogtoRequestPath('/oidc/.well-known/openid-configuration') // true
|
|
111
|
-
* @example isLogtoRequestPath('/oidc/auth') // true
|
|
112
|
-
* @example isLogtoRequestPath('/api/interaction/submit') // true
|
|
113
|
-
* @example isLogtoRequestPath('/consent') // true
|
|
114
|
-
*/
|
|
115
|
-
export const isLogtoRequestPath = (requestPath) => ['/oidc/', '/api/'].some((path) => requestPath?.startsWith(path)) || requestPath === '/consent';
|
|
116
|
-
const isFileAssetPath = (url) => url.split('/').at(-1)?.includes('.');
|
|
117
|
-
const getMimeType = (requestPath) => {
|
|
118
|
-
const fallBackToIndex = !isFileAssetPath(requestPath);
|
|
119
|
-
if (fallBackToIndex) {
|
|
120
|
-
return indexContentType;
|
|
121
|
-
}
|
|
122
|
-
return mime.getType(requestPath) ?? 'application/octet-stream';
|
|
123
|
-
};
|
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
import { isLanguageTag } from '@logto/language-kit';
|
|
2
|
-
import { isBuiltInLanguageTag as isPhrasesBuiltInLanguageTag } from '@logto/phrases';
|
|
3
|
-
import { isBuiltInLanguageTag as isPhrasesUiBuiltInLanguageTag } from '@logto/phrases-experience';
|
|
4
|
-
import { consoleLog, inquireInstancePath } from '../../utils.js';
|
|
5
|
-
import { createFullTranslation } from './utils.js';
|
|
6
|
-
const create = {
|
|
7
|
-
command: ['create <language-tag>', 'c'],
|
|
8
|
-
describe: 'Create a new language translation using ChatGPT. Note the environment variable `OPENAI_API_KEY` is required to work.',
|
|
9
|
-
builder: (yargs) => yargs.positional('language-tag', {
|
|
10
|
-
describe: 'The language tag to create, e.g. `af-ZA`.',
|
|
11
|
-
type: 'string',
|
|
12
|
-
demandOption: true,
|
|
13
|
-
}),
|
|
14
|
-
handler: async ({ path: inputPath, languageTag }) => {
|
|
15
|
-
if (!isLanguageTag(languageTag)) {
|
|
16
|
-
consoleLog.fatal('Invalid language tag. Run `logto translate list-tags` to see available list.');
|
|
17
|
-
}
|
|
18
|
-
const instancePath = await inquireInstancePath(inputPath);
|
|
19
|
-
if (isPhrasesBuiltInLanguageTag(languageTag)) {
|
|
20
|
-
consoleLog.info(languageTag + ' is a built-in tag of phrases, updating untranslated phrases');
|
|
21
|
-
}
|
|
22
|
-
await createFullTranslation({
|
|
23
|
-
instancePath,
|
|
24
|
-
packageName: 'phrases',
|
|
25
|
-
languageTag,
|
|
26
|
-
});
|
|
27
|
-
if (isPhrasesUiBuiltInLanguageTag(languageTag)) {
|
|
28
|
-
consoleLog.info(languageTag + ' is a built-in tag of phrases-experience, updating untranslated phrases');
|
|
29
|
-
}
|
|
30
|
-
await createFullTranslation({
|
|
31
|
-
instancePath,
|
|
32
|
-
packageName: 'phrases-experience',
|
|
33
|
-
languageTag,
|
|
34
|
-
});
|
|
35
|
-
},
|
|
36
|
-
};
|
|
37
|
-
export default create;
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
import { noop } from '@silverhand/essentials';
|
|
2
|
-
import create from './create.js';
|
|
3
|
-
import listTags from './list-tags.js';
|
|
4
|
-
import syncKeys from './sync-keys/index.js';
|
|
5
|
-
import sync from './sync.js';
|
|
6
|
-
const translate = {
|
|
7
|
-
command: ['translate', 't'],
|
|
8
|
-
describe: 'Commands for Logto translation',
|
|
9
|
-
builder: (yargs) => yargs
|
|
10
|
-
.option('path', {
|
|
11
|
-
alias: 'p',
|
|
12
|
-
type: 'string',
|
|
13
|
-
describe: 'The path to your Logto instance directory',
|
|
14
|
-
})
|
|
15
|
-
.option('skip-core-check', {
|
|
16
|
-
alias: 'sc',
|
|
17
|
-
type: 'boolean',
|
|
18
|
-
describe: 'Skip checking if the core package is existed',
|
|
19
|
-
})
|
|
20
|
-
.command(create)
|
|
21
|
-
.command(listTags)
|
|
22
|
-
.command(sync)
|
|
23
|
-
.command(syncKeys)
|
|
24
|
-
.demandCommand(1),
|
|
25
|
-
handler: noop,
|
|
26
|
-
};
|
|
27
|
-
export default translate;
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
import { languages } from '@logto/language-kit';
|
|
2
|
-
import { isBuiltInLanguageTag as isPhrasesBuiltInLanguageTag } from '@logto/phrases';
|
|
3
|
-
import { isBuiltInLanguageTag as isPhrasesUiBuiltInLanguageTag } from '@logto/phrases-experience';
|
|
4
|
-
import chalk from 'chalk';
|
|
5
|
-
import { consoleLog } from '../../utils.js';
|
|
6
|
-
const listTags = {
|
|
7
|
-
command: ['list-tags', 'list'],
|
|
8
|
-
describe: 'List all available language tags',
|
|
9
|
-
handler: async () => {
|
|
10
|
-
for (const tag of Object.keys(languages)) {
|
|
11
|
-
consoleLog.plain(...[
|
|
12
|
-
tag,
|
|
13
|
-
isPhrasesBuiltInLanguageTag(tag) && chalk.blue('phrases'),
|
|
14
|
-
isPhrasesUiBuiltInLanguageTag(tag) && chalk.blue('phrases-experience'),
|
|
15
|
-
].filter(Boolean));
|
|
16
|
-
}
|
|
17
|
-
},
|
|
18
|
-
};
|
|
19
|
-
export default listTags;
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
import { type LanguageTag } from '@logto/language-kit';
|
|
2
|
-
import { type Got } from 'got';
|
|
3
|
-
export declare const createOpenaiApi: () => Got;
|
|
4
|
-
type TranslateConfig = {
|
|
5
|
-
api: Got;
|
|
6
|
-
sourceFilePath: string;
|
|
7
|
-
targetLanguage: LanguageTag;
|
|
8
|
-
extraPrompt?: string;
|
|
9
|
-
};
|
|
10
|
-
export declare const translate: ({ api, targetLanguage, sourceFilePath, extraPrompt, }: TranslateConfig) => Promise<string | undefined>;
|
|
11
|
-
export {};
|