UBERF-8887: Allow override region settings (#7450)

Signed-off-by: Andrey Sobolev <haiodo@gmail.com>
This commit is contained in:
Andrey Sobolev 2024-12-13 16:23:14 +07:00 committed by GitHub
parent f467388b64
commit de77b1a559
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 375 additions and 341 deletions

View File

@ -17,7 +17,7 @@ const Dotenv = require('dotenv-webpack')
const path = require('path')
const CompressionPlugin = require('compression-webpack-plugin')
const DefinePlugin = require('webpack').DefinePlugin
const HtmlWebpackPlugin = require('html-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin')
const { Configuration } = require('webpack')
const mode = process.env.NODE_ENV || 'development'
@ -26,17 +26,17 @@ const devServer = (process.env.CLIENT_TYPE ?? '') === 'dev-server'
const devProduction = (process.env.CLIENT_TYPE ?? '') === 'dev-production'
const devProductionHuly = (process.env.CLIENT_TYPE ?? '') === 'dev-huly'
const devProductionBold = (process.env.CLIENT_TYPE ?? '') === 'dev-bold'
const dev = (process.env.CLIENT_TYPE ?? '') === 'dev' || devServer || devProduction || devProductionHuly || devProductionBold
const ForkTsCheckerWebpackPlugin = require('fork-ts-checker-webpack-plugin');
const dev =
(process.env.CLIENT_TYPE ?? '') === 'dev' || devServer || devProduction || devProductionHuly || devProductionBold
const ForkTsCheckerWebpackPlugin = require('fork-ts-checker-webpack-plugin')
const { EsbuildPlugin } = require('esbuild-loader')
const doValidate = !prod || (process.env.DO_VALIDATE === 'true')
const doValidate = !prod || process.env.DO_VALIDATE === 'true'
const useCache = process.env.USE_CACHE === 'true'
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin
/**
* @type {Configuration}
@ -77,356 +77,366 @@ module.exports = [
}
},
{
cache: useCache ? {
type: 'filesystem',
allowCollectingMemory: true,
cacheLocation: path.resolve(__dirname, '.build_dev'),
}: undefined,
entry: {
bundle: [
'@hcengineering/theme/styles/global.scss',
...(dev ? ['./src/main-dev.ts'] : ['./src/main.ts']),
]
},
ignoreWarnings: [
{
message: /a11y-/,
cache: useCache
? {
type: 'filesystem',
allowCollectingMemory: true,
cacheLocation: path.resolve(__dirname, '.build_dev')
}
: undefined,
entry: {
bundle: ['@hcengineering/theme/styles/global.scss', ...(dev ? ['./src/main-dev.ts'] : ['./src/main.ts'])]
},
/warning from compiler/,
(warning) => true,
],
resolve: {
symlinks: true,
alias: {
svelte: path.resolve('node_modules', 'svelte/src/runtime'),
'@hcengineering/platform-rig/profiles/ui/svelte': path.resolve('node_modules', 'svelte/src/runtime')
},
fallback: {
crypto: false
},
extensions: ['.mjs', '.js', '.svelte', '.ts'],
mainFields: ['svelte', 'browser', 'module', 'main'],
conditionNames: ['svelte', 'browser', 'import']
},
output: {
path: __dirname + '/dist',
filename: '[name].[contenthash].js',
chunkFilename: '[name].[contenthash].js',
publicPath: '/',
pathinfo: false
},
optimization: prod ? {
minimize: true,
minimizer: [
new EsbuildPlugin({ target: 'es2021' })
],
splitChunks: {
chunks: 'all'
}
} : {
minimize: false,
mangleExports: false,
usedExports: false,
splitChunks: {
chunks: 'all'
}
},
module: {
rules: [
ignoreWarnings: [
{
test: /\.ts?$/,
loader: 'esbuild-loader',
options: {
target: 'es2021',
keepNames: true,
minify: prod,
sourcemap: true
},
exclude: /node_modules/,
message: /a11y-/
},
{
test: /\.svelte$/,
use: [
{
loader: 'svelte-loader',
/warning from compiler/,
(warning) => true
],
resolve: {
symlinks: true,
alias: {
svelte: path.resolve('node_modules', 'svelte/src/runtime'),
'@hcengineering/platform-rig/profiles/ui/svelte': path.resolve('node_modules', 'svelte/src/runtime')
},
fallback: {
crypto: false
},
extensions: ['.mjs', '.js', '.svelte', '.ts'],
mainFields: ['svelte', 'browser', 'module', 'main'],
conditionNames: ['svelte', 'browser', 'import']
},
output: {
path: __dirname + '/dist',
filename: '[name].[contenthash].js',
chunkFilename: '[name].[contenthash].js',
publicPath: '/',
pathinfo: false
},
optimization: prod
? {
minimize: true,
minimizer: [new EsbuildPlugin({ target: 'es2021' })],
splitChunks: {
chunks: 'all'
}
}
: {
minimize: false,
mangleExports: false,
usedExports: false,
splitChunks: {
chunks: 'all'
}
},
module: {
rules: [
{
test: /\.ts?$/,
loader: 'esbuild-loader',
options: {
compilerOptions: {
dev: !prod
},
emitCss: true,
hotReload: !prod,
preprocess: require('svelte-preprocess')({
postcss: true,
sourceMap: true,
}),
hotOptions: {
// Prevent preserving local component state
preserveLocalState: true,
target: 'es2021',
keepNames: true,
minify: prod,
sourcemap: true
},
exclude: /node_modules/
},
{
test: /\.svelte$/,
use: [
{
loader: 'svelte-loader',
options: {
compilerOptions: {
dev: !prod
},
emitCss: true,
hotReload: !prod,
preprocess: require('svelte-preprocess')({
postcss: true,
sourceMap: true
}),
hotOptions: {
// Prevent preserving local component state
preserveLocalState: true,
// If this string appears anywhere in your component's code, then local
// state won't be preserved, even when noPreserveState is false
noPreserveStateKey: '@!hmr',
// If this string appears anywhere in your component's code, then local
// state won't be preserved, even when noPreserveState is false
noPreserveStateKey: '@!hmr',
// Prevent doing a full reload on next HMR update after fatal error
noReload: true,
// Prevent doing a full reload on next HMR update after fatal error
noReload: true,
// Try to recover after runtime errors in component init
optimistic: false,
// Try to recover after runtime errors in component init
optimistic: false,
// --- Advanced ---
// --- Advanced ---
// Prevent adding an HMR accept handler to components with
// accessors option to true, or to components with named exports
// (from <script context="module">). This have the effect of
// recreating the consumer of those components, instead of the
// component themselves, on HMR updates. This might be needed to
// reflect changes to accessors / named exports in the parents,
// depending on how you use them.
acceptAccessors: true,
acceptNamedExports: true,
// Prevent adding an HMR accept handler to components with
// accessors option to true, or to components with named exports
// (from <script context="module">). This have the effect of
// recreating the consumer of those components, instead of the
// component themselves, on HMR updates. This might be needed to
// reflect changes to accessors / named exports in the parents,
// depending on how you use them.
acceptAccessors: true,
acceptNamedExports: true
}
}
}
]
},
{
test: /\.css$/,
use: [
// prod ? MiniCssExtractPlugin.loader :
'style-loader',
'css-loader',
'postcss-loader'
]
},
{
test: /\.scss$/,
use: [
// prod ? MiniCssExtractPlugin.loader :
'style-loader',
'css-loader',
'postcss-loader',
'sass-loader'
]
},
{
test: /\.(ttf|otf|eot|woff|woff2)$/,
use: {
loader: 'file-loader',
options: {
name: 'fonts/[hash:base64:8].[ext]',
esModule: false
}
}
}]
},
{
test: /\.css$/,
use: [
// prod ? MiniCssExtractPlugin.loader :
'style-loader',
'css-loader',
'postcss-loader'
]
},
{
test: /\.scss$/,
use: [
// prod ? MiniCssExtractPlugin.loader :
'style-loader',
'css-loader',
'postcss-loader',
'sass-loader',
],
},
{
test: /\.(ttf|otf|eot|woff|woff2)$/,
use: {
loader: 'file-loader',
options: {
name: 'fonts/[hash:base64:8].[ext]',
esModule: false
}
}
},
{
test: /\.(jpg|png|webp|heic|avif)$/,
use: {
loader: 'file-loader',
options: {
name: 'img/[contenthash].[ext]',
esModule: false
}
}
},
{
test: /\.(wav|ogg)$/,
use: {
loader: 'file-loader',
options: {
'name': 'snd/[contenthash].[ext]',
esModule: false
}
}
},
{
test: /\.svg$/,
use: [
{
},
{
test: /\.(jpg|png|webp|heic|avif)$/,
use: {
loader: 'file-loader',
options: {
name: 'img/[contenthash].[ext]',
esModule: false
}
},
{
loader: 'svgo-loader',
}
},
{
test: /\.(wav|ogg)$/,
use: {
loader: 'file-loader',
options: {
plugins: [
{ name: 'removeHiddenElems', active: false }
// { removeHiddenElems: { displayNone: false } },
// { cleanupIDs: false },
// { removeTitle: true }
]
name: 'snd/[contenthash].[ext]',
esModule: false
}
}
]
}
]
},
mode,
plugins: [
new BundleAnalyzerPlugin({
analyzerMode: 'static',
openAnalyzer: false,
}),
new HtmlWebpackPlugin({
meta: {
viewport: 'width=device-width, initial-scale=1.0'
}
}),
...(prod ? [new CompressionPlugin()] : []),
// new MiniCssExtractPlugin({
// filename: '[name].[id][contenthash].css'
// }),
new Dotenv({ path: prod ? '.env-prod' : '.env' }),
new DefinePlugin({
'process.env.CLIENT_TYPE': JSON.stringify(process.env.CLIENT_TYPE)
}),
...(doValidate ? [
new ForkTsCheckerWebpackPlugin()
] : [])
],
watchOptions: {
// for some systems, watching many files can result in a lot of CPU or memory usage
// https://webpack.js.org/configuration/watch/#watchoptionsignored
// don't use this pattern, if you have a monorepo with linked packages
ignored: [
"**/node_modules",
"**/.git",
"**/common/temp",
"**/.rush",
"**/.rush/**",
"**/rush-logs",
"**/lib/*.js",
"**/lib/*.js.map",
"**/types/*.d.ts",
"**/.git/objects/**",
"**/node_modules/**",
"**/desktop/deploy/**",
"**/dist/**",
"**/.validate/**",
"**/.format/**",
"**/.build_dev/**"
},
{
test: /\.svg$/,
use: [
{
loader: 'file-loader',
options: {
name: 'img/[contenthash].[ext]',
esModule: false
}
},
{
loader: 'svgo-loader',
options: {
plugins: [
{ name: 'removeHiddenElems', active: false }
// { removeHiddenElems: { displayNone: false } },
// { cleanupIDs: false },
// { removeTitle: true }
]
}
}
]
}
]
},
mode,
plugins: [
...(prod
? [
new BundleAnalyzerPlugin({
analyzerMode: 'static',
openAnalyzer: false
})
]
: []),
new HtmlWebpackPlugin({
meta: {
viewport: 'width=device-width, initial-scale=1.0'
}
}),
...(prod ? [new CompressionPlugin()] : []),
// new MiniCssExtractPlugin({
// filename: '[name].[id][contenthash].css'
// }),
new Dotenv({ path: prod ? '.env-prod' : '.env' }),
new DefinePlugin({
'process.env.CLIENT_TYPE': JSON.stringify(process.env.CLIENT_TYPE)
}),
...(doValidate ? [new ForkTsCheckerWebpackPlugin()] : [])
],
aggregateTimeout: 100,
followSymlinks: false,
poll: 250
},
devtool: prod ? 'source-map' : 'eval-source-map', // 'inline-source-map',
devServer: {
static: {
directory: path.resolve(__dirname, "public"),
publicPath: "/",
serveIndex: true,
watch: true,
watchOptions: {
// for some systems, watching many files can result in a lot of CPU or memory usage
// https://webpack.js.org/configuration/watch/#watchoptionsignored
// don't use this pattern, if you have a monorepo with linked packages
ignored: [
'**/node_modules',
'**/.git',
'**/common/temp',
'**/.rush',
'**/.rush/**',
'**/rush-logs',
'**/lib/*.js',
'**/lib/*.js.map',
'**/types/*.d.ts',
'**/.git/objects/**',
'**/node_modules/**',
'**/desktop/deploy/**',
'**/dist/**',
'**/.validate/**',
'**/.format/**',
'**/.build_dev/**'
],
aggregateTimeout: 100,
followSymlinks: false,
poll: 250
},
historyApiFallback: {
disableDotRule: true
},
host: '0.0.0.0',
allowedHosts: 'all',
hot: true,
client: {
logging: "info",
overlay: true,
progress: false,
},
proxy: (devServer && !devProduction && !devProductionHuly && !devProductionBold) ? {
'/account': {
target: 'http://localhost:3000',
changeOrigin: true,
pathRewrite: { '^/account': '' },
logLevel: 'debug'
devtool: prod ? 'source-map' : 'eval-source-map', // 'inline-source-map',
devServer: {
static: {
directory: path.resolve(__dirname, 'public'),
publicPath: '/',
serveIndex: true,
watch: true
},
'/files': {
target: 'http://localhost:8087',
changeOrigin: true,
logLevel: 'debug'
historyApiFallback: {
disableDotRule: true
},
'/api/v1': {
target: 'http://localhost:8087',
changeOrigin: true,
logLevel: 'debug'
host: '0.0.0.0',
allowedHosts: 'all',
hot: true,
client: {
logging: 'info',
overlay: true,
progress: false
},
'/import': {
target: 'http://localhost:8087',
changeOrigin: true,
logLevel: 'debug'
},
'/rekoni/recognize': {
target: 'http://localhost:4004',
changeOrigin: true,
pathRewrite: { '^/rekoni/recognize': '/recognize' },
logLevel: 'debug'
}
} : !devProductionHuly && !devProductionBold ? {
'/account': {
target: 'https://account.hc.engineering/',
changeOrigin: true,
pathRewrite: { '^/account': '' },
logLevel: 'debug'
},
'/files': {
target: 'https://front.hc.engineering/files',
changeOrigin: true,
pathRewrite: { '^/files': '' },
logLevel: 'debug'
},
'/rekoni/recognize': {
target: 'https://rekoni.hc.enigneering',
changeOrigin: true,
pathRewrite: { '^/rekoni/recognize': '/recognize' },
logLevel: 'debug'
}
}: !devProductionBold ? {
'/account': {
target: 'https://account.huly.app/',
changeOrigin: true,
pathRewrite: { '^/account': '' },
logLevel: 'debug'
},
'/api/v1': {
target: 'http://huly.app',
changeOrigin: true,
logLevel: 'debug'
},
'/files': {
target: 'https://huly.app/files',
changeOrigin: true,
pathRewrite: { '^/files': '' },
logLevel: 'debug'
},
'/rekoni/recognize': {
target: 'https://rekoni.huly.app',
changeOrigin: true,
pathRewrite: { '^/rekoni/recognize': '/recognize' },
logLevel: 'debug'
}
} : {
'/account': {
target: 'https://account.bold.ru/',
changeOrigin: true,
pathRewrite: { '^/account': '' },
logLevel: 'debug'
},
'/files': {
target: 'https://app.bold.ru/files',
changeOrigin: true,
pathRewrite: { '^/files': '' },
logLevel: 'debug'
},
'/api/v1': {
target: 'http://app.bold.ru',
changeOrigin: true,
logLevel: 'debug'
},
'/rekoni/recognize': {
target: 'https://rekoni.bold.ru',
changeOrigin: true,
pathRewrite: { '^/rekoni/recognize': '/recognize' },
logLevel: 'debug'
}
proxy:
devServer && !devProduction && !devProductionHuly && !devProductionBold
? {
'/account': {
target: 'http://localhost:3000',
changeOrigin: true,
pathRewrite: { '^/account': '' },
logLevel: 'debug'
},
'/files': {
target: 'http://localhost:8087',
changeOrigin: true,
logLevel: 'debug'
},
'/api/v1': {
target: 'http://localhost:8087',
changeOrigin: true,
logLevel: 'debug'
},
'/import': {
target: 'http://localhost:8087',
changeOrigin: true,
logLevel: 'debug'
},
'/rekoni/recognize': {
target: 'http://localhost:4004',
changeOrigin: true,
pathRewrite: { '^/rekoni/recognize': '/recognize' },
logLevel: 'debug'
}
}
: !devProductionHuly && !devProductionBold
? {
'/account': {
target: 'https://account.hc.engineering/',
changeOrigin: true,
pathRewrite: { '^/account': '' },
logLevel: 'debug'
},
'/files': {
target: 'https://front.hc.engineering/files',
changeOrigin: true,
pathRewrite: { '^/files': '' },
logLevel: 'debug'
},
'/rekoni/recognize': {
target: 'https://rekoni.hc.enigneering',
changeOrigin: true,
pathRewrite: { '^/rekoni/recognize': '/recognize' },
logLevel: 'debug'
}
}
: !devProductionBold
? {
'/account': {
target: 'https://account.huly.app/',
changeOrigin: true,
pathRewrite: { '^/account': '' },
logLevel: 'debug'
},
'/api/v1': {
target: 'http://huly.app',
changeOrigin: true,
logLevel: 'debug'
},
'/files': {
target: 'https://huly.app/files',
changeOrigin: true,
pathRewrite: { '^/files': '' },
logLevel: 'debug'
},
'/rekoni/recognize': {
target: 'https://rekoni.huly.app',
changeOrigin: true,
pathRewrite: { '^/rekoni/recognize': '/recognize' },
logLevel: 'debug'
}
}
: {
'/account': {
target: 'https://account.bold.ru/',
changeOrigin: true,
pathRewrite: { '^/account': '' },
logLevel: 'debug'
},
'/files': {
target: 'https://app.bold.ru/files',
changeOrigin: true,
pathRewrite: { '^/files': '' },
logLevel: 'debug'
},
'/api/v1': {
target: 'http://app.bold.ru',
changeOrigin: true,
logLevel: 'debug'
},
'/rekoni/recognize': {
target: 'https://rekoni.bold.ru',
changeOrigin: true,
pathRewrite: { '^/rekoni/recognize': '/recognize' },
logLevel: 'debug'
}
}
}
}
}]
]

View File

@ -426,13 +426,25 @@ export async function selectWorkspace (
branding: Branding | null,
token: string,
workspaceUrl: string,
kind: 'external' | 'internal',
allowAdmin: boolean = true
kind: 'external' | 'internal' | 'byregion',
allowAdmin: boolean = true,
externalRegions: string[] = []
): Promise<WorkspaceLoginInfo> {
const decodedToken = decodeToken(ctx, token)
const email = cleanEmail(decodedToken.email)
const endpointKind = kind === 'external' ? EndpointKind.External : EndpointKind.Internal
const getKind = (region: string | undefined): EndpointKind => {
switch (kind) {
case 'external':
return EndpointKind.External
case 'internal':
return EndpointKind.Internal
case 'byregion':
return externalRegions.includes(region ?? '') ? EndpointKind.External : EndpointKind.Internal
default:
return EndpointKind.External
}
}
if (email === guestAccountEmail && decodedToken.extra?.guest === 'true') {
const workspaceInfo = await getWorkspaceByUrl(db, workspaceUrl)
@ -441,9 +453,10 @@ export async function selectWorkspace (
new Status(Severity.ERROR, platform.status.WorkspaceNotFound, { workspace: workspaceUrl })
)
}
// Guest mode select workspace
return {
endpoint: getEndpoint(ctx, workspaceInfo, kind === 'external' ? EndpointKind.External : EndpointKind.Internal),
endpoint: getEndpoint(ctx, workspaceInfo, getKind(workspaceInfo.region)),
email,
token,
workspace: workspaceUrl,
@ -475,7 +488,7 @@ export async function selectWorkspace (
if ((accountInfo?.admin === true || email === systemAccountEmail) && allowAdmin) {
return {
endpoint: getEndpoint(ctx, workspaceInfo, endpointKind),
endpoint: getEndpoint(ctx, workspaceInfo, getKind(workspaceInfo.region)),
email,
token: generateToken(email, getWorkspaceId(workspaceInfo.workspace), getExtra(accountInfo)),
workspace: workspaceUrl,
@ -509,7 +522,7 @@ export async function selectWorkspace (
for (const w of workspaces) {
if (areDbIdsEqual(w, workspaceInfo._id)) {
const result = {
endpoint: getEndpoint(ctx, workspaceInfo, endpointKind),
endpoint: getEndpoint(ctx, workspaceInfo, getKind(workspaceInfo.region)),
email,
token: generateToken(email, getWorkspaceId(workspaceInfo.workspace), getExtra(accountInfo)),
workspace: workspaceUrl,

View File

@ -76,9 +76,20 @@ export async function updateBackupInfo (token: string, info: BackupStatus): Prom
return (workspaces.result as BaseWorkspaceInfo[]) ?? []
}
const externalRegions = process.env.EXTERNAL_REGIONS?.split(';') ?? []
/**
* Retrieves the transactor endpoint for a given token and kind.
*
* @param token - The authorization token.
* @param kind - The type of endpoint to retrieve. Can be 'internal', 'external', or 'byregion'. Defaults to 'byregion'.
* @param timeout - The timeout duration in milliseconds. Defaults to -1 (no timeout).
* @returns A promise that resolves to the transactor endpoint URL as a string.
* @throws Will throw an error if the request fails or if the timeout is reached.
*/
export async function getTransactorEndpoint (
token: string,
kind: 'internal' | 'external' = 'internal',
kind: 'internal' | 'external' | 'byregion' = 'byregion',
timeout: number = -1
): Promise<string> {
const accountsUrl = getAccoutsUrlOrFail()
@ -94,7 +105,7 @@ export async function getTransactorEndpoint (
},
body: JSON.stringify({
method: 'selectWorkspace',
params: ['', kind]
params: ['', kind, true, externalRegions]
})
})
).json()