@intlayer/cli 8.9.6-canary.0 → 8.9.7
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/dist/cjs/auth/login.cjs +71 -75
- package/dist/cjs/auth/login.cjs.map +1 -1
- package/dist/cjs/auth/sessionToken.cjs +43 -0
- package/dist/cjs/auth/sessionToken.cjs.map +1 -0
- package/dist/cjs/utils/checkAccess.cjs +51 -30
- package/dist/cjs/utils/checkAccess.cjs.map +1 -1
- package/dist/esm/auth/login.mjs +71 -75
- package/dist/esm/auth/login.mjs.map +1 -1
- package/dist/esm/auth/sessionToken.mjs +39 -0
- package/dist/esm/auth/sessionToken.mjs.map +1 -0
- package/dist/esm/utils/checkAccess.mjs +51 -30
- package/dist/esm/utils/checkAccess.mjs.map +1 -1
- package/dist/types/auth/login.d.ts.map +1 -1
- package/dist/types/auth/sessionToken.d.ts +13 -0
- package/dist/types/auth/sessionToken.d.ts.map +1 -0
- package/dist/types/utils/checkAccess.d.ts.map +1 -1
- package/package.json +12 -12
package/dist/cjs/auth/login.cjs
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
2
2
|
const require_runtime = require('../_virtual/_rolldown/runtime.cjs');
|
|
3
3
|
const require_utils_openBrowser = require('../utils/openBrowser.cjs');
|
|
4
|
+
const require_auth_sessionToken = require('./sessionToken.cjs');
|
|
4
5
|
let _intlayer_chokidar_cli = require("@intlayer/chokidar/cli");
|
|
5
6
|
let _intlayer_config_colors = require("@intlayer/config/colors");
|
|
6
7
|
_intlayer_config_colors = require_runtime.__toESM(_intlayer_config_colors);
|
|
@@ -11,13 +12,65 @@ node_http = require_runtime.__toESM(node_http);
|
|
|
11
12
|
let node_url = require("node:url");
|
|
12
13
|
|
|
13
14
|
//#region src/auth/login.ts
|
|
15
|
+
const buildSuccessHtml = (message) => `
|
|
16
|
+
<!DOCTYPE html>
|
|
17
|
+
<html lang="en" data-theme="dark">
|
|
18
|
+
<head>
|
|
19
|
+
<meta charset="UTF-8">
|
|
20
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
21
|
+
<title>Intlayer CLI Login</title>
|
|
22
|
+
<style>
|
|
23
|
+
:root {
|
|
24
|
+
--color-background: rgba(23, 23, 23);
|
|
25
|
+
--color-card: rgba(39, 39, 39);
|
|
26
|
+
--color-text: rgba(255, 245, 237);
|
|
27
|
+
--color-neutral: rgba(93, 93, 93);
|
|
28
|
+
--font-sans: "Inter", -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;
|
|
29
|
+
}
|
|
30
|
+
* { box-sizing: border-box; }
|
|
31
|
+
body {
|
|
32
|
+
font-family: var(--font-sans);
|
|
33
|
+
display: flex;
|
|
34
|
+
align-items: center;
|
|
35
|
+
justify-content: center;
|
|
36
|
+
min-height: 100vh;
|
|
37
|
+
margin: 0;
|
|
38
|
+
padding: 1rem;
|
|
39
|
+
background-color: var(--color-background);
|
|
40
|
+
color: var(--color-text);
|
|
41
|
+
}
|
|
42
|
+
.container {
|
|
43
|
+
text-align: center;
|
|
44
|
+
padding: 2rem;
|
|
45
|
+
border-radius: 1rem;
|
|
46
|
+
background-color: var(--color-card);
|
|
47
|
+
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
|
|
48
|
+
max-width: 400px;
|
|
49
|
+
width: 100%;
|
|
50
|
+
}
|
|
51
|
+
h1 { margin: 0 0 1rem 0; font-size: 1.5rem; font-weight: 700; color: var(--color-text); }
|
|
52
|
+
p { color: var(--color-neutral); font-size: 0.8rem; margin: 0 0 1.5rem 0; line-height: 1.5; }
|
|
53
|
+
</style>
|
|
54
|
+
</head>
|
|
55
|
+
<body>
|
|
56
|
+
<div class="container">
|
|
57
|
+
<h1>Login Successful</h1>
|
|
58
|
+
<p>${message}</p>
|
|
59
|
+
</div>
|
|
60
|
+
<script>
|
|
61
|
+
window.close();
|
|
62
|
+
setTimeout(() => { window.close(); }, 1000);
|
|
63
|
+
<\/script>
|
|
64
|
+
</body>
|
|
65
|
+
</html>
|
|
66
|
+
`;
|
|
14
67
|
const login = async (options) => {
|
|
15
68
|
const configuration = (0, _intlayer_config_node.getConfiguration)(options.configOptions);
|
|
16
69
|
(0, _intlayer_chokidar_cli.logConfigDetails)(options?.configOptions);
|
|
17
70
|
const logger = (0, _intlayer_config_logger.getAppLogger)(configuration);
|
|
18
71
|
const cmsUrl = options.cmsUrl ?? configuration.editor.cmsURL;
|
|
19
72
|
return new Promise((resolve) => {
|
|
20
|
-
const server = node_http.default.createServer((req, res) => {
|
|
73
|
+
const server = node_http.default.createServer(async (req, res) => {
|
|
21
74
|
const url = new node_url.URL(req.url ?? "", `http://${req.headers.host}`);
|
|
22
75
|
res.setHeader("Access-Control-Allow-Origin", "*");
|
|
23
76
|
res.setHeader("Access-Control-Allow-Methods", "GET, OPTIONS");
|
|
@@ -28,8 +81,24 @@ const login = async (options) => {
|
|
|
28
81
|
return;
|
|
29
82
|
}
|
|
30
83
|
if (url.pathname === "/callback") {
|
|
84
|
+
const sessionToken = url.searchParams.get("sessionToken");
|
|
85
|
+
const sessionExpiresAt = url.searchParams.get("expiresAt");
|
|
31
86
|
const clientId = url.searchParams.get("clientId");
|
|
32
87
|
const clientSecret = url.searchParams.get("clientSecret");
|
|
88
|
+
if (sessionToken && sessionExpiresAt) {
|
|
89
|
+
logger("");
|
|
90
|
+
logger(`Log in successful. ${(0, _intlayer_config_logger.colorize)("2h", _intlayer_config_colors.BLUE)} session token received.`);
|
|
91
|
+
logger("");
|
|
92
|
+
logger((0, _intlayer_config_logger.colorize)(`Token expires at: ${new Date(sessionExpiresAt).toLocaleString()}`, _intlayer_config_colors.GREY));
|
|
93
|
+
await require_auth_sessionToken.writeCliSessionToken(configuration, sessionToken, new Date(sessionExpiresAt));
|
|
94
|
+
res.writeHead(200, { "Content-Type": "text/html" });
|
|
95
|
+
res.end(buildSuccessHtml("Your 2h session token has been stored. You can now close this tab and return to your terminal."));
|
|
96
|
+
server.close(() => {
|
|
97
|
+
resolve();
|
|
98
|
+
process.exit(0);
|
|
99
|
+
});
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
33
102
|
if (clientId && clientSecret) {
|
|
34
103
|
logger("");
|
|
35
104
|
logger("Log in successful. Client ID and Client Secret received.");
|
|
@@ -60,80 +129,7 @@ const login = async (options) => {
|
|
|
60
129
|
});
|
|
61
130
|
logger((0, _intlayer_config_logger.colorize)("--------------------------------", _intlayer_config_colors.GREY_DARK));
|
|
62
131
|
res.writeHead(200, { "Content-Type": "text/html" });
|
|
63
|
-
res.end(
|
|
64
|
-
<!DOCTYPE html>
|
|
65
|
-
<html lang="en" data-theme="dark">
|
|
66
|
-
<head>
|
|
67
|
-
<meta charset="UTF-8">
|
|
68
|
-
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
69
|
-
<title>Intlayer CLI Login</title>
|
|
70
|
-
<style>
|
|
71
|
-
:root {
|
|
72
|
-
--color-background: rgba(23, 23, 23);
|
|
73
|
-
--color-card: rgba(39, 39, 39);
|
|
74
|
-
--color-text: rgba(255, 245, 237);
|
|
75
|
-
--color-neutral: rgba(93, 93, 93);
|
|
76
|
-
--font-sans: "Inter", -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
* {
|
|
80
|
-
box-sizing: border-box;
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
body {
|
|
84
|
-
font-family: var(--font-sans);
|
|
85
|
-
display: flex;
|
|
86
|
-
align-items: center;
|
|
87
|
-
justify-content: center;
|
|
88
|
-
min-height: 100vh;
|
|
89
|
-
margin: 0;
|
|
90
|
-
padding: 1rem;
|
|
91
|
-
background-color: var(--color-background);
|
|
92
|
-
color: var(--color-text);
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
.container {
|
|
96
|
-
text-align: center;
|
|
97
|
-
padding: 2rem;
|
|
98
|
-
border-radius: 1rem;
|
|
99
|
-
background-color: var(--color-card);
|
|
100
|
-
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
|
|
101
|
-
max-width: 400px;
|
|
102
|
-
width: 100%;
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
h1 {
|
|
106
|
-
margin: 0 0 1rem 0;
|
|
107
|
-
font-size: 1.5rem;
|
|
108
|
-
font-weight: 700;
|
|
109
|
-
color: var(--color-text);
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
p {
|
|
113
|
-
color: var(--color-neutral);
|
|
114
|
-
font-size: 0.8rem;
|
|
115
|
-
margin: 0 0 1.5rem 0;
|
|
116
|
-
line-height: 1.5;
|
|
117
|
-
}
|
|
118
|
-
</style>
|
|
119
|
-
</head>
|
|
120
|
-
<body>
|
|
121
|
-
<div class="container">
|
|
122
|
-
<h1>Login Successful</h1>
|
|
123
|
-
<p>You have successfully logged in to Intlayer CLI. You can now close this tab and return to your terminal.</p>
|
|
124
|
-
</div>
|
|
125
|
-
<script>
|
|
126
|
-
// Attempt to close the window
|
|
127
|
-
window.close();
|
|
128
|
-
|
|
129
|
-
// Fallback: if window.close() doesn't work, show a message
|
|
130
|
-
setTimeout(() => {
|
|
131
|
-
window.close();
|
|
132
|
-
}, 1000);
|
|
133
|
-
<\/script>
|
|
134
|
-
</body>
|
|
135
|
-
</html>
|
|
136
|
-
`);
|
|
132
|
+
res.end(buildSuccessHtml("You have successfully logged in to Intlayer CLI. You can now close this tab and return to your terminal."));
|
|
137
133
|
server.close(() => {
|
|
138
134
|
resolve();
|
|
139
135
|
process.exit(0);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"login.cjs","names":["http","URL","ANSIColors"],"sources":["../../../src/auth/login.ts"],"sourcesContent":["import http from 'node:http';\nimport { URL } from 'node:url';\nimport { logConfigDetails } from '@intlayer/chokidar/cli';\nimport * as ANSIColors from '@intlayer/config/colors';\nimport { colorize, colorizePath, getAppLogger } from '@intlayer/config/logger';\nimport {\n type GetConfigurationOptions,\n getConfiguration,\n} from '@intlayer/config/node';\nimport { openBrowser } from '../utils/openBrowser';\n\ntype LoginOptions = {\n cmsUrl?: string;\n configOptions?: GetConfigurationOptions;\n};\n\nexport const login = async (options: LoginOptions) => {\n const configuration = getConfiguration(options.configOptions);\n logConfigDetails(options?.configOptions);\n\n const logger = getAppLogger(configuration);\n\n const cmsUrl = options.cmsUrl ?? configuration.editor.cmsURL;\n\n return new Promise<void>((resolve) => {\n const server = http.createServer((req, res) => {\n const url = new URL(req.url ?? '', `http://${req.headers.host}`);\n\n // Set CORS headers\n res.setHeader('Access-Control-Allow-Origin', '*');\n res.setHeader('Access-Control-Allow-Methods', 'GET, OPTIONS');\n res.setHeader('Access-Control-Allow-Headers', 'Content-Type');\n\n if (req.method === 'OPTIONS') {\n res.writeHead(204);\n res.end();\n return;\n }\n\n if (url.pathname === '/callback') {\n const clientId = url.searchParams.get('clientId');\n const clientSecret = url.searchParams.get('clientSecret');\n\n if (clientId && clientSecret) {\n logger('');\n logger('Log in successful. Client ID and Client Secret received.');\n\n logger('');\n logger([\n '1. Insert the Client ID and Client Secret in your',\n colorizePath('.env'),\n 'file:',\n ]);\n logger(\n colorize('--------------------------------', ANSIColors.GREY_DARK)\n );\n logger(\n [\n colorize('INTLAYER_CLIENT_ID=', ANSIColors.GREY_LIGHT),\n colorize(clientId, ANSIColors.BLUE),\n ].join('')\n );\n logger(\n [\n colorize('INTLAYER_CLIENT_SECRET=', ANSIColors.GREY_LIGHT),\n colorize(clientSecret, ANSIColors.BLUE),\n ].join('')\n );\n logger(\n colorize('--------------------------------', ANSIColors.GREY_DARK)\n );\n logger('');\n logger('2. Insert in your Intlayer configuration file:');\n logger(\n colorize('--------------------------------', ANSIColors.GREY_DARK)\n );\n [\n `${ANSIColors.GREY_LIGHT}{`,\n ` editor: {`,\n ` enabled: true,`,\n ` cmsURL: '${colorizePath(cmsUrl!, undefined, ANSIColors.GREY_LIGHT)}',`,\n ` clientId: '${colorize('process.env.INTLAYER_CLIENT_ID', ANSIColors.BLUE, ANSIColors.GREY_LIGHT)}',`,\n ` clientSecret: '${colorize('process.env.INTLAYER_CLIENT_SECRET', ANSIColors.BLUE, ANSIColors.GREY_LIGHT)}',`,\n ` },`,\n `}`,\n ].forEach((line) => {\n logger(line);\n });\n logger(\n colorize('--------------------------------', ANSIColors.GREY_DARK)\n );\n\n res.writeHead(200, { 'Content-Type': 'text/html' });\n res.end(
|
|
1
|
+
{"version":3,"file":"login.cjs","names":["http","URL","ANSIColors","writeCliSessionToken"],"sources":["../../../src/auth/login.ts"],"sourcesContent":["import http from 'node:http';\nimport { relative } from 'node:path';\nimport { URL } from 'node:url';\nimport { logConfigDetails } from '@intlayer/chokidar/cli';\nimport * as ANSIColors from '@intlayer/config/colors';\nimport { colorize, colorizePath, getAppLogger } from '@intlayer/config/logger';\nimport {\n type GetConfigurationOptions,\n getConfiguration,\n} from '@intlayer/config/node';\nimport { openBrowser } from '../utils/openBrowser';\nimport { writeCliSessionToken } from './sessionToken';\n\nconst buildSuccessHtml = (message: string): string => `\n <!DOCTYPE html>\n <html lang=\"en\" data-theme=\"dark\">\n <head>\n <meta charset=\"UTF-8\">\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n <title>Intlayer CLI Login</title>\n <style>\n :root {\n --color-background: rgba(23, 23, 23);\n --color-card: rgba(39, 39, 39);\n --color-text: rgba(255, 245, 237);\n --color-neutral: rgba(93, 93, 93);\n --font-sans: \"Inter\", -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;\n }\n * { box-sizing: border-box; }\n body {\n font-family: var(--font-sans);\n display: flex;\n align-items: center;\n justify-content: center;\n min-height: 100vh;\n margin: 0;\n padding: 1rem;\n background-color: var(--color-background);\n color: var(--color-text);\n }\n .container {\n text-align: center;\n padding: 2rem;\n border-radius: 1rem;\n background-color: var(--color-card);\n box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);\n max-width: 400px;\n width: 100%;\n }\n h1 { margin: 0 0 1rem 0; font-size: 1.5rem; font-weight: 700; color: var(--color-text); }\n p { color: var(--color-neutral); font-size: 0.8rem; margin: 0 0 1.5rem 0; line-height: 1.5; }\n </style>\n </head>\n <body>\n <div class=\"container\">\n <h1>Login Successful</h1>\n <p>${message}</p>\n </div>\n <script>\n window.close();\n setTimeout(() => { window.close(); }, 1000);\n </script>\n </body>\n </html>\n`;\n\ntype LoginOptions = {\n cmsUrl?: string;\n configOptions?: GetConfigurationOptions;\n};\n\nexport const login = async (options: LoginOptions) => {\n const configuration = getConfiguration(options.configOptions);\n logConfigDetails(options?.configOptions);\n\n const logger = getAppLogger(configuration);\n\n const cmsUrl = options.cmsUrl ?? configuration.editor.cmsURL;\n\n return new Promise<void>((resolve) => {\n const server = http.createServer(async (req, res) => {\n const url = new URL(req.url ?? '', `http://${req.headers.host}`);\n\n // Set CORS headers\n res.setHeader('Access-Control-Allow-Origin', '*');\n res.setHeader('Access-Control-Allow-Methods', 'GET, OPTIONS');\n res.setHeader('Access-Control-Allow-Headers', 'Content-Type');\n\n if (req.method === 'OPTIONS') {\n res.writeHead(204);\n res.end();\n return;\n }\n\n if (url.pathname === '/callback') {\n const sessionToken = url.searchParams.get('sessionToken');\n const sessionExpiresAt = url.searchParams.get('expiresAt');\n const clientId = url.searchParams.get('clientId');\n const clientSecret = url.searchParams.get('clientSecret');\n\n if (sessionToken && sessionExpiresAt) {\n logger('');\n logger(\n `Log in successful. ${colorize('2h', ANSIColors.BLUE)} session token received.`\n );\n logger('');\n\n logger(\n colorize(\n `Token expires at: ${new Date(sessionExpiresAt).toLocaleString()}`,\n ANSIColors.GREY\n )\n );\n\n await writeCliSessionToken(\n configuration,\n sessionToken,\n new Date(sessionExpiresAt)\n );\n\n res.writeHead(200, { 'Content-Type': 'text/html' });\n res.end(\n buildSuccessHtml(\n 'Your 2h session token has been stored. You can now close this tab and return to your terminal.'\n )\n );\n\n server.close(() => {\n resolve();\n process.exit(0);\n });\n return;\n }\n\n if (clientId && clientSecret) {\n logger('');\n logger('Log in successful. Client ID and Client Secret received.');\n\n logger('');\n logger([\n '1. Insert the Client ID and Client Secret in your',\n colorizePath('.env'),\n 'file:',\n ]);\n logger(\n colorize('--------------------------------', ANSIColors.GREY_DARK)\n );\n logger(\n [\n colorize('INTLAYER_CLIENT_ID=', ANSIColors.GREY_LIGHT),\n colorize(clientId, ANSIColors.BLUE),\n ].join('')\n );\n logger(\n [\n colorize('INTLAYER_CLIENT_SECRET=', ANSIColors.GREY_LIGHT),\n colorize(clientSecret, ANSIColors.BLUE),\n ].join('')\n );\n logger(\n colorize('--------------------------------', ANSIColors.GREY_DARK)\n );\n logger('');\n logger('2. Insert in your Intlayer configuration file:');\n logger(\n colorize('--------------------------------', ANSIColors.GREY_DARK)\n );\n [\n `${ANSIColors.GREY_LIGHT}{`,\n ` editor: {`,\n ` enabled: true,`,\n ` cmsURL: '${colorizePath(cmsUrl!, undefined, ANSIColors.GREY_LIGHT)}',`,\n ` clientId: '${colorize('process.env.INTLAYER_CLIENT_ID', ANSIColors.BLUE, ANSIColors.GREY_LIGHT)}',`,\n ` clientSecret: '${colorize('process.env.INTLAYER_CLIENT_SECRET', ANSIColors.BLUE, ANSIColors.GREY_LIGHT)}',`,\n ` },`,\n `}`,\n ].forEach((line) => {\n logger(line);\n });\n logger(\n colorize('--------------------------------', ANSIColors.GREY_DARK)\n );\n\n res.writeHead(200, { 'Content-Type': 'text/html' });\n res.end(\n buildSuccessHtml(\n 'You have successfully logged in to Intlayer CLI. You can now close this tab and return to your terminal.'\n )\n );\n\n server.close(() => {\n resolve();\n process.exit(0);\n });\n } else {\n res.writeHead(400, { 'Content-Type': 'text/plain' });\n res.end('Missing parameters');\n }\n } else {\n res.writeHead(404, { 'Content-Type': 'text/plain' });\n res.end('Not found');\n }\n });\n\n server.listen(0, () => {\n const address = server.address();\n const port = typeof address === 'object' && address ? address.port : 0;\n const state = Math.random().toString(36).substring(7);\n\n const websiteUrl =\n cmsUrl ?? process.env.INTLAYER_SITE_URL ?? 'http://localhost:3000';\n const loginUrl = `${websiteUrl}/auth/cli-login?port=${port}&state=${state}`;\n\n logger('Opening browser for login...');\n logger(`If browser does not open, visit: ${colorizePath(loginUrl)}`);\n\n openBrowser(loginUrl);\n });\n });\n};\n"],"mappings":"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"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
2
|
+
const require_runtime = require('../_virtual/_rolldown/runtime.cjs');
|
|
3
|
+
let node_path = require("node:path");
|
|
4
|
+
let node_fs_promises = require("node:fs/promises");
|
|
5
|
+
|
|
6
|
+
//#region src/auth/sessionToken.ts
|
|
7
|
+
const SESSION_FILE_NAME = "cli-session.json";
|
|
8
|
+
const getSessionFilePath = (config) => (0, node_path.join)(config.system.tempDir, SESSION_FILE_NAME);
|
|
9
|
+
const writeCliSessionToken = async (config, token, expiresAt) => {
|
|
10
|
+
const filePath = getSessionFilePath(config);
|
|
11
|
+
await (0, node_fs_promises.mkdir)(config.system.tempDir, { recursive: true });
|
|
12
|
+
const data = {
|
|
13
|
+
token,
|
|
14
|
+
expiresAt: expiresAt.toISOString()
|
|
15
|
+
};
|
|
16
|
+
await (0, node_fs_promises.writeFile)(filePath, JSON.stringify(data, null, 2), { mode: 384 });
|
|
17
|
+
};
|
|
18
|
+
const readCliSessionToken = async (config) => {
|
|
19
|
+
const filePath = getSessionFilePath(config);
|
|
20
|
+
try {
|
|
21
|
+
const raw = await (0, node_fs_promises.readFile)(filePath, "utf8");
|
|
22
|
+
const data = JSON.parse(raw);
|
|
23
|
+
if (!data.token || !data.expiresAt) return null;
|
|
24
|
+
if (/* @__PURE__ */ new Date() >= new Date(data.expiresAt)) {
|
|
25
|
+
await clearCliSessionToken(config);
|
|
26
|
+
return null;
|
|
27
|
+
}
|
|
28
|
+
return data;
|
|
29
|
+
} catch {
|
|
30
|
+
return null;
|
|
31
|
+
}
|
|
32
|
+
};
|
|
33
|
+
const clearCliSessionToken = async (config) => {
|
|
34
|
+
try {
|
|
35
|
+
await (0, node_fs_promises.unlink)(getSessionFilePath(config));
|
|
36
|
+
} catch {}
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
//#endregion
|
|
40
|
+
exports.clearCliSessionToken = clearCliSessionToken;
|
|
41
|
+
exports.readCliSessionToken = readCliSessionToken;
|
|
42
|
+
exports.writeCliSessionToken = writeCliSessionToken;
|
|
43
|
+
//# sourceMappingURL=sessionToken.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sessionToken.cjs","names":[],"sources":["../../../src/auth/sessionToken.ts"],"sourcesContent":["import { mkdir, readFile, unlink, writeFile } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport type { IntlayerConfig } from '@intlayer/types/config';\n\nconst SESSION_FILE_NAME = 'cli-session.json';\n\ntype CliSessionData = {\n token: string;\n expiresAt: string; // ISO date string\n};\n\nconst getSessionFilePath = (config: IntlayerConfig): string =>\n join(config.system.tempDir, SESSION_FILE_NAME);\n\nexport const writeCliSessionToken = async (\n config: IntlayerConfig,\n token: string,\n expiresAt: Date\n): Promise<void> => {\n const filePath = getSessionFilePath(config);\n\n await mkdir(config.system.tempDir, { recursive: true });\n\n const data: CliSessionData = { token, expiresAt: expiresAt.toISOString() };\n await writeFile(filePath, JSON.stringify(data, null, 2), { mode: 0o600 });\n};\n\nexport const readCliSessionToken = async (\n config: IntlayerConfig\n): Promise<CliSessionData | null> => {\n const filePath = getSessionFilePath(config);\n\n try {\n const raw = await readFile(filePath, 'utf8');\n const data: CliSessionData = JSON.parse(raw);\n\n if (!data.token || !data.expiresAt) {\n return null;\n }\n\n if (new Date() >= new Date(data.expiresAt)) {\n await clearCliSessionToken(config);\n return null;\n }\n\n return data;\n } catch {\n return null;\n }\n};\n\nexport const clearCliSessionToken = async (\n config: IntlayerConfig\n): Promise<void> => {\n try {\n await unlink(getSessionFilePath(config));\n } catch {\n // Ignore errors (file may not exist)\n }\n};\n"],"mappings":";;;;;;AAIA,MAAM,oBAAoB;AAO1B,MAAM,sBAAsB,+BACrB,OAAO,OAAO,SAAS,kBAAkB;AAEhD,MAAa,uBAAuB,OAClC,QACA,OACA,cACkB;CAClB,MAAM,WAAW,mBAAmB,OAAO;CAE3C,kCAAY,OAAO,OAAO,SAAS,EAAE,WAAW,MAAM,CAAC;CAEvD,MAAM,OAAuB;EAAE;EAAO,WAAW,UAAU,aAAa;EAAE;CAC1E,sCAAgB,UAAU,KAAK,UAAU,MAAM,MAAM,EAAE,EAAE,EAAE,MAAM,KAAO,CAAC;;AAG3E,MAAa,sBAAsB,OACjC,WACmC;CACnC,MAAM,WAAW,mBAAmB,OAAO;CAE3C,IAAI;EACF,MAAM,MAAM,qCAAe,UAAU,OAAO;EAC5C,MAAM,OAAuB,KAAK,MAAM,IAAI;EAE5C,IAAI,CAAC,KAAK,SAAS,CAAC,KAAK,WACvB,OAAO;EAGT,oBAAI,IAAI,MAAM,IAAI,IAAI,KAAK,KAAK,UAAU,EAAE;GAC1C,MAAM,qBAAqB,OAAO;GAClC,OAAO;;EAGT,OAAO;SACD;EACN,OAAO;;;AAIX,MAAa,uBAAuB,OAClC,WACkB;CAClB,IAAI;EACF,mCAAa,mBAAmB,OAAO,CAAC;SAClC"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
2
2
|
const require_runtime = require('../_virtual/_rolldown/runtime.cjs');
|
|
3
|
+
const require_auth_sessionToken = require('../auth/sessionToken.cjs');
|
|
3
4
|
const require_utils_checkConfigConsistency = require('./checkConfigConsistency.cjs');
|
|
4
5
|
let _intlayer_config_colors = require("@intlayer/config/colors");
|
|
5
6
|
_intlayer_config_colors = require_runtime.__toESM(_intlayer_config_colors);
|
|
@@ -8,12 +9,53 @@ let _intlayer_api = require("@intlayer/api");
|
|
|
8
9
|
let _intlayer_config_utils = require("@intlayer/config/utils");
|
|
9
10
|
|
|
10
11
|
//#region src/utils/checkAccess.ts
|
|
12
|
+
const checkProjectConfigConsistency = (project, configuration, appLogger) => {
|
|
13
|
+
if (!project?.configuration) return;
|
|
14
|
+
try {
|
|
15
|
+
let remoteConfigToCheck = project.configuration;
|
|
16
|
+
if (remoteConfigToCheck.ai && "apiKeyConfigured" in remoteConfigToCheck.ai) {
|
|
17
|
+
const { apiKeyConfigured, ...restAi } = remoteConfigToCheck.ai;
|
|
18
|
+
remoteConfigToCheck = {
|
|
19
|
+
...remoteConfigToCheck,
|
|
20
|
+
ai: restAi
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
require_utils_checkConfigConsistency.checkConfigConsistency(remoteConfigToCheck, configuration);
|
|
24
|
+
} catch {
|
|
25
|
+
appLogger([
|
|
26
|
+
"Remote configuration is not up to date. The project configuration does not match the local configuration.",
|
|
27
|
+
"You can push the configuration by running",
|
|
28
|
+
(0, _intlayer_config_logger.colorize)("npx intlayer configuration push", _intlayer_config_colors.CYAN),
|
|
29
|
+
(0, _intlayer_config_logger.colorize)("(see doc:", _intlayer_config_colors.GREY_DARK),
|
|
30
|
+
(0, _intlayer_config_logger.colorize)("https://intlayer.org/doc/concept/cli/push", _intlayer_config_colors.GREY),
|
|
31
|
+
(0, _intlayer_config_logger.colorize)(")", _intlayer_config_colors.GREY_DARK),
|
|
32
|
+
"."
|
|
33
|
+
], { level: "warn" });
|
|
34
|
+
}
|
|
35
|
+
};
|
|
11
36
|
const checkCMSAuth = async (configuration, shouldCheckConfigConsistency = true) => {
|
|
12
37
|
const appLogger = (0, _intlayer_config_logger.getAppLogger)(configuration);
|
|
38
|
+
const sessionData = await require_auth_sessionToken.readCliSessionToken(configuration);
|
|
39
|
+
if (sessionData) {
|
|
40
|
+
const intlayerAPI = (0, _intlayer_api.getIntlayerAPIProxy)(void 0, configuration, sessionData.token);
|
|
41
|
+
try {
|
|
42
|
+
const project = (await intlayerAPI.oAuth.getCliSessionMe()).data?.project;
|
|
43
|
+
if (project && shouldCheckConfigConsistency) checkProjectConfigConsistency(project, configuration, appLogger);
|
|
44
|
+
return true;
|
|
45
|
+
} catch (error) {
|
|
46
|
+
appLogger((0, _intlayer_config_utils.extractErrorMessage)(error), { level: "error" });
|
|
47
|
+
return false;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
13
50
|
if (!(configuration.editor.clientId && configuration.editor.clientSecret)) {
|
|
14
51
|
appLogger([
|
|
15
|
-
"CMS auth not provided.
|
|
16
|
-
(0, _intlayer_config_logger.colorize)("
|
|
52
|
+
"CMS auth not provided. Run",
|
|
53
|
+
(0, _intlayer_config_logger.colorize)("npx intlayer login", _intlayer_config_colors.CYAN),
|
|
54
|
+
"to authenticate, or set",
|
|
55
|
+
(0, _intlayer_config_logger.colorize)("INTLAYER_CLIENT_ID", _intlayer_config_colors.GREY_LIGHT),
|
|
56
|
+
"and",
|
|
57
|
+
(0, _intlayer_config_logger.colorize)("INTLAYER_CLIENT_SECRET", _intlayer_config_colors.GREY_LIGHT),
|
|
58
|
+
"in your .env file",
|
|
17
59
|
(0, _intlayer_config_logger.colorize)("(see doc:", _intlayer_config_colors.GREY_DARK),
|
|
18
60
|
(0, _intlayer_config_logger.colorize)("https://intlayer.org/doc/concept/cms", _intlayer_config_colors.GREY),
|
|
19
61
|
(0, _intlayer_config_logger.colorize)(")", _intlayer_config_colors.GREY_DARK),
|
|
@@ -28,27 +70,7 @@ const checkCMSAuth = async (configuration, shouldCheckConfigConsistency = true)
|
|
|
28
70
|
appLogger("Project not found");
|
|
29
71
|
return true;
|
|
30
72
|
}
|
|
31
|
-
if (project
|
|
32
|
-
let remoteConfigToCheck = project.configuration;
|
|
33
|
-
if (remoteConfigToCheck.ai && "apiKeyConfigured" in remoteConfigToCheck.ai) {
|
|
34
|
-
const { apiKeyConfigured, ...restAi } = remoteConfigToCheck.ai;
|
|
35
|
-
remoteConfigToCheck = {
|
|
36
|
-
...remoteConfigToCheck,
|
|
37
|
-
ai: restAi
|
|
38
|
-
};
|
|
39
|
-
}
|
|
40
|
-
require_utils_checkConfigConsistency.checkConfigConsistency(remoteConfigToCheck, configuration);
|
|
41
|
-
} catch {
|
|
42
|
-
appLogger([
|
|
43
|
-
"Remote configuration is not up to date. The project configuration does not match the local configuration.",
|
|
44
|
-
"You can push the configuration by running",
|
|
45
|
-
(0, _intlayer_config_logger.colorize)("npx intlayer configuration push", _intlayer_config_colors.CYAN),
|
|
46
|
-
(0, _intlayer_config_logger.colorize)("(see doc:", _intlayer_config_colors.GREY_DARK),
|
|
47
|
-
(0, _intlayer_config_logger.colorize)("https://intlayer.org/doc/concept/cli/push", _intlayer_config_colors.GREY),
|
|
48
|
-
(0, _intlayer_config_logger.colorize)(")", _intlayer_config_colors.GREY_DARK),
|
|
49
|
-
"."
|
|
50
|
-
], { level: "warn" });
|
|
51
|
-
}
|
|
73
|
+
if (shouldCheckConfigConsistency) checkProjectConfigConsistency(project, configuration, appLogger);
|
|
52
74
|
} catch (error) {
|
|
53
75
|
appLogger((0, _intlayer_config_utils.extractErrorMessage)(error), { level: "error" });
|
|
54
76
|
return false;
|
|
@@ -58,16 +80,15 @@ const checkCMSAuth = async (configuration, shouldCheckConfigConsistency = true)
|
|
|
58
80
|
const checkAIAccess = async (configuration, aiOptions, shouldCheckConfigConsistency = true) => {
|
|
59
81
|
const appLogger = (0, _intlayer_config_logger.getAppLogger)(configuration);
|
|
60
82
|
const hasCMSAuth = Boolean(configuration.editor.clientId && configuration.editor.clientSecret);
|
|
83
|
+
const sessionData = await require_auth_sessionToken.readCliSessionToken(configuration);
|
|
84
|
+
const hasSessionToken = Boolean(sessionData);
|
|
61
85
|
const isOllama = configuration.ai?.provider === "ollama" || aiOptions?.provider === "ollama";
|
|
62
86
|
if (Boolean(configuration.ai?.apiKey || aiOptions?.apiKey) || isOllama) return true;
|
|
63
|
-
if (!hasCMSAuth) {
|
|
87
|
+
if (!hasCMSAuth && !hasSessionToken) {
|
|
64
88
|
appLogger([
|
|
65
|
-
"AI options or API key not provided.
|
|
66
|
-
(0, _intlayer_config_logger.colorize)("
|
|
67
|
-
|
|
68
|
-
(0, _intlayer_config_logger.colorize)("https://intlayer.org/doc/concept/cms", _intlayer_config_colors.GREY),
|
|
69
|
-
(0, _intlayer_config_logger.colorize)(")", _intlayer_config_colors.GREY_DARK),
|
|
70
|
-
". Alternatively, you can add your own OpenAI API key in the settings",
|
|
89
|
+
"AI options or API key not provided. Run",
|
|
90
|
+
(0, _intlayer_config_logger.colorize)("npx intlayer login", _intlayer_config_colors.CYAN),
|
|
91
|
+
"to authenticate, or provide an API key",
|
|
71
92
|
(0, _intlayer_config_logger.colorize)("(see doc:", _intlayer_config_colors.GREY_DARK),
|
|
72
93
|
(0, _intlayer_config_logger.colorize)("https://intlayer.org/doc/concept/configuration", _intlayer_config_colors.GREY),
|
|
73
94
|
(0, _intlayer_config_logger.colorize)(")", _intlayer_config_colors.GREY_DARK),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"checkAccess.cjs","names":["ANSIColors"],"sources":["../../../src/utils/checkAccess.ts"],"sourcesContent":["import type { AIOptions } from '@intlayer/api';\nimport { getIntlayerAPIProxy } from '@intlayer/api';\nimport * as ANSIColors from '@intlayer/config/colors';\nimport { colorize, getAppLogger } from '@intlayer/config/logger';\nimport { extractErrorMessage } from '@intlayer/config/utils';\nimport type { IntlayerConfig } from '@intlayer/types/config';\nimport { checkConfigConsistency } from './checkConfigConsistency';\n\
|
|
1
|
+
{"version":3,"file":"checkAccess.cjs","names":["ANSIColors","readCliSessionToken"],"sources":["../../../src/utils/checkAccess.ts"],"sourcesContent":["import type { AIOptions } from '@intlayer/api';\nimport { getIntlayerAPIProxy } from '@intlayer/api';\nimport * as ANSIColors from '@intlayer/config/colors';\nimport { colorize, getAppLogger } from '@intlayer/config/logger';\nimport { extractErrorMessage } from '@intlayer/config/utils';\nimport type { IntlayerConfig } from '@intlayer/types/config';\nimport { readCliSessionToken } from '../auth/sessionToken';\nimport { checkConfigConsistency } from './checkConfigConsistency';\n\nconst checkProjectConfigConsistency = (\n project: { configuration?: any } | null | undefined,\n configuration: IntlayerConfig,\n appLogger: ReturnType<typeof getAppLogger>\n): void => {\n if (!project?.configuration) return;\n\n try {\n let remoteConfigToCheck = project.configuration;\n\n if (\n remoteConfigToCheck.ai &&\n 'apiKeyConfigured' in remoteConfigToCheck.ai\n ) {\n const { apiKeyConfigured, ...restAi } = remoteConfigToCheck.ai as any;\n remoteConfigToCheck = { ...remoteConfigToCheck, ai: restAi };\n }\n\n checkConfigConsistency(remoteConfigToCheck, configuration);\n } catch {\n appLogger(\n [\n 'Remote configuration is not up to date. The project configuration does not match the local configuration.',\n 'You can push the configuration by running',\n colorize('npx intlayer configuration push', ANSIColors.CYAN),\n colorize('(see doc:', ANSIColors.GREY_DARK),\n colorize('https://intlayer.org/doc/concept/cli/push', ANSIColors.GREY),\n colorize(')', ANSIColors.GREY_DARK),\n '.',\n ],\n { level: 'warn' }\n );\n }\n};\n\nexport const checkCMSAuth = async (\n configuration: IntlayerConfig,\n shouldCheckConfigConsistency: boolean = true\n): Promise<boolean> => {\n const appLogger = getAppLogger(configuration);\n\n // Try CLI session token first (short-lived 2h token stored in tempDir)\n const sessionData = await readCliSessionToken(configuration);\n if (sessionData) {\n const intlayerAPI = getIntlayerAPIProxy(\n undefined,\n configuration,\n sessionData.token\n );\n\n try {\n const result = await intlayerAPI.oAuth.getCliSessionMe();\n const project = result.data?.project;\n\n if (project && shouldCheckConfigConsistency) {\n checkProjectConfigConsistency(project, configuration, appLogger);\n }\n\n return true;\n } catch (error) {\n const message = extractErrorMessage(error);\n appLogger(message, { level: 'error' });\n return false;\n }\n }\n\n // Fall back to client_credentials (access key)\n const hasCMSAuth =\n configuration.editor.clientId && configuration.editor.clientSecret;\n if (!hasCMSAuth) {\n appLogger(\n [\n 'CMS auth not provided. Run',\n colorize('npx intlayer login', ANSIColors.CYAN),\n 'to authenticate, or set',\n colorize('INTLAYER_CLIENT_ID', ANSIColors.GREY_LIGHT),\n 'and',\n colorize('INTLAYER_CLIENT_SECRET', ANSIColors.GREY_LIGHT),\n 'in your .env file',\n colorize('(see doc:', ANSIColors.GREY_DARK),\n colorize('https://intlayer.org/doc/concept/cms', ANSIColors.GREY),\n colorize(')', ANSIColors.GREY_DARK),\n '.',\n ],\n { level: 'error' }\n );\n\n return false;\n }\n\n const intlayerAPI = getIntlayerAPIProxy(undefined, configuration);\n\n try {\n const result = await intlayerAPI.oAuth.getOAuth2AccessToken();\n\n const project = result.data?.project;\n\n if (!project) {\n appLogger('Project not found');\n return true;\n }\n\n if (shouldCheckConfigConsistency) {\n checkProjectConfigConsistency(project, configuration, appLogger);\n }\n } catch (error) {\n const message = extractErrorMessage(error);\n appLogger(message, { level: 'error' });\n return false;\n }\n\n return true;\n};\n\nexport const checkAIAccess = async (\n configuration: IntlayerConfig,\n aiOptions?: AIOptions,\n shouldCheckConfigConsistency: boolean = true\n): Promise<boolean> => {\n const appLogger = getAppLogger(configuration);\n\n const hasCMSAuth = Boolean(\n configuration.editor.clientId && configuration.editor.clientSecret\n );\n\n const sessionData = await readCliSessionToken(configuration);\n const hasSessionToken = Boolean(sessionData);\n const isOllama =\n configuration.ai?.provider === 'ollama' || aiOptions?.provider === 'ollama';\n const hasHisOwnAIAPIKey = Boolean(\n configuration.ai?.apiKey || aiOptions?.apiKey\n );\n\n if (hasHisOwnAIAPIKey || isOllama) {\n return true;\n }\n\n // User need to provide either his own AI API key or the CMS auth\n if (!hasCMSAuth && !hasSessionToken) {\n appLogger(\n [\n 'AI options or API key not provided. Run',\n colorize('npx intlayer login', ANSIColors.CYAN),\n 'to authenticate, or provide an API key',\n colorize('(see doc:', ANSIColors.GREY_DARK),\n colorize(\n 'https://intlayer.org/doc/concept/configuration',\n ANSIColors.GREY\n ),\n colorize(')', ANSIColors.GREY_DARK),\n '.',\n ],\n { level: 'error' }\n );\n\n return false;\n }\n\n // If the user do not have his own AI API key, we need to check the CMS auth\n return await checkCMSAuth(configuration, shouldCheckConfigConsistency);\n};\n"],"mappings":";;;;;;;;;;;AASA,MAAM,iCACJ,SACA,eACA,cACS;CACT,IAAI,CAAC,SAAS,eAAe;CAE7B,IAAI;EACF,IAAI,sBAAsB,QAAQ;EAElC,IACE,oBAAoB,MACpB,sBAAsB,oBAAoB,IAC1C;GACA,MAAM,EAAE,kBAAkB,GAAG,WAAW,oBAAoB;GAC5D,sBAAsB;IAAE,GAAG;IAAqB,IAAI;IAAQ;;EAG9D,4DAAuB,qBAAqB,cAAc;SACpD;EACN,UACE;GACE;GACA;yCACS,mCAAmCA,wBAAW,KAAK;yCACnD,aAAaA,wBAAW,UAAU;yCAClC,6CAA6CA,wBAAW,KAAK;yCAC7D,KAAKA,wBAAW,UAAU;GACnC;GACD,EACD,EAAE,OAAO,QAAQ,CAClB;;;AAIL,MAAa,eAAe,OAC1B,eACA,+BAAwC,SACnB;CACrB,MAAM,sDAAyB,cAAc;CAG7C,MAAM,cAAc,MAAMC,8CAAoB,cAAc;CAC5D,IAAI,aAAa;EACf,MAAM,qDACJ,QACA,eACA,YAAY,MACb;EAED,IAAI;GAEF,MAAM,WAAU,MADK,YAAY,MAAM,iBAAiB,EACjC,MAAM;GAE7B,IAAI,WAAW,8BACb,8BAA8B,SAAS,eAAe,UAAU;GAGlE,OAAO;WACA,OAAO;GAEd,0DADoC,MACnB,EAAE,EAAE,OAAO,SAAS,CAAC;GACtC,OAAO;;;CAOX,IAAI,EADF,cAAc,OAAO,YAAY,cAAc,OAAO,eACvC;EACf,UACE;GACE;yCACS,sBAAsBD,wBAAW,KAAK;GAC/C;yCACS,sBAAsBA,wBAAW,WAAW;GACrD;yCACS,0BAA0BA,wBAAW,WAAW;GACzD;yCACS,aAAaA,wBAAW,UAAU;yCAClC,wCAAwCA,wBAAW,KAAK;yCACxD,KAAKA,wBAAW,UAAU;GACnC;GACD,EACD,EAAE,OAAO,SAAS,CACnB;EAED,OAAO;;CAGT,MAAM,qDAAkC,QAAW,cAAc;CAEjE,IAAI;EAGF,MAAM,WAAU,MAFK,YAAY,MAAM,sBAAsB,EAEtC,MAAM;EAE7B,IAAI,CAAC,SAAS;GACZ,UAAU,oBAAoB;GAC9B,OAAO;;EAGT,IAAI,8BACF,8BAA8B,SAAS,eAAe,UAAU;UAE3D,OAAO;EAEd,0DADoC,MACnB,EAAE,EAAE,OAAO,SAAS,CAAC;EACtC,OAAO;;CAGT,OAAO;;AAGT,MAAa,gBAAgB,OAC3B,eACA,WACA,+BAAwC,SACnB;CACrB,MAAM,sDAAyB,cAAc;CAE7C,MAAM,aAAa,QACjB,cAAc,OAAO,YAAY,cAAc,OAAO,aACvD;CAED,MAAM,cAAc,MAAMC,8CAAoB,cAAc;CAC5D,MAAM,kBAAkB,QAAQ,YAAY;CAC5C,MAAM,WACJ,cAAc,IAAI,aAAa,YAAY,WAAW,aAAa;CAKrE,IAJ0B,QACxB,cAAc,IAAI,UAAU,WAAW,OAGpB,IAAI,UACvB,OAAO;CAIT,IAAI,CAAC,cAAc,CAAC,iBAAiB;EACnC,UACE;GACE;yCACS,sBAAsBD,wBAAW,KAAK;GAC/C;yCACS,aAAaA,wBAAW,UAAU;yCAEzC,kDACAA,wBAAW,KACZ;yCACQ,KAAKA,wBAAW,UAAU;GACnC;GACD,EACD,EAAE,OAAO,SAAS,CACnB;EAED,OAAO;;CAIT,OAAO,MAAM,aAAa,eAAe,6BAA6B"}
|
package/dist/esm/auth/login.mjs
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { openBrowser } from "../utils/openBrowser.mjs";
|
|
2
|
+
import { writeCliSessionToken } from "./sessionToken.mjs";
|
|
2
3
|
import { logConfigDetails } from "@intlayer/chokidar/cli";
|
|
3
4
|
import * as ANSIColors from "@intlayer/config/colors";
|
|
4
5
|
import { colorize, colorizePath, getAppLogger } from "@intlayer/config/logger";
|
|
@@ -7,13 +8,65 @@ import http from "node:http";
|
|
|
7
8
|
import { URL } from "node:url";
|
|
8
9
|
|
|
9
10
|
//#region src/auth/login.ts
|
|
11
|
+
const buildSuccessHtml = (message) => `
|
|
12
|
+
<!DOCTYPE html>
|
|
13
|
+
<html lang="en" data-theme="dark">
|
|
14
|
+
<head>
|
|
15
|
+
<meta charset="UTF-8">
|
|
16
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
17
|
+
<title>Intlayer CLI Login</title>
|
|
18
|
+
<style>
|
|
19
|
+
:root {
|
|
20
|
+
--color-background: rgba(23, 23, 23);
|
|
21
|
+
--color-card: rgba(39, 39, 39);
|
|
22
|
+
--color-text: rgba(255, 245, 237);
|
|
23
|
+
--color-neutral: rgba(93, 93, 93);
|
|
24
|
+
--font-sans: "Inter", -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;
|
|
25
|
+
}
|
|
26
|
+
* { box-sizing: border-box; }
|
|
27
|
+
body {
|
|
28
|
+
font-family: var(--font-sans);
|
|
29
|
+
display: flex;
|
|
30
|
+
align-items: center;
|
|
31
|
+
justify-content: center;
|
|
32
|
+
min-height: 100vh;
|
|
33
|
+
margin: 0;
|
|
34
|
+
padding: 1rem;
|
|
35
|
+
background-color: var(--color-background);
|
|
36
|
+
color: var(--color-text);
|
|
37
|
+
}
|
|
38
|
+
.container {
|
|
39
|
+
text-align: center;
|
|
40
|
+
padding: 2rem;
|
|
41
|
+
border-radius: 1rem;
|
|
42
|
+
background-color: var(--color-card);
|
|
43
|
+
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
|
|
44
|
+
max-width: 400px;
|
|
45
|
+
width: 100%;
|
|
46
|
+
}
|
|
47
|
+
h1 { margin: 0 0 1rem 0; font-size: 1.5rem; font-weight: 700; color: var(--color-text); }
|
|
48
|
+
p { color: var(--color-neutral); font-size: 0.8rem; margin: 0 0 1.5rem 0; line-height: 1.5; }
|
|
49
|
+
</style>
|
|
50
|
+
</head>
|
|
51
|
+
<body>
|
|
52
|
+
<div class="container">
|
|
53
|
+
<h1>Login Successful</h1>
|
|
54
|
+
<p>${message}</p>
|
|
55
|
+
</div>
|
|
56
|
+
<script>
|
|
57
|
+
window.close();
|
|
58
|
+
setTimeout(() => { window.close(); }, 1000);
|
|
59
|
+
<\/script>
|
|
60
|
+
</body>
|
|
61
|
+
</html>
|
|
62
|
+
`;
|
|
10
63
|
const login = async (options) => {
|
|
11
64
|
const configuration = getConfiguration(options.configOptions);
|
|
12
65
|
logConfigDetails(options?.configOptions);
|
|
13
66
|
const logger = getAppLogger(configuration);
|
|
14
67
|
const cmsUrl = options.cmsUrl ?? configuration.editor.cmsURL;
|
|
15
68
|
return new Promise((resolve) => {
|
|
16
|
-
const server = http.createServer((req, res) => {
|
|
69
|
+
const server = http.createServer(async (req, res) => {
|
|
17
70
|
const url = new URL(req.url ?? "", `http://${req.headers.host}`);
|
|
18
71
|
res.setHeader("Access-Control-Allow-Origin", "*");
|
|
19
72
|
res.setHeader("Access-Control-Allow-Methods", "GET, OPTIONS");
|
|
@@ -24,8 +77,24 @@ const login = async (options) => {
|
|
|
24
77
|
return;
|
|
25
78
|
}
|
|
26
79
|
if (url.pathname === "/callback") {
|
|
80
|
+
const sessionToken = url.searchParams.get("sessionToken");
|
|
81
|
+
const sessionExpiresAt = url.searchParams.get("expiresAt");
|
|
27
82
|
const clientId = url.searchParams.get("clientId");
|
|
28
83
|
const clientSecret = url.searchParams.get("clientSecret");
|
|
84
|
+
if (sessionToken && sessionExpiresAt) {
|
|
85
|
+
logger("");
|
|
86
|
+
logger(`Log in successful. ${colorize("2h", ANSIColors.BLUE)} session token received.`);
|
|
87
|
+
logger("");
|
|
88
|
+
logger(colorize(`Token expires at: ${new Date(sessionExpiresAt).toLocaleString()}`, ANSIColors.GREY));
|
|
89
|
+
await writeCliSessionToken(configuration, sessionToken, new Date(sessionExpiresAt));
|
|
90
|
+
res.writeHead(200, { "Content-Type": "text/html" });
|
|
91
|
+
res.end(buildSuccessHtml("Your 2h session token has been stored. You can now close this tab and return to your terminal."));
|
|
92
|
+
server.close(() => {
|
|
93
|
+
resolve();
|
|
94
|
+
process.exit(0);
|
|
95
|
+
});
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
29
98
|
if (clientId && clientSecret) {
|
|
30
99
|
logger("");
|
|
31
100
|
logger("Log in successful. Client ID and Client Secret received.");
|
|
@@ -56,80 +125,7 @@ const login = async (options) => {
|
|
|
56
125
|
});
|
|
57
126
|
logger(colorize("--------------------------------", ANSIColors.GREY_DARK));
|
|
58
127
|
res.writeHead(200, { "Content-Type": "text/html" });
|
|
59
|
-
res.end(
|
|
60
|
-
<!DOCTYPE html>
|
|
61
|
-
<html lang="en" data-theme="dark">
|
|
62
|
-
<head>
|
|
63
|
-
<meta charset="UTF-8">
|
|
64
|
-
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
65
|
-
<title>Intlayer CLI Login</title>
|
|
66
|
-
<style>
|
|
67
|
-
:root {
|
|
68
|
-
--color-background: rgba(23, 23, 23);
|
|
69
|
-
--color-card: rgba(39, 39, 39);
|
|
70
|
-
--color-text: rgba(255, 245, 237);
|
|
71
|
-
--color-neutral: rgba(93, 93, 93);
|
|
72
|
-
--font-sans: "Inter", -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
* {
|
|
76
|
-
box-sizing: border-box;
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
body {
|
|
80
|
-
font-family: var(--font-sans);
|
|
81
|
-
display: flex;
|
|
82
|
-
align-items: center;
|
|
83
|
-
justify-content: center;
|
|
84
|
-
min-height: 100vh;
|
|
85
|
-
margin: 0;
|
|
86
|
-
padding: 1rem;
|
|
87
|
-
background-color: var(--color-background);
|
|
88
|
-
color: var(--color-text);
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
.container {
|
|
92
|
-
text-align: center;
|
|
93
|
-
padding: 2rem;
|
|
94
|
-
border-radius: 1rem;
|
|
95
|
-
background-color: var(--color-card);
|
|
96
|
-
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
|
|
97
|
-
max-width: 400px;
|
|
98
|
-
width: 100%;
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
h1 {
|
|
102
|
-
margin: 0 0 1rem 0;
|
|
103
|
-
font-size: 1.5rem;
|
|
104
|
-
font-weight: 700;
|
|
105
|
-
color: var(--color-text);
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
p {
|
|
109
|
-
color: var(--color-neutral);
|
|
110
|
-
font-size: 0.8rem;
|
|
111
|
-
margin: 0 0 1.5rem 0;
|
|
112
|
-
line-height: 1.5;
|
|
113
|
-
}
|
|
114
|
-
</style>
|
|
115
|
-
</head>
|
|
116
|
-
<body>
|
|
117
|
-
<div class="container">
|
|
118
|
-
<h1>Login Successful</h1>
|
|
119
|
-
<p>You have successfully logged in to Intlayer CLI. You can now close this tab and return to your terminal.</p>
|
|
120
|
-
</div>
|
|
121
|
-
<script>
|
|
122
|
-
// Attempt to close the window
|
|
123
|
-
window.close();
|
|
124
|
-
|
|
125
|
-
// Fallback: if window.close() doesn't work, show a message
|
|
126
|
-
setTimeout(() => {
|
|
127
|
-
window.close();
|
|
128
|
-
}, 1000);
|
|
129
|
-
<\/script>
|
|
130
|
-
</body>
|
|
131
|
-
</html>
|
|
132
|
-
`);
|
|
128
|
+
res.end(buildSuccessHtml("You have successfully logged in to Intlayer CLI. You can now close this tab and return to your terminal."));
|
|
133
129
|
server.close(() => {
|
|
134
130
|
resolve();
|
|
135
131
|
process.exit(0);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"login.mjs","names":[],"sources":["../../../src/auth/login.ts"],"sourcesContent":["import http from 'node:http';\nimport { URL } from 'node:url';\nimport { logConfigDetails } from '@intlayer/chokidar/cli';\nimport * as ANSIColors from '@intlayer/config/colors';\nimport { colorize, colorizePath, getAppLogger } from '@intlayer/config/logger';\nimport {\n type GetConfigurationOptions,\n getConfiguration,\n} from '@intlayer/config/node';\nimport { openBrowser } from '../utils/openBrowser';\n\ntype LoginOptions = {\n cmsUrl?: string;\n configOptions?: GetConfigurationOptions;\n};\n\nexport const login = async (options: LoginOptions) => {\n const configuration = getConfiguration(options.configOptions);\n logConfigDetails(options?.configOptions);\n\n const logger = getAppLogger(configuration);\n\n const cmsUrl = options.cmsUrl ?? configuration.editor.cmsURL;\n\n return new Promise<void>((resolve) => {\n const server = http.createServer((req, res) => {\n const url = new URL(req.url ?? '', `http://${req.headers.host}`);\n\n // Set CORS headers\n res.setHeader('Access-Control-Allow-Origin', '*');\n res.setHeader('Access-Control-Allow-Methods', 'GET, OPTIONS');\n res.setHeader('Access-Control-Allow-Headers', 'Content-Type');\n\n if (req.method === 'OPTIONS') {\n res.writeHead(204);\n res.end();\n return;\n }\n\n if (url.pathname === '/callback') {\n const clientId = url.searchParams.get('clientId');\n const clientSecret = url.searchParams.get('clientSecret');\n\n if (clientId && clientSecret) {\n logger('');\n logger('Log in successful. Client ID and Client Secret received.');\n\n logger('');\n logger([\n '1. Insert the Client ID and Client Secret in your',\n colorizePath('.env'),\n 'file:',\n ]);\n logger(\n colorize('--------------------------------', ANSIColors.GREY_DARK)\n );\n logger(\n [\n colorize('INTLAYER_CLIENT_ID=', ANSIColors.GREY_LIGHT),\n colorize(clientId, ANSIColors.BLUE),\n ].join('')\n );\n logger(\n [\n colorize('INTLAYER_CLIENT_SECRET=', ANSIColors.GREY_LIGHT),\n colorize(clientSecret, ANSIColors.BLUE),\n ].join('')\n );\n logger(\n colorize('--------------------------------', ANSIColors.GREY_DARK)\n );\n logger('');\n logger('2. Insert in your Intlayer configuration file:');\n logger(\n colorize('--------------------------------', ANSIColors.GREY_DARK)\n );\n [\n `${ANSIColors.GREY_LIGHT}{`,\n ` editor: {`,\n ` enabled: true,`,\n ` cmsURL: '${colorizePath(cmsUrl!, undefined, ANSIColors.GREY_LIGHT)}',`,\n ` clientId: '${colorize('process.env.INTLAYER_CLIENT_ID', ANSIColors.BLUE, ANSIColors.GREY_LIGHT)}',`,\n ` clientSecret: '${colorize('process.env.INTLAYER_CLIENT_SECRET', ANSIColors.BLUE, ANSIColors.GREY_LIGHT)}',`,\n ` },`,\n `}`,\n ].forEach((line) => {\n logger(line);\n });\n logger(\n colorize('--------------------------------', ANSIColors.GREY_DARK)\n );\n\n res.writeHead(200, { 'Content-Type': 'text/html' });\n res.end(
|
|
1
|
+
{"version":3,"file":"login.mjs","names":[],"sources":["../../../src/auth/login.ts"],"sourcesContent":["import http from 'node:http';\nimport { relative } from 'node:path';\nimport { URL } from 'node:url';\nimport { logConfigDetails } from '@intlayer/chokidar/cli';\nimport * as ANSIColors from '@intlayer/config/colors';\nimport { colorize, colorizePath, getAppLogger } from '@intlayer/config/logger';\nimport {\n type GetConfigurationOptions,\n getConfiguration,\n} from '@intlayer/config/node';\nimport { openBrowser } from '../utils/openBrowser';\nimport { writeCliSessionToken } from './sessionToken';\n\nconst buildSuccessHtml = (message: string): string => `\n <!DOCTYPE html>\n <html lang=\"en\" data-theme=\"dark\">\n <head>\n <meta charset=\"UTF-8\">\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n <title>Intlayer CLI Login</title>\n <style>\n :root {\n --color-background: rgba(23, 23, 23);\n --color-card: rgba(39, 39, 39);\n --color-text: rgba(255, 245, 237);\n --color-neutral: rgba(93, 93, 93);\n --font-sans: \"Inter\", -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;\n }\n * { box-sizing: border-box; }\n body {\n font-family: var(--font-sans);\n display: flex;\n align-items: center;\n justify-content: center;\n min-height: 100vh;\n margin: 0;\n padding: 1rem;\n background-color: var(--color-background);\n color: var(--color-text);\n }\n .container {\n text-align: center;\n padding: 2rem;\n border-radius: 1rem;\n background-color: var(--color-card);\n box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);\n max-width: 400px;\n width: 100%;\n }\n h1 { margin: 0 0 1rem 0; font-size: 1.5rem; font-weight: 700; color: var(--color-text); }\n p { color: var(--color-neutral); font-size: 0.8rem; margin: 0 0 1.5rem 0; line-height: 1.5; }\n </style>\n </head>\n <body>\n <div class=\"container\">\n <h1>Login Successful</h1>\n <p>${message}</p>\n </div>\n <script>\n window.close();\n setTimeout(() => { window.close(); }, 1000);\n </script>\n </body>\n </html>\n`;\n\ntype LoginOptions = {\n cmsUrl?: string;\n configOptions?: GetConfigurationOptions;\n};\n\nexport const login = async (options: LoginOptions) => {\n const configuration = getConfiguration(options.configOptions);\n logConfigDetails(options?.configOptions);\n\n const logger = getAppLogger(configuration);\n\n const cmsUrl = options.cmsUrl ?? configuration.editor.cmsURL;\n\n return new Promise<void>((resolve) => {\n const server = http.createServer(async (req, res) => {\n const url = new URL(req.url ?? '', `http://${req.headers.host}`);\n\n // Set CORS headers\n res.setHeader('Access-Control-Allow-Origin', '*');\n res.setHeader('Access-Control-Allow-Methods', 'GET, OPTIONS');\n res.setHeader('Access-Control-Allow-Headers', 'Content-Type');\n\n if (req.method === 'OPTIONS') {\n res.writeHead(204);\n res.end();\n return;\n }\n\n if (url.pathname === '/callback') {\n const sessionToken = url.searchParams.get('sessionToken');\n const sessionExpiresAt = url.searchParams.get('expiresAt');\n const clientId = url.searchParams.get('clientId');\n const clientSecret = url.searchParams.get('clientSecret');\n\n if (sessionToken && sessionExpiresAt) {\n logger('');\n logger(\n `Log in successful. ${colorize('2h', ANSIColors.BLUE)} session token received.`\n );\n logger('');\n\n logger(\n colorize(\n `Token expires at: ${new Date(sessionExpiresAt).toLocaleString()}`,\n ANSIColors.GREY\n )\n );\n\n await writeCliSessionToken(\n configuration,\n sessionToken,\n new Date(sessionExpiresAt)\n );\n\n res.writeHead(200, { 'Content-Type': 'text/html' });\n res.end(\n buildSuccessHtml(\n 'Your 2h session token has been stored. You can now close this tab and return to your terminal.'\n )\n );\n\n server.close(() => {\n resolve();\n process.exit(0);\n });\n return;\n }\n\n if (clientId && clientSecret) {\n logger('');\n logger('Log in successful. Client ID and Client Secret received.');\n\n logger('');\n logger([\n '1. Insert the Client ID and Client Secret in your',\n colorizePath('.env'),\n 'file:',\n ]);\n logger(\n colorize('--------------------------------', ANSIColors.GREY_DARK)\n );\n logger(\n [\n colorize('INTLAYER_CLIENT_ID=', ANSIColors.GREY_LIGHT),\n colorize(clientId, ANSIColors.BLUE),\n ].join('')\n );\n logger(\n [\n colorize('INTLAYER_CLIENT_SECRET=', ANSIColors.GREY_LIGHT),\n colorize(clientSecret, ANSIColors.BLUE),\n ].join('')\n );\n logger(\n colorize('--------------------------------', ANSIColors.GREY_DARK)\n );\n logger('');\n logger('2. Insert in your Intlayer configuration file:');\n logger(\n colorize('--------------------------------', ANSIColors.GREY_DARK)\n );\n [\n `${ANSIColors.GREY_LIGHT}{`,\n ` editor: {`,\n ` enabled: true,`,\n ` cmsURL: '${colorizePath(cmsUrl!, undefined, ANSIColors.GREY_LIGHT)}',`,\n ` clientId: '${colorize('process.env.INTLAYER_CLIENT_ID', ANSIColors.BLUE, ANSIColors.GREY_LIGHT)}',`,\n ` clientSecret: '${colorize('process.env.INTLAYER_CLIENT_SECRET', ANSIColors.BLUE, ANSIColors.GREY_LIGHT)}',`,\n ` },`,\n `}`,\n ].forEach((line) => {\n logger(line);\n });\n logger(\n colorize('--------------------------------', ANSIColors.GREY_DARK)\n );\n\n res.writeHead(200, { 'Content-Type': 'text/html' });\n res.end(\n buildSuccessHtml(\n 'You have successfully logged in to Intlayer CLI. You can now close this tab and return to your terminal.'\n )\n );\n\n server.close(() => {\n resolve();\n process.exit(0);\n });\n } else {\n res.writeHead(400, { 'Content-Type': 'text/plain' });\n res.end('Missing parameters');\n }\n } else {\n res.writeHead(404, { 'Content-Type': 'text/plain' });\n res.end('Not found');\n }\n });\n\n server.listen(0, () => {\n const address = server.address();\n const port = typeof address === 'object' && address ? address.port : 0;\n const state = Math.random().toString(36).substring(7);\n\n const websiteUrl =\n cmsUrl ?? process.env.INTLAYER_SITE_URL ?? 'http://localhost:3000';\n const loginUrl = `${websiteUrl}/auth/cli-login?port=${port}&state=${state}`;\n\n logger('Opening browser for login...');\n logger(`If browser does not open, visit: ${colorizePath(loginUrl)}`);\n\n openBrowser(loginUrl);\n });\n });\n};\n"],"mappings":"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"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { join } from "node:path";
|
|
2
|
+
import { mkdir, readFile, unlink, writeFile } from "node:fs/promises";
|
|
3
|
+
|
|
4
|
+
//#region src/auth/sessionToken.ts
|
|
5
|
+
const SESSION_FILE_NAME = "cli-session.json";
|
|
6
|
+
const getSessionFilePath = (config) => join(config.system.tempDir, SESSION_FILE_NAME);
|
|
7
|
+
const writeCliSessionToken = async (config, token, expiresAt) => {
|
|
8
|
+
const filePath = getSessionFilePath(config);
|
|
9
|
+
await mkdir(config.system.tempDir, { recursive: true });
|
|
10
|
+
const data = {
|
|
11
|
+
token,
|
|
12
|
+
expiresAt: expiresAt.toISOString()
|
|
13
|
+
};
|
|
14
|
+
await writeFile(filePath, JSON.stringify(data, null, 2), { mode: 384 });
|
|
15
|
+
};
|
|
16
|
+
const readCliSessionToken = async (config) => {
|
|
17
|
+
const filePath = getSessionFilePath(config);
|
|
18
|
+
try {
|
|
19
|
+
const raw = await readFile(filePath, "utf8");
|
|
20
|
+
const data = JSON.parse(raw);
|
|
21
|
+
if (!data.token || !data.expiresAt) return null;
|
|
22
|
+
if (/* @__PURE__ */ new Date() >= new Date(data.expiresAt)) {
|
|
23
|
+
await clearCliSessionToken(config);
|
|
24
|
+
return null;
|
|
25
|
+
}
|
|
26
|
+
return data;
|
|
27
|
+
} catch {
|
|
28
|
+
return null;
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
const clearCliSessionToken = async (config) => {
|
|
32
|
+
try {
|
|
33
|
+
await unlink(getSessionFilePath(config));
|
|
34
|
+
} catch {}
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
//#endregion
|
|
38
|
+
export { clearCliSessionToken, readCliSessionToken, writeCliSessionToken };
|
|
39
|
+
//# sourceMappingURL=sessionToken.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sessionToken.mjs","names":[],"sources":["../../../src/auth/sessionToken.ts"],"sourcesContent":["import { mkdir, readFile, unlink, writeFile } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport type { IntlayerConfig } from '@intlayer/types/config';\n\nconst SESSION_FILE_NAME = 'cli-session.json';\n\ntype CliSessionData = {\n token: string;\n expiresAt: string; // ISO date string\n};\n\nconst getSessionFilePath = (config: IntlayerConfig): string =>\n join(config.system.tempDir, SESSION_FILE_NAME);\n\nexport const writeCliSessionToken = async (\n config: IntlayerConfig,\n token: string,\n expiresAt: Date\n): Promise<void> => {\n const filePath = getSessionFilePath(config);\n\n await mkdir(config.system.tempDir, { recursive: true });\n\n const data: CliSessionData = { token, expiresAt: expiresAt.toISOString() };\n await writeFile(filePath, JSON.stringify(data, null, 2), { mode: 0o600 });\n};\n\nexport const readCliSessionToken = async (\n config: IntlayerConfig\n): Promise<CliSessionData | null> => {\n const filePath = getSessionFilePath(config);\n\n try {\n const raw = await readFile(filePath, 'utf8');\n const data: CliSessionData = JSON.parse(raw);\n\n if (!data.token || !data.expiresAt) {\n return null;\n }\n\n if (new Date() >= new Date(data.expiresAt)) {\n await clearCliSessionToken(config);\n return null;\n }\n\n return data;\n } catch {\n return null;\n }\n};\n\nexport const clearCliSessionToken = async (\n config: IntlayerConfig\n): Promise<void> => {\n try {\n await unlink(getSessionFilePath(config));\n } catch {\n // Ignore errors (file may not exist)\n }\n};\n"],"mappings":";;;;AAIA,MAAM,oBAAoB;AAO1B,MAAM,sBAAsB,WAC1B,KAAK,OAAO,OAAO,SAAS,kBAAkB;AAEhD,MAAa,uBAAuB,OAClC,QACA,OACA,cACkB;CAClB,MAAM,WAAW,mBAAmB,OAAO;CAE3C,MAAM,MAAM,OAAO,OAAO,SAAS,EAAE,WAAW,MAAM,CAAC;CAEvD,MAAM,OAAuB;EAAE;EAAO,WAAW,UAAU,aAAa;EAAE;CAC1E,MAAM,UAAU,UAAU,KAAK,UAAU,MAAM,MAAM,EAAE,EAAE,EAAE,MAAM,KAAO,CAAC;;AAG3E,MAAa,sBAAsB,OACjC,WACmC;CACnC,MAAM,WAAW,mBAAmB,OAAO;CAE3C,IAAI;EACF,MAAM,MAAM,MAAM,SAAS,UAAU,OAAO;EAC5C,MAAM,OAAuB,KAAK,MAAM,IAAI;EAE5C,IAAI,CAAC,KAAK,SAAS,CAAC,KAAK,WACvB,OAAO;EAGT,oBAAI,IAAI,MAAM,IAAI,IAAI,KAAK,KAAK,UAAU,EAAE;GAC1C,MAAM,qBAAqB,OAAO;GAClC,OAAO;;EAGT,OAAO;SACD;EACN,OAAO;;;AAIX,MAAa,uBAAuB,OAClC,WACkB;CAClB,IAAI;EACF,MAAM,OAAO,mBAAmB,OAAO,CAAC;SAClC"}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { readCliSessionToken } from "../auth/sessionToken.mjs";
|
|
1
2
|
import { checkConfigConsistency } from "./checkConfigConsistency.mjs";
|
|
2
3
|
import * as ANSIColors from "@intlayer/config/colors";
|
|
3
4
|
import { colorize, getAppLogger } from "@intlayer/config/logger";
|
|
@@ -5,12 +6,53 @@ import { getIntlayerAPIProxy } from "@intlayer/api";
|
|
|
5
6
|
import { extractErrorMessage } from "@intlayer/config/utils";
|
|
6
7
|
|
|
7
8
|
//#region src/utils/checkAccess.ts
|
|
9
|
+
const checkProjectConfigConsistency = (project, configuration, appLogger) => {
|
|
10
|
+
if (!project?.configuration) return;
|
|
11
|
+
try {
|
|
12
|
+
let remoteConfigToCheck = project.configuration;
|
|
13
|
+
if (remoteConfigToCheck.ai && "apiKeyConfigured" in remoteConfigToCheck.ai) {
|
|
14
|
+
const { apiKeyConfigured, ...restAi } = remoteConfigToCheck.ai;
|
|
15
|
+
remoteConfigToCheck = {
|
|
16
|
+
...remoteConfigToCheck,
|
|
17
|
+
ai: restAi
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
checkConfigConsistency(remoteConfigToCheck, configuration);
|
|
21
|
+
} catch {
|
|
22
|
+
appLogger([
|
|
23
|
+
"Remote configuration is not up to date. The project configuration does not match the local configuration.",
|
|
24
|
+
"You can push the configuration by running",
|
|
25
|
+
colorize("npx intlayer configuration push", ANSIColors.CYAN),
|
|
26
|
+
colorize("(see doc:", ANSIColors.GREY_DARK),
|
|
27
|
+
colorize("https://intlayer.org/doc/concept/cli/push", ANSIColors.GREY),
|
|
28
|
+
colorize(")", ANSIColors.GREY_DARK),
|
|
29
|
+
"."
|
|
30
|
+
], { level: "warn" });
|
|
31
|
+
}
|
|
32
|
+
};
|
|
8
33
|
const checkCMSAuth = async (configuration, shouldCheckConfigConsistency = true) => {
|
|
9
34
|
const appLogger = getAppLogger(configuration);
|
|
35
|
+
const sessionData = await readCliSessionToken(configuration);
|
|
36
|
+
if (sessionData) {
|
|
37
|
+
const intlayerAPI = getIntlayerAPIProxy(void 0, configuration, sessionData.token);
|
|
38
|
+
try {
|
|
39
|
+
const project = (await intlayerAPI.oAuth.getCliSessionMe()).data?.project;
|
|
40
|
+
if (project && shouldCheckConfigConsistency) checkProjectConfigConsistency(project, configuration, appLogger);
|
|
41
|
+
return true;
|
|
42
|
+
} catch (error) {
|
|
43
|
+
appLogger(extractErrorMessage(error), { level: "error" });
|
|
44
|
+
return false;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
10
47
|
if (!(configuration.editor.clientId && configuration.editor.clientSecret)) {
|
|
11
48
|
appLogger([
|
|
12
|
-
"CMS auth not provided.
|
|
13
|
-
colorize("
|
|
49
|
+
"CMS auth not provided. Run",
|
|
50
|
+
colorize("npx intlayer login", ANSIColors.CYAN),
|
|
51
|
+
"to authenticate, or set",
|
|
52
|
+
colorize("INTLAYER_CLIENT_ID", ANSIColors.GREY_LIGHT),
|
|
53
|
+
"and",
|
|
54
|
+
colorize("INTLAYER_CLIENT_SECRET", ANSIColors.GREY_LIGHT),
|
|
55
|
+
"in your .env file",
|
|
14
56
|
colorize("(see doc:", ANSIColors.GREY_DARK),
|
|
15
57
|
colorize("https://intlayer.org/doc/concept/cms", ANSIColors.GREY),
|
|
16
58
|
colorize(")", ANSIColors.GREY_DARK),
|
|
@@ -25,27 +67,7 @@ const checkCMSAuth = async (configuration, shouldCheckConfigConsistency = true)
|
|
|
25
67
|
appLogger("Project not found");
|
|
26
68
|
return true;
|
|
27
69
|
}
|
|
28
|
-
if (project
|
|
29
|
-
let remoteConfigToCheck = project.configuration;
|
|
30
|
-
if (remoteConfigToCheck.ai && "apiKeyConfigured" in remoteConfigToCheck.ai) {
|
|
31
|
-
const { apiKeyConfigured, ...restAi } = remoteConfigToCheck.ai;
|
|
32
|
-
remoteConfigToCheck = {
|
|
33
|
-
...remoteConfigToCheck,
|
|
34
|
-
ai: restAi
|
|
35
|
-
};
|
|
36
|
-
}
|
|
37
|
-
checkConfigConsistency(remoteConfigToCheck, configuration);
|
|
38
|
-
} catch {
|
|
39
|
-
appLogger([
|
|
40
|
-
"Remote configuration is not up to date. The project configuration does not match the local configuration.",
|
|
41
|
-
"You can push the configuration by running",
|
|
42
|
-
colorize("npx intlayer configuration push", ANSIColors.CYAN),
|
|
43
|
-
colorize("(see doc:", ANSIColors.GREY_DARK),
|
|
44
|
-
colorize("https://intlayer.org/doc/concept/cli/push", ANSIColors.GREY),
|
|
45
|
-
colorize(")", ANSIColors.GREY_DARK),
|
|
46
|
-
"."
|
|
47
|
-
], { level: "warn" });
|
|
48
|
-
}
|
|
70
|
+
if (shouldCheckConfigConsistency) checkProjectConfigConsistency(project, configuration, appLogger);
|
|
49
71
|
} catch (error) {
|
|
50
72
|
appLogger(extractErrorMessage(error), { level: "error" });
|
|
51
73
|
return false;
|
|
@@ -55,16 +77,15 @@ const checkCMSAuth = async (configuration, shouldCheckConfigConsistency = true)
|
|
|
55
77
|
const checkAIAccess = async (configuration, aiOptions, shouldCheckConfigConsistency = true) => {
|
|
56
78
|
const appLogger = getAppLogger(configuration);
|
|
57
79
|
const hasCMSAuth = Boolean(configuration.editor.clientId && configuration.editor.clientSecret);
|
|
80
|
+
const sessionData = await readCliSessionToken(configuration);
|
|
81
|
+
const hasSessionToken = Boolean(sessionData);
|
|
58
82
|
const isOllama = configuration.ai?.provider === "ollama" || aiOptions?.provider === "ollama";
|
|
59
83
|
if (Boolean(configuration.ai?.apiKey || aiOptions?.apiKey) || isOllama) return true;
|
|
60
|
-
if (!hasCMSAuth) {
|
|
84
|
+
if (!hasCMSAuth && !hasSessionToken) {
|
|
61
85
|
appLogger([
|
|
62
|
-
"AI options or API key not provided.
|
|
63
|
-
colorize("
|
|
64
|
-
|
|
65
|
-
colorize("https://intlayer.org/doc/concept/cms", ANSIColors.GREY),
|
|
66
|
-
colorize(")", ANSIColors.GREY_DARK),
|
|
67
|
-
". Alternatively, you can add your own OpenAI API key in the settings",
|
|
86
|
+
"AI options or API key not provided. Run",
|
|
87
|
+
colorize("npx intlayer login", ANSIColors.CYAN),
|
|
88
|
+
"to authenticate, or provide an API key",
|
|
68
89
|
colorize("(see doc:", ANSIColors.GREY_DARK),
|
|
69
90
|
colorize("https://intlayer.org/doc/concept/configuration", ANSIColors.GREY),
|
|
70
91
|
colorize(")", ANSIColors.GREY_DARK),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"checkAccess.mjs","names":[],"sources":["../../../src/utils/checkAccess.ts"],"sourcesContent":["import type { AIOptions } from '@intlayer/api';\nimport { getIntlayerAPIProxy } from '@intlayer/api';\nimport * as ANSIColors from '@intlayer/config/colors';\nimport { colorize, getAppLogger } from '@intlayer/config/logger';\nimport { extractErrorMessage } from '@intlayer/config/utils';\nimport type { IntlayerConfig } from '@intlayer/types/config';\nimport { checkConfigConsistency } from './checkConfigConsistency';\n\
|
|
1
|
+
{"version":3,"file":"checkAccess.mjs","names":[],"sources":["../../../src/utils/checkAccess.ts"],"sourcesContent":["import type { AIOptions } from '@intlayer/api';\nimport { getIntlayerAPIProxy } from '@intlayer/api';\nimport * as ANSIColors from '@intlayer/config/colors';\nimport { colorize, getAppLogger } from '@intlayer/config/logger';\nimport { extractErrorMessage } from '@intlayer/config/utils';\nimport type { IntlayerConfig } from '@intlayer/types/config';\nimport { readCliSessionToken } from '../auth/sessionToken';\nimport { checkConfigConsistency } from './checkConfigConsistency';\n\nconst checkProjectConfigConsistency = (\n project: { configuration?: any } | null | undefined,\n configuration: IntlayerConfig,\n appLogger: ReturnType<typeof getAppLogger>\n): void => {\n if (!project?.configuration) return;\n\n try {\n let remoteConfigToCheck = project.configuration;\n\n if (\n remoteConfigToCheck.ai &&\n 'apiKeyConfigured' in remoteConfigToCheck.ai\n ) {\n const { apiKeyConfigured, ...restAi } = remoteConfigToCheck.ai as any;\n remoteConfigToCheck = { ...remoteConfigToCheck, ai: restAi };\n }\n\n checkConfigConsistency(remoteConfigToCheck, configuration);\n } catch {\n appLogger(\n [\n 'Remote configuration is not up to date. The project configuration does not match the local configuration.',\n 'You can push the configuration by running',\n colorize('npx intlayer configuration push', ANSIColors.CYAN),\n colorize('(see doc:', ANSIColors.GREY_DARK),\n colorize('https://intlayer.org/doc/concept/cli/push', ANSIColors.GREY),\n colorize(')', ANSIColors.GREY_DARK),\n '.',\n ],\n { level: 'warn' }\n );\n }\n};\n\nexport const checkCMSAuth = async (\n configuration: IntlayerConfig,\n shouldCheckConfigConsistency: boolean = true\n): Promise<boolean> => {\n const appLogger = getAppLogger(configuration);\n\n // Try CLI session token first (short-lived 2h token stored in tempDir)\n const sessionData = await readCliSessionToken(configuration);\n if (sessionData) {\n const intlayerAPI = getIntlayerAPIProxy(\n undefined,\n configuration,\n sessionData.token\n );\n\n try {\n const result = await intlayerAPI.oAuth.getCliSessionMe();\n const project = result.data?.project;\n\n if (project && shouldCheckConfigConsistency) {\n checkProjectConfigConsistency(project, configuration, appLogger);\n }\n\n return true;\n } catch (error) {\n const message = extractErrorMessage(error);\n appLogger(message, { level: 'error' });\n return false;\n }\n }\n\n // Fall back to client_credentials (access key)\n const hasCMSAuth =\n configuration.editor.clientId && configuration.editor.clientSecret;\n if (!hasCMSAuth) {\n appLogger(\n [\n 'CMS auth not provided. Run',\n colorize('npx intlayer login', ANSIColors.CYAN),\n 'to authenticate, or set',\n colorize('INTLAYER_CLIENT_ID', ANSIColors.GREY_LIGHT),\n 'and',\n colorize('INTLAYER_CLIENT_SECRET', ANSIColors.GREY_LIGHT),\n 'in your .env file',\n colorize('(see doc:', ANSIColors.GREY_DARK),\n colorize('https://intlayer.org/doc/concept/cms', ANSIColors.GREY),\n colorize(')', ANSIColors.GREY_DARK),\n '.',\n ],\n { level: 'error' }\n );\n\n return false;\n }\n\n const intlayerAPI = getIntlayerAPIProxy(undefined, configuration);\n\n try {\n const result = await intlayerAPI.oAuth.getOAuth2AccessToken();\n\n const project = result.data?.project;\n\n if (!project) {\n appLogger('Project not found');\n return true;\n }\n\n if (shouldCheckConfigConsistency) {\n checkProjectConfigConsistency(project, configuration, appLogger);\n }\n } catch (error) {\n const message = extractErrorMessage(error);\n appLogger(message, { level: 'error' });\n return false;\n }\n\n return true;\n};\n\nexport const checkAIAccess = async (\n configuration: IntlayerConfig,\n aiOptions?: AIOptions,\n shouldCheckConfigConsistency: boolean = true\n): Promise<boolean> => {\n const appLogger = getAppLogger(configuration);\n\n const hasCMSAuth = Boolean(\n configuration.editor.clientId && configuration.editor.clientSecret\n );\n\n const sessionData = await readCliSessionToken(configuration);\n const hasSessionToken = Boolean(sessionData);\n const isOllama =\n configuration.ai?.provider === 'ollama' || aiOptions?.provider === 'ollama';\n const hasHisOwnAIAPIKey = Boolean(\n configuration.ai?.apiKey || aiOptions?.apiKey\n );\n\n if (hasHisOwnAIAPIKey || isOllama) {\n return true;\n }\n\n // User need to provide either his own AI API key or the CMS auth\n if (!hasCMSAuth && !hasSessionToken) {\n appLogger(\n [\n 'AI options or API key not provided. Run',\n colorize('npx intlayer login', ANSIColors.CYAN),\n 'to authenticate, or provide an API key',\n colorize('(see doc:', ANSIColors.GREY_DARK),\n colorize(\n 'https://intlayer.org/doc/concept/configuration',\n ANSIColors.GREY\n ),\n colorize(')', ANSIColors.GREY_DARK),\n '.',\n ],\n { level: 'error' }\n );\n\n return false;\n }\n\n // If the user do not have his own AI API key, we need to check the CMS auth\n return await checkCMSAuth(configuration, shouldCheckConfigConsistency);\n};\n"],"mappings":";;;;;;;;AASA,MAAM,iCACJ,SACA,eACA,cACS;CACT,IAAI,CAAC,SAAS,eAAe;CAE7B,IAAI;EACF,IAAI,sBAAsB,QAAQ;EAElC,IACE,oBAAoB,MACpB,sBAAsB,oBAAoB,IAC1C;GACA,MAAM,EAAE,kBAAkB,GAAG,WAAW,oBAAoB;GAC5D,sBAAsB;IAAE,GAAG;IAAqB,IAAI;IAAQ;;EAG9D,uBAAuB,qBAAqB,cAAc;SACpD;EACN,UACE;GACE;GACA;GACA,SAAS,mCAAmC,WAAW,KAAK;GAC5D,SAAS,aAAa,WAAW,UAAU;GAC3C,SAAS,6CAA6C,WAAW,KAAK;GACtE,SAAS,KAAK,WAAW,UAAU;GACnC;GACD,EACD,EAAE,OAAO,QAAQ,CAClB;;;AAIL,MAAa,eAAe,OAC1B,eACA,+BAAwC,SACnB;CACrB,MAAM,YAAY,aAAa,cAAc;CAG7C,MAAM,cAAc,MAAM,oBAAoB,cAAc;CAC5D,IAAI,aAAa;EACf,MAAM,cAAc,oBAClB,QACA,eACA,YAAY,MACb;EAED,IAAI;GAEF,MAAM,WAAU,MADK,YAAY,MAAM,iBAAiB,EACjC,MAAM;GAE7B,IAAI,WAAW,8BACb,8BAA8B,SAAS,eAAe,UAAU;GAGlE,OAAO;WACA,OAAO;GAEd,UADgB,oBAAoB,MACnB,EAAE,EAAE,OAAO,SAAS,CAAC;GACtC,OAAO;;;CAOX,IAAI,EADF,cAAc,OAAO,YAAY,cAAc,OAAO,eACvC;EACf,UACE;GACE;GACA,SAAS,sBAAsB,WAAW,KAAK;GAC/C;GACA,SAAS,sBAAsB,WAAW,WAAW;GACrD;GACA,SAAS,0BAA0B,WAAW,WAAW;GACzD;GACA,SAAS,aAAa,WAAW,UAAU;GAC3C,SAAS,wCAAwC,WAAW,KAAK;GACjE,SAAS,KAAK,WAAW,UAAU;GACnC;GACD,EACD,EAAE,OAAO,SAAS,CACnB;EAED,OAAO;;CAGT,MAAM,cAAc,oBAAoB,QAAW,cAAc;CAEjE,IAAI;EAGF,MAAM,WAAU,MAFK,YAAY,MAAM,sBAAsB,EAEtC,MAAM;EAE7B,IAAI,CAAC,SAAS;GACZ,UAAU,oBAAoB;GAC9B,OAAO;;EAGT,IAAI,8BACF,8BAA8B,SAAS,eAAe,UAAU;UAE3D,OAAO;EAEd,UADgB,oBAAoB,MACnB,EAAE,EAAE,OAAO,SAAS,CAAC;EACtC,OAAO;;CAGT,OAAO;;AAGT,MAAa,gBAAgB,OAC3B,eACA,WACA,+BAAwC,SACnB;CACrB,MAAM,YAAY,aAAa,cAAc;CAE7C,MAAM,aAAa,QACjB,cAAc,OAAO,YAAY,cAAc,OAAO,aACvD;CAED,MAAM,cAAc,MAAM,oBAAoB,cAAc;CAC5D,MAAM,kBAAkB,QAAQ,YAAY;CAC5C,MAAM,WACJ,cAAc,IAAI,aAAa,YAAY,WAAW,aAAa;CAKrE,IAJ0B,QACxB,cAAc,IAAI,UAAU,WAAW,OAGpB,IAAI,UACvB,OAAO;CAIT,IAAI,CAAC,cAAc,CAAC,iBAAiB;EACnC,UACE;GACE;GACA,SAAS,sBAAsB,WAAW,KAAK;GAC/C;GACA,SAAS,aAAa,WAAW,UAAU;GAC3C,SACE,kDACA,WAAW,KACZ;GACD,SAAS,KAAK,WAAW,UAAU;GACnC;GACD,EACD,EAAE,OAAO,SAAS,CACnB;EAED,OAAO;;CAIT,OAAO,MAAM,aAAa,eAAe,6BAA6B"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"login.d.ts","names":[],"sources":["../../../src/auth/login.ts"],"mappings":";;;
|
|
1
|
+
{"version":3,"file":"login.d.ts","names":[],"sources":["../../../src/auth/login.ts"],"mappings":";;;KAkEK,YAAA;EACH,MAAA;EACA,aAAA,GAAgB,uBAAA;AAAA;AAAA,cAGL,KAAA,GAAe,OAAA,EAAS,YAAA,KAAY,OAAA"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { IntlayerConfig } from "@intlayer/types/config";
|
|
2
|
+
|
|
3
|
+
//#region src/auth/sessionToken.d.ts
|
|
4
|
+
type CliSessionData = {
|
|
5
|
+
token: string;
|
|
6
|
+
expiresAt: string;
|
|
7
|
+
};
|
|
8
|
+
declare const writeCliSessionToken: (config: IntlayerConfig, token: string, expiresAt: Date) => Promise<void>;
|
|
9
|
+
declare const readCliSessionToken: (config: IntlayerConfig) => Promise<CliSessionData | null>;
|
|
10
|
+
declare const clearCliSessionToken: (config: IntlayerConfig) => Promise<void>;
|
|
11
|
+
//#endregion
|
|
12
|
+
export { clearCliSessionToken, readCliSessionToken, writeCliSessionToken };
|
|
13
|
+
//# sourceMappingURL=sessionToken.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sessionToken.d.ts","names":[],"sources":["../../../src/auth/sessionToken.ts"],"mappings":";;;KAMK,cAAA;EACH,KAAA;EACA,SAAA;AAAA;AAAA,cAMW,oBAAA,GACX,MAAA,EAAQ,cAAA,EACR,KAAA,UACA,SAAA,EAAW,IAAA,KACV,OAAA;AAAA,cASU,mBAAA,GACX,MAAA,EAAQ,cAAA,KACP,OAAA,CAAQ,cAAA;AAAA,cAsBE,oBAAA,GACX,MAAA,EAAQ,cAAA,KACP,OAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"checkAccess.d.ts","names":[],"sources":["../../../src/utils/checkAccess.ts"],"mappings":";;;;
|
|
1
|
+
{"version":3,"file":"checkAccess.d.ts","names":[],"sources":["../../../src/utils/checkAccess.ts"],"mappings":";;;;cA4Ca,YAAA,GACX,aAAA,EAAe,cAAA,EACf,4BAAA,eACC,OAAA;AAAA,cA4EU,aAAA,GACX,aAAA,EAAe,cAAA,EACf,SAAA,GAAY,SAAA,EACZ,4BAAA,eACC,OAAA"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@intlayer/cli",
|
|
3
|
-
"version": "8.9.
|
|
3
|
+
"version": "8.9.7",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "Provides uniform command-line interface scripts for Intlayer, used in packages like intlayer-cli and intlayer.",
|
|
6
6
|
"keywords": [
|
|
@@ -67,22 +67,22 @@
|
|
|
67
67
|
},
|
|
68
68
|
"dependencies": {
|
|
69
69
|
"@clack/prompts": "0.11.0",
|
|
70
|
-
"@intlayer/api": "8.9.
|
|
71
|
-
"@intlayer/babel": "8.9.
|
|
72
|
-
"@intlayer/chokidar": "8.9.
|
|
73
|
-
"@intlayer/config": "8.9.
|
|
74
|
-
"@intlayer/core": "8.9.
|
|
75
|
-
"@intlayer/dictionaries-entry": "8.9.
|
|
76
|
-
"@intlayer/remote-dictionaries-entry": "8.9.
|
|
77
|
-
"@intlayer/types": "8.9.
|
|
78
|
-
"@intlayer/unmerged-dictionaries-entry": "8.9.
|
|
70
|
+
"@intlayer/api": "8.9.7",
|
|
71
|
+
"@intlayer/babel": "8.9.7",
|
|
72
|
+
"@intlayer/chokidar": "8.9.7",
|
|
73
|
+
"@intlayer/config": "8.9.7",
|
|
74
|
+
"@intlayer/core": "8.9.7",
|
|
75
|
+
"@intlayer/dictionaries-entry": "8.9.7",
|
|
76
|
+
"@intlayer/remote-dictionaries-entry": "8.9.7",
|
|
77
|
+
"@intlayer/types": "8.9.7",
|
|
78
|
+
"@intlayer/unmerged-dictionaries-entry": "8.9.7",
|
|
79
79
|
"commander": "14.0.3",
|
|
80
80
|
"enquirer": "^2.4.1",
|
|
81
81
|
"eventsource": "4.1.0",
|
|
82
82
|
"fast-glob": "3.3.3"
|
|
83
83
|
},
|
|
84
84
|
"devDependencies": {
|
|
85
|
-
"@intlayer/ai": "8.9.
|
|
85
|
+
"@intlayer/ai": "8.9.7",
|
|
86
86
|
"@types/node": "25.8.0",
|
|
87
87
|
"@utils/ts-config": "1.0.4",
|
|
88
88
|
"@utils/ts-config-types": "1.0.4",
|
|
@@ -93,7 +93,7 @@
|
|
|
93
93
|
"vitest": "4.1.6"
|
|
94
94
|
},
|
|
95
95
|
"peerDependencies": {
|
|
96
|
-
"@intlayer/ai": "8.9.
|
|
96
|
+
"@intlayer/ai": "8.9.7"
|
|
97
97
|
},
|
|
98
98
|
"peerDependenciesMeta": {
|
|
99
99
|
"@intlayer/ai": {
|