diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 2cef0ff948..b602a5b102 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -409,7 +409,7 @@ jobs: DOCKER_CLI_HINTS: false - name: Configure /etc/hosts run: | - sudo echo "127.0.0.1 host.docker.internal" | sudo tee -a /etc/hosts + sudo echo "127.0.0.1 huly.local" | sudo tee -a /etc/hosts - name: Prepare server run: | cd ./qms-tests @@ -479,7 +479,7 @@ jobs: DOCKER_CLI_HINTS: false - name: Configure /etc/hosts run: | - sudo echo "127.0.0.1 host.docker.internal" | sudo tee -a /etc/hosts + sudo echo "127.0.0.1 huly.local" | sudo tee -a /etc/hosts - name: Prepare server run: | cd ./ws-tests diff --git a/.vscode/launch.json b/.vscode/launch.json index d3ee324774..d78c98e888 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -35,12 +35,12 @@ "args": ["src/__start.ts"], "env": { // "FULLTEXT_URL": "http://localhost:4700", - "FULLTEXT_URL": "http://host.docker.internal:4702", + "FULLTEXT_URL": "http://huly.local:4702", // "MONGO_URL": "mongodb://localhost:27017", // "DB_URL": "mongodb://localhost:27017", // "DB_URL": "postgresql://postgres:example@localhost:5432", - "DB_URL": "postgresql://root@host.docker.internal:26257/defaultdb?sslmode=disable", - "GREEN_URL": "http://host.docker.internal:6767?token=secret", + "DB_URL": "postgresql://root@huly.local:26257/defaultdb?sslmode=disable", + "GREEN_URL": "http://huly.local:6767?token=secret", "SERVER_PORT": "3332", "APM_SERVER_URL2": "http://localhost:8200", "METRICS_CONSOLE": "false", @@ -60,7 +60,7 @@ "ELASTIC_INDEX_NAME": "local_storage_index", "UPLOAD_URL": "/files", "AI_BOT_URL": "http://localhost:4010", - "STATS_URL": "http://host.docker.internal:4900" + "STATS_URL": "http://huly.local:4900" }, "runtimeArgs": ["--nolazy", "-r", "ts-node/register"], "runtimeVersion": "20", @@ -79,8 +79,8 @@ "FULLTEXT_URL": "http://localhost:4710", // "DB_URL": "mongodb://localhost:27018", // "DB_URL": "postgresql://postgres:example@localhost:5432", - "DB_URL": "postgresql://root@host.docker.internal:26258/defaultdb?sslmode=disable", - // "GREEN_URL": "http://host.docker.internal:6767?token=secret", + "DB_URL": "postgresql://root@huly.local:26258/defaultdb?sslmode=disable", + // "GREEN_URL": "http://huly.local:6767?token=secret", "SERVER_PORT": "3335", "METRICS_CONSOLE": "false", "METRICS_FILE": "${workspaceRoot}/metrics.txt", // Show metrics in console evert 30 seconds., @@ -92,7 +92,7 @@ "ACCOUNTS_URL": "http://localhost:3003", "MODEL_JSON": "${workspaceRoot}/models/all/bundle/model.json", "MODEL_VERSION": "0.7.1", - "STATS_URL": "http://host.docker.internal:4901" + "STATS_URL": "http://huly.local:4901" }, "runtimeArgs": ["--nolazy", "-r", "ts-node/register"], "runtimeVersion": "20", @@ -113,13 +113,13 @@ "FULLTEXT_DB_URL": "http://localhost:9200", // "DB_URL": "mongodb://localhost:27017", // "DB_URL": "postgresql://postgres:example@localhost:5432", - "DB_URL": "postgresql://root@host.docker.internal:26257/defaultdb?sslmode=disable", + "DB_URL": "postgresql://root@huly.local:26257/defaultdb?sslmode=disable", "STORAGE_CONFIG": "minio|localhost?accessKey=minioadmin&secretKey=minioadmin", "SERVER_SECRET": "secret", "REKONI_URL": "http://localhost:4004", "MODEL_JSON": "${workspaceRoot}/models/all/bundle/model.json", "ELASTIC_INDEX_NAME": "local_storage_index", - "STATS_URL":"http://host.docker.internal:4900", + "STATS_URL":"http://huly.local:4900", "ACCOUNTS_URL": "http://localhost:3000", }, "runtimeArgs": ["--nolazy", "-r", "ts-node/register"], @@ -138,14 +138,14 @@ "env": { "MONGO_URL": "mongodb://localhost:27017", "DB_URL": "mongodb://localhost:27017", - // "DB_URL": "postgresql://root@host.docker.internal:26257/defaultdb?sslmode=disable", + // "DB_URL": "postgresql://root@huly.local:26257/defaultdb?sslmode=disable", "SERVER_SECRET": "secret", "REGION_INFO":"|Mongo;cockroach|CockroachDB", - "TRANSACTOR_URL": "ws://host.docker.internal:3333,ws://host.docker.internal:3332;;cockroach", + "TRANSACTOR_URL": "ws://huly.local:3333,ws://huly.local:3332;;cockroach", "ACCOUNTS_URL": "http://localhost:3000", "ACCOUNT_PORT": "3000", "FRONT_URL": "http://localhost:8080", - "STATS_URL": "http://host.docker.internal:4900", + "STATS_URL": "http://huly.local:4900", "SES_URL": "", // "DB_NS": "account-2", // "WS_LIVENESS_DAYS": "1", @@ -172,11 +172,11 @@ // "DB_URL": "postgresql://postgres:example@localhost:5432", "SERVER_SECRET": "secret", "REGION_INFO":"|Mongo;pg|Postgres;cockroach|CockroachDB", - "TRANSACTOR_URL": "ws://host.docker.internal:3334;;,ws://host.docker.internal:3335;;europe", + "TRANSACTOR_URL": "ws://huly.local:3334;;,ws://huly.local:3335;;europe", "ACCOUNTS_URL": "http://localhost:3003", "ACCOUNT_PORT": "3003", "FRONT_URL": "http://localhost:8083", - "STATS_URL": "http://host.docker.internal:4901", + "STATS_URL": "http://huly.local:4901", "SES_URL": "", // "DB_NS": "account-2", // "WS_LIVENESS_DAYS": "1", @@ -216,7 +216,7 @@ "env": { "DB_URL": "mongodb://localhost:27017", // "DB_URL": "postgresql://postgres:example@localhost:5432", - // "DB_URL": "postgresql://root@host.docker.internal:26257/defaultdb?sslmode=disable", + // "DB_URL": "postgresql://root@huly.local:26257/defaultdb?sslmode=disable", "REGION": "", "SERVER_SECRET": "secret", @@ -249,8 +249,8 @@ "env": { // "DB_URL": "mongodb://localhost:27017", // "DB_URL": "postgresql://postgres:example@localhost:5432", - "DB_URL": "postgresql://root@host.docker.internal:26257/defaultdb?sslmode=disable", - "FULLTEXT_URL": "http://host.docker.internal:4702", + "DB_URL": "postgresql://root@huly.local:26257/defaultdb?sslmode=disable", + "FULLTEXT_URL": "http://huly.local:4702", "REGION": "cockroach", "SERVER_SECRET": "secret", "TRANSACTOR_URL": "ws://localhost:3332", @@ -415,7 +415,7 @@ "ACCOUNT_DB_URL": "mongodb://localhost:27017", // "ACCOUNT_DB_URL": "postgresql://postgres:example@localhost:5433", // "DB_URL": "postgresql://postgres:example@localhost:5433", - "DB_URL": "postgresql://root@host.docker.internal:26257/defaultdb?sslmode=disable", + "DB_URL": "postgresql://root@huly.local:26257/defaultdb?sslmode=disable", "MONGO_URL": "mongodb://localhost:27017", "TELEGRAM_DATABASE": "telegram-service", "REKONI_URL": "http://localhost:4004", @@ -514,7 +514,7 @@ "PLATFORM_OPERATION_LOGGING": "true", "FRONT_URL": "http://localhost:8080", "PORT": "3500", - "STATS_URL": "http://host.docker.internal:4900" + "STATS_URL": "http://huly.local:4900" }, "runtimeArgs": ["--nolazy", "-r", "ts-node/register"], "sourceMaps": true, diff --git a/README.md b/README.md index 48d5b15082..6335127895 100644 --- a/README.md +++ b/README.md @@ -31,6 +31,8 @@ This project offers a convenient method to host Huly using `docker`, designed fo - [Table of Content](#table-of-content) - [Pre-requisites](#pre-requisites) - [Verification](#verification) + - [Fast start](#fast-start) + - [Branches \& Contributing](#branches--contributing) - [Installation](#installation) - [Build and run](#build-and-run) - [Run in development mode](#run-in-development-mode) @@ -81,7 +83,7 @@ We periodically merge `develop` into `staging` to perform testing builds. Once w ## Installation -You need Microsoft's [rush](https://rushjs.io) to install application. +You need Microsoft's [rush](https://rushjs.io) to install the application. 1. Install Rush globally using the command: @@ -149,10 +151,10 @@ sh ./scripts/create-workspace.sh Add the following line to your /etc/hosts file ```plain -127.0.0.1 host.docker.internal +127.0.0.1 huly.local ``` -Accessing the URL will lead you to the app in development mode. +Accessing the URL will lead you to the app in development mode. Limitations: diff --git a/common/config/rush/pnpm-lock.yaml b/common/config/rush/pnpm-lock.yaml index b4c2c57fbf..cb4157384d 100644 --- a/common/config/rush/pnpm-lock.yaml +++ b/common/config/rush/pnpm-lock.yaml @@ -1330,6 +1330,9 @@ importers: '@types/compression': specifier: ~1.7.2 version: 1.7.5 + '@types/cookies': + specifier: ^0.9.0 + version: 0.9.0 '@types/cors': specifier: ^2.8.12 version: 2.8.17 @@ -1534,6 +1537,9 @@ importers: compression-webpack-plugin: specifier: ^10.0.0 version: 10.0.0(webpack@5.97.1) + cookies: + specifier: ^0.9.1 + version: 0.9.1 copy-webpack-plugin: specifier: ^11.0.0 version: 11.0.0(webpack@5.97.1) @@ -3955,7 +3961,7 @@ packages: version: 0.0.0 '@rush-temp/account-service@file:projects/account-service.tgz': - resolution: {integrity: sha512-SBWP6HBOnzpJC3MIOlYbttcjYw1HoD9VpbLpUS3zRwEL2slU6c0W/hEBU0/rzh3KkLb6bScKssS5utlSx5RrNw==, tarball: file:projects/account-service.tgz} + resolution: {integrity: sha512-ViPfMFYJ6+K9NPAIyV9v6+v6BRtdPCSiU4iTXCdZsoPgpag3nFxhE5PC3ahzS2wJ0TbCX+5UdaUX/UE3ySL4OA==, tarball: file:projects/account-service.tgz} version: 0.0.0 '@rush-temp/account@file:projects/account.tgz': @@ -4003,7 +4009,7 @@ packages: version: 0.0.0 '@rush-temp/api-client@file:projects/api-client.tgz': - resolution: {integrity: sha512-lFsfqbx6XIWKo8wq95O25j0RYJ9pUMgtb3T/tVUKfWG36NUuImICpStaQRmcm6MPYq7Gtb0KKuOXyQJg3y/80w==, tarball: file:projects/api-client.tgz} + resolution: {integrity: sha512-SMKCkubeb8nE1zsYu0fsutpc9LJKiNOG0bn9NP+FxlSU4NGb8++EpZfb650lGYdvg2MljvrQD+kqYQDt1IRd1A==, tarball: file:projects/api-client.tgz} version: 0.0.0 '@rush-temp/attachment-assets@file:projects/attachment-assets.tgz': @@ -4471,7 +4477,7 @@ packages: version: 0.0.0 '@rush-temp/model-presence@file:projects/model-presence.tgz': - resolution: {integrity: sha512-bE9NfhmtkeenHePBuorhYSQloGaNnGqtlw2i8ObXBD2ecu21ArwfbrJdHnQiy+Qtq8rs3j+rcCV/BcWpJSBJYQ==, tarball: file:projects/model-presence.tgz} + resolution: {integrity: sha512-qmASNpTrKWs0Gu44tU9AQk5a95g8DXoO3wkLRh4ySUYquv6msXXRYs0RbtPg0AV0qqoBmkvDlQowaoN8O1eG+Q==, tarball: file:projects/model-presence.tgz} version: 0.0.0 '@rush-temp/model-presentation@file:projects/model-presentation.tgz': @@ -4839,7 +4845,7 @@ packages: version: 0.0.0 '@rush-temp/presence@file:projects/presence.tgz': - resolution: {integrity: sha512-UAKP+9sJPe3sFFYkuaoRLl5OGmzjdjb35+WCRBenMndS9HljrLekTZp2DL9F1XiyBa4OkB38vYYy2OoobeXx6Q==, tarball: file:projects/presence.tgz} + resolution: {integrity: sha512-omWUs5nB6Ialj+zdl2/frK7kgnBKNKdnsOK4kckybnR+MUscznChTAs5LtdSpmRvOG0uJeAlR1jHHui0STlBUg==, tarball: file:projects/presence.tgz} version: 0.0.0 '@rush-temp/presentation@file:projects/presentation.tgz': @@ -5239,7 +5245,7 @@ packages: version: 0.0.0 '@rush-temp/server-ws@file:projects/server-ws.tgz': - resolution: {integrity: sha512-5g3NGK0JdwcpXIRpsGN75fiev+4fpwl4V33V5rwzrLZzHUNE7CAzTtc/cFRxK5cZIVRwaaTNCYi+WCEfoFI7Tg==, tarball: file:projects/server-ws.tgz} + resolution: {integrity: sha512-Sev25LbpscG4MEnofW4g16Wsd4CzBMuFd1WqiVKwCOBPQEFxrH6zQ9wt20gHcjKacPZfn4GMFWuHew0H/ThuqQ==, tarball: file:projects/server-ws.tgz} version: 0.0.0 '@rush-temp/server@file:projects/server.tgz': @@ -5367,7 +5373,7 @@ packages: version: 0.0.0 '@rush-temp/text-editor-resources@file:projects/text-editor-resources.tgz': - resolution: {integrity: sha512-PkvG582CT0XfnKC+4uNE1ZnwUgT9ywmfDmVr5vgcXti04Ntx1rB9VzTqnNDFI/A7h5dFAeEbR8s08gzgO6fdrw==, tarball: file:projects/text-editor-resources.tgz} + resolution: {integrity: sha512-EOKVWvCnTrXtst6yszXjgYSe1Hi0pCnMvNVw34jFBOQfLgMrUi1pk2IN6HVwFXFa5hSEEoR3C3Bh/Ga8quvrqQ==, tarball: file:projects/text-editor-resources.tgz} version: 0.0.0 '@rush-temp/text-editor@file:projects/text-editor.tgz': @@ -5427,7 +5433,7 @@ packages: version: 0.0.0 '@rush-temp/ui@file:projects/ui.tgz': - resolution: {integrity: sha512-THkZLcaBxS58m9cqY59M3XZMTKNmmjb4CWSnh3nv8pzI0uuMHhZ9ldjS6zrzOLQJRlVB7XWuJBT/J5F9oLFs+w==, tarball: file:projects/ui.tgz} + resolution: {integrity: sha512-RoUDfXdl8E3vT/wG4bVrY9FsfUPeqG9Bck6lQsnKj9kk/Q6gG7a4xl3qEkwk+qLU6qH6QD7lkUiaEbm4PXh5MA==, tarball: file:projects/ui.tgz} version: 0.0.0 '@rush-temp/uploader-assets@file:projects/uploader-assets.tgz': @@ -8405,9 +8411,6 @@ packages: emoji-regex@9.2.2: resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} - emojibase-regex@16.0.0: - resolution: {integrity: sha512-ZMp31BkzBWNW+T73of6NURL6nXQa5GkfKneOkr3cEwBDVllbW/2nuva7NO0J3RjaQ07+SZQNgPTGZ4JlIhmM2Q==} - emojibase@16.0.0: resolution: {integrity: sha512-Nw2m7JLIO4Ou2X/yZPRNscHQXVbbr6SErjkJ7EooG7MbR3yDZszCv9KTizsXFc7yZl0n3WF+qUKIC/Lw6H9xaQ==} engines: {node: '>=18.12.0'} @@ -16067,6 +16070,7 @@ snapshots: '@rush-temp/account-service@file:projects/account-service.tgz(@babel/core@7.23.9)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.23.9))(gcp-metadata@5.3.0(encoding@0.1.13))(snappy@7.2.2)(socks@2.8.3)': dependencies: '@koa/cors': 5.0.0 + '@types/cookies': 0.9.0 '@types/jest': 29.5.12 '@types/koa': 2.15.0 '@types/koa-bodyparser': 4.3.12 @@ -16075,6 +16079,7 @@ snapshots: '@types/node': 20.11.19 '@typescript-eslint/eslint-plugin': 6.21.0(@typescript-eslint/parser@6.21.0(eslint@8.56.0)(typescript@5.3.3))(eslint@8.56.0)(typescript@5.3.3) '@typescript-eslint/parser': 6.21.0(eslint@8.56.0)(typescript@5.3.3) + cookies: 0.9.1 cross-env: 7.0.3 esbuild: 0.24.2 eslint: 8.56.0 @@ -16454,6 +16459,7 @@ snapshots: dependencies: '@types/jest': 29.5.12 '@types/node': 20.11.19 + '@types/snappyjs': 0.7.1 '@types/ws': 8.5.11 '@typescript-eslint/eslint-plugin': 6.21.0(@typescript-eslint/parser@6.21.0(eslint@8.56.0)(typescript@5.3.3))(eslint@8.56.0)(typescript@5.6.2) '@typescript-eslint/parser': 6.21.0(eslint@8.56.0)(typescript@5.6.2) @@ -16465,6 +16471,7 @@ snapshots: jest: 29.7.0(@types/node@20.11.19)(ts-node@10.9.2(@types/node@20.11.19)(typescript@5.3.3)) prettier: 3.2.5 simplytyped: 3.3.0(typescript@5.6.2) + snappyjs: 0.7.0 ts-jest: 29.1.2(@babel/core@7.23.9)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.23.9))(esbuild@0.24.2)(jest@29.7.0(@types/node@20.11.19)(ts-node@10.9.2(@types/node@20.11.19)(typescript@5.3.3)))(typescript@5.6.2) ts-node: 10.9.2(@types/node@20.11.19)(typescript@5.6.2) typescript: 5.6.2 @@ -26144,7 +26151,6 @@ snapshots: date-fns-tz: 2.0.0(date-fns@2.30.0) dompurify: 3.1.6 emojibase: 16.0.0 - emojibase-regex: 16.0.0 eslint: 8.56.0 eslint-config-standard-with-typescript: 40.0.0(@typescript-eslint/eslint-plugin@6.21.0(@typescript-eslint/parser@6.21.0(eslint@8.56.0)(typescript@5.3.3))(eslint@8.56.0)(typescript@5.3.3))(eslint-plugin-import@2.29.1(eslint@8.56.0))(eslint-plugin-n@15.7.0(eslint@8.56.0))(eslint-plugin-promise@6.1.1(eslint@8.56.0))(eslint@8.56.0)(typescript@5.3.3) eslint-plugin-import: 2.29.1(eslint@8.56.0) @@ -30194,8 +30200,6 @@ snapshots: emoji-regex@9.2.2: {} - emojibase-regex@16.0.0: {} - emojibase@16.0.0: {} emojis-list@3.0.0: {} diff --git a/desktop/.env-dev b/desktop/.env-dev index 037febc783..936dd726fd 100644 --- a/desktop/.env-dev +++ b/desktop/.env-dev @@ -1,2 +1,2 @@ -FRONT_URL=http://localhost:8087 +FRONT_URL=http://huly.local:8087 CONFIG_URL=config.json diff --git a/desktop/src/main/start.ts b/desktop/src/main/start.ts index fee9be59bc..6c276e1aa6 100644 --- a/desktop/src/main/start.ts +++ b/desktop/src/main/start.ts @@ -63,7 +63,7 @@ const serverChanged = oldFront !== FRONT_URL function readServerUrl (): string { if (isDev) { - return process.env.FRONT_URL ?? 'http://localhost:8087' + return process.env.FRONT_URL ?? 'http://huly.local:8087' } return ((settings as any).get('server', process.env.FRONT_URL) as string) ?? 'https://huly.app' diff --git a/desktop/src/ui/index.ts b/desktop/src/ui/index.ts index 2658d01ea9..499a86d5f5 100644 --- a/desktop/src/ui/index.ts +++ b/desktop/src/ui/index.ts @@ -1,24 +1,21 @@ -import login, { loginId } from '@hcengineering/login' -import { getEmbeddedLabel, getMetadata, setMetadata } from '@hcengineering/platform' -import presentation, { closeClient, MessageBox, setDownloadProgress } from '@hcengineering/presentation' +import { loginId } from '@hcengineering/login' +import { getEmbeddedLabel, getMetadata } from '@hcengineering/platform' +import presentation, { MessageBox, setDownloadProgress } from '@hcengineering/presentation' import settings, { settingId } from '@hcengineering/setting' import { closePanel, closePopup, createApp, - fetchMetadataLocalStorage, - getCurrentLocation, getCurrentResolvedLocation, navigate, parseLocation, pushRootBarProgressComponent, removeRootBarComponent, - setMetadataLocalStorage, showPopup } from '@hcengineering/ui' import { notificationId } from '@hcengineering/notification' -import { workbenchId } from '@hcengineering/workbench' +import { workbenchId, logOut } from '@hcengineering/workbench' import { isOwnerOrMaintainer } from '@hcengineering/core' import { configurePlatform } from './platform' @@ -58,18 +55,7 @@ window.addEventListener('DOMContentLoaded', () => { }) ipcMain.on('logout', () => { - const tokens = fetchMetadataLocalStorage(login.metadata.LoginTokensV2) - if (tokens !== null) { - const loc = getCurrentLocation() - // eslint-disable-next-line @typescript-eslint/no-dynamic-delete - delete tokens[loc.path[1]] - setMetadataLocalStorage(login.metadata.LoginTokensV2, tokens) - } - setMetadata(presentation.metadata.Token, null) - setMetadataLocalStorage(login.metadata.LastToken, null) - setMetadataLocalStorage(login.metadata.LoginEndpoint, null) - setMetadataLocalStorage(login.metadata.LoginAccount, null) - void closeClient().then(() => { + void logOut().then(() => { navigate({ path: [loginId] }) }) }) diff --git a/dev/branding.json b/dev/branding.json index b35a6042a5..44b2d6d91e 100644 --- a/dev/branding.json +++ b/dev/branding.json @@ -1,12 +1,12 @@ { - "localhost:8080": { + "huly.local:8080": { "key": "huly-dev", "title": "Huly", "protocol": "http", "language": "en", "lastNameFirst": "true" }, - "localhost:8087": { + "huly.local:8087": { "key": "huly", "title": "Huly", "protocol": "http", @@ -20,13 +20,13 @@ "language": "en", "lastNameFirst": "true" }, - "localhost:8081": { + "huly.local:8081": { "key": "tracex-dev", "title": "TraceX", "protocol": "http", "language": "en" }, - "localhost:8088": { + "huly.local:8088": { "key": "tracex", "title": "TraceX", "protocol": "http", diff --git a/dev/docker-compose.yaml b/dev/docker-compose.yaml index 99a9ceab8e..99ca8cf30a 100644 --- a/dev/docker-compose.yaml +++ b/dev/docker-compose.yaml @@ -3,7 +3,7 @@ services: image: 'mongo:7-jammy' container_name: mongodb extra_hosts: - - 'host.docker.internal:host-gateway' + - 'huly.local:host-gateway' healthcheck: test: echo "try { db.currentOp().ok } catch (err) { }" | mongosh --port 27017 --quiet interval: 5s @@ -61,7 +61,7 @@ services: account: image: hardcoreeng/account extra_hosts: - - 'host.docker.internal:host-gateway' + - 'huly.local:host-gateway' links: - mongodb - minio @@ -74,29 +74,29 @@ services: - ACCOUNT_PORT=3000 - SERVER_SECRET=secret - ADMIN_EMAILS=admin - - STATS_URL=http://host.docker.internal:4900 - # - DB_URL=postgresql://root@host.docker.internal:26257/defaultdb?sslmode=disable + - STATS_URL=http://huly.local:4900 + # - DB_URL=postgresql://root@huly.local:26257/defaultdb?sslmode=disable - DB_URL=${MONGO_URL} # - DB_NS=account-2 # Pass only one region to disallow selection for new workspaces.Ø - REGION_INFO=|Mongo;cockroach|CockroachDB # - REGION_INFO=cockroach|CockroachDB - - TRANSACTOR_URL=ws://host.docker.internal:3333,ws://host.docker.internal:3332;;cockroach, + - TRANSACTOR_URL=ws://huly.local:3333,ws://huly.local:3332;;cockroach, - SES_URL= - STORAGE_CONFIG=${STORAGE_CONFIG} - - FRONT_URL=http://host.docker.internal:8087 + - FRONT_URL=http://huly.local:8087 - RESERVED_DB_NAMES=telegram,gmail,github - MODEL_ENABLED=* - LAST_NAME_FIRST=true # - WS_LIVENESS_DAYS=1 - - ACCOUNTS_URL=http://host.docker.internal:3000 + - ACCOUNTS_URL=http://huly.local:3000 - BRANDING_PATH=/var/cfg/branding.json # - DISABLE_SIGNUP=true restart: unless-stopped stats: image: hardcoreeng/stats extra_hosts: - - 'host.docker.internal:host-gateway' + - 'huly.local:host-gateway' ports: - 4900:4900 environment: @@ -106,7 +106,7 @@ services: workspace: image: hardcoreeng/workspace extra_hosts: - - 'host.docker.internal:host-gateway' + - 'huly.local:host-gateway' links: - mongodb - minio @@ -117,12 +117,12 @@ services: - WS_OPERATION=all+backup - SERVER_SECRET=secret - DB_URL=${MONGO_URL} - - STATS_URL=http://host.docker.internal:4900 + - STATS_URL=http://huly.local:4900 - SES_URL= - STORAGE_CONFIG=${STORAGE_CONFIG} - RESERVED_DB_NAMES=telegram,gmail,github - MODEL_ENABLED=* - - ACCOUNTS_URL=http://host.docker.internal:3000 + - ACCOUNTS_URL=http://huly.local:3000 - BRANDING_PATH=/var/cfg/branding.json # - PARALLEL=2 - BACKUP_STORAGE=${BACKUP_STORAGE_CONFIG} @@ -132,7 +132,7 @@ services: workspace_cockroach: image: hardcoreeng/workspace extra_hosts: - - 'host.docker.internal:host-gateway' + - 'huly.local:host-gateway' links: - cockroach - minio @@ -142,14 +142,14 @@ services: environment: - WS_OPERATION=all+backup - SERVER_SECRET=secret - - DB_URL=postgresql://root@host.docker.internal:26257/defaultdb?sslmode=disable - - STATS_URL=http://host.docker.internal:4900 + - DB_URL=postgresql://root@huly.local:26257/defaultdb?sslmode=disable + - STATS_URL=http://huly.local:4900 - SES_URL= - REGION=cockroach - STORAGE_CONFIG=${STORAGE_CONFIG} - RESERVED_DB_NAMES=telegram,gmail,github - MODEL_ENABLED=* - - ACCOUNTS_URL=http://host.docker.internal:3000 + - ACCOUNTS_URL=http://huly.local:3000 - BRANDING_PATH=/var/cfg/branding.json # - PARALLEL=2 - BACKUP_STORAGE=${BACKUP_STORAGE_CONFIG} @@ -159,7 +159,7 @@ services: collaborator: image: hardcoreeng/collaborator extra_hosts: - - 'host.docker.internal:host-gateway' + - 'huly.local:host-gateway' links: - mongodb - minio @@ -170,14 +170,14 @@ services: environment: - COLLABORATOR_PORT=3078 - SECRET=secret - - ACCOUNTS_URL=http://host.docker.internal:3000 + - ACCOUNTS_URL=http://huly.local:3000 - STORAGE_CONFIG=${STORAGE_CONFIG} - - STATS_URL=http://host.docker.internal:4900 + - STATS_URL=http://huly.local:4900 restart: unless-stopped front: image: hardcoreeng/front extra_hosts: - - 'host.docker.internal:host-gateway' + - 'huly.local:host-gateway' links: - mongodb - minio @@ -191,28 +191,28 @@ services: environment: - SERVER_PORT=8080 - SERVER_SECRET=secret - - ACCOUNTS_URL=http://host.docker.internal:3000 - - STATS_URL=http://host.docker.internal:4900 + - ACCOUNTS_URL=http://huly.local:3000 + - STATS_URL=http://huly.local:4900 - UPLOAD_URL=/files - - GMAIL_URL=http://host.docker.internal:8088 - - CALENDAR_URL=http://host.docker.internal:8095 - - TELEGRAM_URL=http://host.docker.internal:8086 - - REKONI_URL=http://host.docker.internal:4004 - - COLLABORATOR_URL=ws://host.docker.internal:3078 + - GMAIL_URL=http://huly.local:8088 + - CALENDAR_URL=http://huly.local:8095 + - TELEGRAM_URL=http://huly.local:8086 + - REKONI_URL=http://huly.local:4004 + - COLLABORATOR_URL=ws://huly.local:3078 - STORAGE_CONFIG=${STORAGE_CONFIG} - - GITHUB_URL=http://host.docker.internal:3500 - - PRINT_URL=http://host.docker.internal:4005 - - SIGN_URL=http://host.docker.internal:4006 - - ANALYTICS_COLLECTOR_URL=http://host.docker.internal:4017 + - GITHUB_URL=http://huly.local:3500 + - PRINT_URL=http://huly.local:4005 + - SIGN_URL=http://huly.local:4006 + - ANALYTICS_COLLECTOR_URL=http://huly.local:4017 - DESKTOP_UPDATES_URL=https://dist.huly.io - DESKTOP_UPDATES_CHANNEL=dev - - BRANDING_URL=http://host.docker.internal:8087/branding.json + - BRANDING_URL=http://huly.local:8087/branding.json # - DISABLE_SIGNUP=true restart: unless-stopped transactor: image: hardcoreeng/transactor extra_hosts: - - 'host.docker.internal:host-gateway' + - 'huly.local:host-gateway' links: - mongodb - minio @@ -230,8 +230,8 @@ services: - SERVER_PORT=3333 - SERVER_SECRET=secret - ENABLE_COMPRESSION=false - - STATS_URL=http://host.docker.internal:4900 - - FULLTEXT_URL=http://host.docker.internal:4700 + - STATS_URL=http://huly.local:4900 + - FULLTEXT_URL=http://huly.local:4700 # - DB_URL=postgresql://postgres:example@postgres:5432 - DB_URL=${MONGO_URL} - MONGO_URL=${MONGO_URL} @@ -239,18 +239,18 @@ services: - METRICS_CONSOLE=false - METRICS_FILE=metrics.txt - STORAGE_CONFIG=${STORAGE_CONFIG} - - FRONT_URL=http://host.docker.internal:8087 + - FRONT_URL=http://huly.local:8087 # - APM_SERVER_URL=http://apm-server:8200 - SES_URL='' - - ACCOUNTS_URL=http://host.docker.internal:3000 + - ACCOUNTS_URL=http://huly.local:3000 - LAST_NAME_FIRST=true - BRANDING_PATH=/var/cfg/branding.json - - AI_BOT_URL=http://host.docker.internal:4010 + - AI_BOT_URL=http://huly.local:4010 restart: unless-stopped transactor_cockroach: image: hardcoreeng/transactor extra_hosts: - - 'host.docker.internal:host-gateway' + - 'huly.local:host-gateway' links: - cockroach - minio @@ -268,24 +268,24 @@ services: - SERVER_PORT=3332 - SERVER_SECRET=secret - ENABLE_COMPRESSION=false - - FULLTEXT_URL=http://host.docker.internal:4702 - - STATS_URL=http://host.docker.internal:4900 - - DB_URL=postgresql://root@host.docker.internal:26257/defaultdb?sslmode=disable + - FULLTEXT_URL=http://huly.local:4702 + - STATS_URL=http://huly.local:4900 + - DB_URL=postgresql://root@huly.local:26257/defaultdb?sslmode=disable - METRICS_CONSOLE=false - METRICS_FILE=metrics.txt - STORAGE_CONFIG=${STORAGE_CONFIG} - - FRONT_URL=http://host.docker.internal:8087 + - FRONT_URL=http://huly.local:8087 # - APM_SERVER_URL=http://apm-server:8200 - SES_URL='' - - ACCOUNTS_URL=http://host.docker.internal:3000 + - ACCOUNTS_URL=http://huly.local:3000 - LAST_NAME_FIRST=true - BRANDING_PATH=/var/cfg/branding.json - - AI_BOT_URL=http://host.docker.internal:4010 + - AI_BOT_URL=http://huly.local:4010 restart: unless-stopped green: image: hardcoreeng/green extra_hosts: - - 'host.docker.internal:host-gateway' + - 'huly.local:host-gateway' links: - cockroach - stats @@ -294,8 +294,8 @@ services: environment: - PORT=6767 - AUTH_TOKEN=secret - - STATS_URL=http://host.docker.internal:4900 - - DB_URL=postgresql://root@host.docker.internal:26257/defaultdb?sslmode=disable + - STATS_URL=http://huly.local:4900 + - DB_URL=postgresql://root@huly.local:26257/defaultdb?sslmode=disable restart: unless-stopped rekoni: image: hardcoreeng/rekoni-service @@ -305,7 +305,7 @@ services: fulltext: image: hardcoreeng/fulltext extra_hosts: - - 'host.docker.internal:host-gateway' + - 'huly.local:host-gateway' restart: unless-stopped links: - elastic @@ -315,16 +315,16 @@ services: environment: - SERVER_SECRET=secret - DB_URL=${MONGO_URL} - - FULLTEXT_DB_URL=http://host.docker.internal:9200 + - FULLTEXT_DB_URL=http://huly.local:9200 - ELASTIC_INDEX_NAME=local_storage_index - STORAGE_CONFIG=${STORAGE_CONFIG} - - STATS_URL=http://host.docker.internal:4900 - - REKONI_URL=http://host.docker.internal:4004 - - ACCOUNTS_URL=http://host.docker.internal:3000 + - STATS_URL=http://huly.local:4900 + - REKONI_URL=http://huly.local:4004 + - ACCOUNTS_URL=http://huly.local:3000 fulltext_cockroach: image: hardcoreeng/fulltext extra_hosts: - - 'host.docker.internal:host-gateway' + - 'huly.local:host-gateway' restart: unless-stopped links: - elastic @@ -334,29 +334,29 @@ services: environment: - PORT=4702 - SERVER_SECRET=secret - - DB_URL=postgresql://root@host.docker.internal:26257/defaultdb?sslmode=disable - - FULLTEXT_DB_URL=http://host.docker.internal:9200 + - DB_URL=postgresql://root@huly.local:26257/defaultdb?sslmode=disable + - FULLTEXT_DB_URL=http://huly.local:9200 - ELASTIC_INDEX_NAME=local_storage_index - STORAGE_CONFIG=${STORAGE_CONFIG} - - STATS_URL=http://host.docker.internal:4900 - - REKONI_URL=http://host.docker.internal:4004 - - ACCOUNTS_URL=http://host.docker.internal:3000 + - STATS_URL=http://huly.local:4900 + - REKONI_URL=http://huly.local:4004 + - ACCOUNTS_URL=http://huly.local:3000 print: image: hardcoreeng/print extra_hosts: - - 'host.docker.internal:host-gateway' + - 'huly.local:host-gateway' restart: unless-stopped ports: - 4005:4005 environment: - SECRET=secret - STORAGE_CONFIG=${STORAGE_CONFIG} - - STATS_URL=http://host.docker.internal:4900 - - ACCOUNTS_URL=http://host.docker.internal:3000 + - STATS_URL=http://huly.local:4900 + - ACCOUNTS_URL=http://huly.local:3000 sign: image: hardcoreeng/sign extra_hosts: - - 'host.docker.internal:host-gateway' + - 'huly.local:host-gateway' restart: unless-stopped ports: - 4006:4006 @@ -367,16 +367,16 @@ services: - SECRET=secret - MINIO_ENDPOINT=minio - MINIO_ACCESS_KEY=minioadmin - - ACCOUNTS_URL=http://host.docker.internal:3000 + - ACCOUNTS_URL=http://huly.local:3000 - MINIO_SECRET_KEY=minioadmin - CERTIFICATE_PATH=/var/cfg/certificate.p12 - SERVICE_ID=sign-service - BRANDING_PATH=/var/cfg/branding.json - - STATS_URL=http://host.docker.internal:4900 + - STATS_URL=http://huly.local:4900 # analytics: # image: hardcoreeng/analytics-collector # extra_hosts: -# - 'host.docker.internal:host-gateway' +# - 'huly.local:host-gateway' # restart: unless-stopped # ports: # - 4017:4017 @@ -386,32 +386,32 @@ services: # - MONGO_URL=${MONGO_URL} # - 'MONGO_OPTIONS={"appName":"analytics","maxPoolSize":1}' # - SERVICE_ID=analytics-collector-service -# - ACCOUNTS_URL=http://host.docker.internal:3000 -# - STATS_URL=http://host.docker.internal:4900 +# - ACCOUNTS_URL=http://huly.local:3000 +# - STATS_URL=http://huly.local:4900 aiBot: image: hardcoreeng/ai-bot ports: - 4010:4010 extra_hosts: - - 'host.docker.internal:host-gateway' + - 'huly.local:host-gateway' restart: unless-stopped environment: - SERVER_SECRET=secret - MONGO_URL=${MONGO_URL} - - ACCOUNTS_URL=http://host.docker.internal:3000 + - ACCOUNTS_URL=http://huly.local:3000 - STORAGE_CONFIG=${STORAGE_CONFIG} - FIRST_NAME=Jolie - LAST_NAME=AI - PASSWORD=password - AVATAR_PATH=./avatar.png - AVATAR_CONTENT_TYPE=.png - - STATS_URL=http://host.docker.internal:4900 -# - LOVE_ENDPOINT=http://host.docker.internal:8096 + - STATS_URL=http://huly.local:4900 +# - LOVE_ENDPOINT=http://huly.local:8096 # - OPENAI_API_KEY=token # telegram-bot: # image: hardcoreeng/telegram-bot # extra_hosts: -# - "host.docker.internal:host-gateway" +# - "huly.local:host-gateway" # restart: unless-stopped # environment: # - PORT=4020 @@ -420,9 +420,9 @@ services: # - MONGO_DB=telegram-bot # - SECRET=secret # - DOMAIN=domain -# - ACCOUNTS_URL=http://host.docker.internal:3000 +# - ACCOUNTS_URL=http://huly.local:3000 # - SERVICE_ID=telegram-bot-service -# - STATS_URL=http://host.docker.internal:4900 +# - STATS_URL=http://huly.local:4900 volumes: db: dbpg: diff --git a/dev/local-mongo/docker-compose.yaml b/dev/local-mongo/docker-compose.yaml index 22b38fdf09..5576d357c2 100644 --- a/dev/local-mongo/docker-compose.yaml +++ b/dev/local-mongo/docker-compose.yaml @@ -40,7 +40,7 @@ services: environment: - ACCOUNT_PORT=3000 - SERVER_SECRET=secret - - MONGO_URL=mongodb://host.docker.internal:27017?compressors=snappy + - MONGO_URL=mongodb://huly.local:27017?compressors=snappy - TRANSACTOR_URL=ws://transactor:3333;ws://localhost:3333 - SES_URL= - STORAGE_CONFIG=${STORAGE_CONFIG} @@ -65,7 +65,7 @@ services: - SECRET=secret - ACCOUNTS_URL=http://account:3000 - UPLOAD_URL=/files - - MONGO_URL=mongodb://host.docker.internal:27017?compressors=snappy + - MONGO_URL=mongodb://huly.local:27017?compressors=snappy - 'MONGO_OPTIONS={"appName":"collaborator","maxPoolSize":2}' - STORAGE_CONFIG=${STORAGE_CONFIG} restart: unless-stopped @@ -83,7 +83,7 @@ services: - UV_THREADPOOL_SIZE=10 - SERVER_PORT=8080 - SERVER_SECRET=secret - - MONGO_URL=mongodb://host.docker.internal:27017?compressors=snappy + - MONGO_URL=mongodb://huly.local:27017?compressors=snappy - 'MONGO_OPTIONS={"appName":"front","maxPoolSize":1}' - ACCOUNTS_URL=http://localhost:3000 - UPLOAD_URL=/files @@ -120,7 +120,7 @@ services: - SERVER_PORT=3333 - SERVER_SECRET=secret - ENABLE_COMPRESSION=true - - MONGO_URL=mongodb://host.docker.internal:27017?compressors=snappy + - MONGO_URL=mongodb://huly.local:27017?compressors=snappy - 'MONGO_OPTIONS={"appName": "transactor", "maxPoolSize": 10}' - METRICS_CONSOLE=false - METRICS_FILE=metrics.txt @@ -151,7 +151,7 @@ services: - 4005:4005 environment: - SECRET=secret - - MONGO_URL=mongodb://host.docker.internal:27017?compressors=snappy + - MONGO_URL=mongodb://huly.local:27017?compressors=snappy - 'MONGO_OPTIONS={"appName":"print","maxPoolSize":1}' - STORAGE_CONFIG=${STORAGE_CONFIG} deploy: @@ -168,7 +168,7 @@ services: - ../../services/sign/pod-sign/debug/branding.json:/var/cfg/branding.json environment: - SECRET=secret - - MONGO_URL=mongodb://host.docker.internal:27017 + - MONGO_URL=mongodb://huly.local:27017 - 'MONGO_OPTIONS={"appName":"sign","maxPoolSize":1}' - MINIO_ENDPOINT=minio - MINIO_ACCESS_KEY=minioadmin @@ -189,7 +189,7 @@ services: # environment: # - SECRET=secret # - PORT=4007 -# - MONGO_URL=mongodb://host.docker.internal:27017 +# - MONGO_URL=mongodb://huly.local:27017 # - 'MONGO_OPTIONS={"appName":"analytics","maxPoolSize":1}' # - SERVICE_ID=analytics-collector-service # - ACCOUNTS_URL=http://account:3000 @@ -202,7 +202,7 @@ services: restart: unless-stopped environment: - SERVER_SECRET=secret - - MONGO_URL=mongodb://host.docker.internal:27017 + - MONGO_URL=mongodb://huly.local:27017 - ACCOUNTS_URL=http://account:3000 - FIRST_NAME=Jolie - LAST_NAME=AI @@ -219,7 +219,7 @@ services: # environment: # - PORT=4020 # - BOT_TOKEN=token -# - MONGO_URL=mongodb://host.docker.internal:27017 +# - MONGO_URL=mongodb://huly.local:27017 # - MONGO_DB=telegram-bot # - SECRET=secret # - DOMAIN=domain diff --git a/dev/prod/public/branding.json b/dev/prod/public/branding.json index 1efd403c58..caccda656f 100644 --- a/dev/prod/public/branding.json +++ b/dev/prod/public/branding.json @@ -1,5 +1,5 @@ { - "localhost:8080": { + "huly.local:8080": { "title": "Huly", "languages": "en,ru,pt,es,zh,fr,de", "defaultLanguage": "en", @@ -28,7 +28,7 @@ } ] }, - "localhost:8087": { + "huly.local:8087": { "title": "Huly", "languages": "en,ru,pt,es,zh,fr,de", "defaultLanguage": "en", @@ -57,7 +57,7 @@ } ] }, - "localhost:8081": { + "huly.local:8081": { "title": "TraceX", "languages": "en", "defaultLanguage": "en", @@ -97,7 +97,7 @@ } ] }, - "localhost:8088": { + "huly.local:8088": { "title": "TraceX", "languages": "en", "defaultLanguage": "en", diff --git a/dev/scripts/debug_account.sh b/dev/scripts/debug_account.sh index 0581bdf248..8809d4bbd8 100755 --- a/dev/scripts/debug_account.sh +++ b/dev/scripts/debug_account.sh @@ -9,14 +9,14 @@ echo "Running account on port: ${port}" #MONGO_URL=mongodb://localhost:27017, export DB_URL="mongodb://localhost:27018" # DB_URL=postgresql://postgres:example@localhost:5432, -# DB_URL=postgresql://root@host.docker.internal:26257/defaultdb?sslmode=disable, +# DB_URL=postgresql://root@huly.local:26257/defaultdb?sslmode=disable, export SERVER_SECRET="secret" export REGION_INFO="|America;europe|" export TRANSACTOR_URL="ws://transactor:3334;ws://localhost:3334,ws://transactor-europe:3335;ws://localhost:3335;europe," export ACCOUNTS_URL="http://localhost:${port}" export ACCOUNT_PORT=${port} export FRONT_URL="http://localhost:8080" -export STATS_URL="http://host.docker.internal:4900" +export STATS_URL="http://huly.local:4900" export SES_URL= export MINIO_ACCESS_KEY="minioadmin" export MINIO_SECRET_KEY="minioadmin" diff --git a/dev/tool/src/index.ts b/dev/tool/src/index.ts index 358d39be10..7d532d0da7 100644 --- a/dev/tool/src/index.ts +++ b/dev/tool/src/index.ts @@ -279,7 +279,11 @@ export function devTool ( throw new Error(`Workspace ${workspace} not found`) } - await assignWorkspace(toolCtx, db, null, getToolToken(), email, ws.uuid, AccountRole.User) + await assignWorkspace(toolCtx, db, null, getToolToken(), { + email, + workspaceUuid: ws.uuid, + role: AccountRole.User + }) } catch (err: any) { console.error(err) } @@ -341,16 +345,12 @@ export function devTool ( undefined, true ) - await updateWorkspaceInfo( - measureCtx, - db, - brandingObj, - getToolToken(), - res.workspaceUuid, - 'create-done', + await updateWorkspaceInfo(measureCtx, db, brandingObj, getToolToken(), { + workspaceUuid: res.workspaceUuid, + event: 'create-done', version, - 100 - ) + progress: 100 + }) console.log('create-workspace done') }) @@ -372,7 +372,7 @@ export function devTool ( throw new Error(`Workspace ${workspace} not found`) } - await assignWorkspace(toolCtx, db, null, getToolToken(), email, ws.uuid, role) + await assignWorkspace(toolCtx, db, null, getToolToken(), { email, workspaceUuid: ws.uuid, role }) }) }) @@ -423,7 +423,12 @@ export function devTool ( true ) - await updateWorkspaceInfo(measureCtx, db, null, getToolToken(), info.uuid, 'upgrade-done', version, 100) + await updateWorkspaceInfo(measureCtx, db, null, getToolToken(), { + workspaceUuid: info.uuid, + event: 'upgrade-done', + version, + progress: 100 + }) console.log(metricsToString(measureCtx.metrics, 'upgrade', 60)) console.log('upgrade-workspace done') diff --git a/packages/account-client/src/client.ts b/packages/account-client/src/client.ts index dfc8e64f33..089e33001b 100644 --- a/packages/account-client/src/client.ts +++ b/packages/account-client/src/client.ts @@ -107,6 +107,9 @@ export interface AccountClient { assignWorkspace: (email: string, workspaceUuid: string, role: AccountRole) => Promise updateBackupInfo: (info: BackupStatus) => Promise updateWorkspaceRoleBySocialId: (socialKey: string, targetRole: AccountRole) => Promise + + setCookie: () => Promise + deleteCookie: () => Promise } /** @public */ @@ -120,10 +123,12 @@ export function getClient (accountsUrl?: string, token?: string): AccountClient interface Request { method: string - params: any[] + params: Record } class AccountClientImpl implements AccountClient { + private readonly request: RequestInit + constructor ( private readonly url: string, private readonly token?: string @@ -131,6 +136,18 @@ class AccountClientImpl implements AccountClient { if (url === '') { throw new Error('Accounts url not specified') } + + this.request = { + keepalive: true, + headers: { + ...(this.token === undefined + ? {} + : { + Authorization: 'Bearer ' + this.token + }) + }, + credentials: 'include' + } } async getProviders (): Promise { @@ -143,16 +160,12 @@ class AccountClientImpl implements AccountClient { private async rpc(request: Request): Promise { const response = await fetch(this.url, { - method: 'POST', - keepalive: true, + ...this.request, headers: { - ...(this.token === undefined - ? {} - : { - Authorization: 'Bearer ' + this.token - }), + ...this.request.headers, 'Content-Type': 'application/json' }, + method: 'POST', body: JSON.stringify(request) }) @@ -183,7 +196,7 @@ class AccountClientImpl implements AccountClient { async getUserWorkspaces (): Promise { const request = { method: 'getUserWorkspaces' as const, - params: [] + params: {} } return (await this.rpc(request)).map((ws) => this.flattenStatus(ws)) @@ -196,7 +209,7 @@ class AccountClientImpl implements AccountClient { ): Promise { const request = { method: 'selectWorkspace' as const, - params: [workspaceUrl, kind, externalRegions] + params: { workspaceUrl, kind, externalRegions } } return await this.rpc(request) @@ -205,7 +218,7 @@ class AccountClientImpl implements AccountClient { async validateOtp (email: string, code: string): Promise { const request = { method: 'validateOtp' as const, - params: [email, code] + params: { email, code } } return await this.rpc(request) @@ -214,7 +227,7 @@ class AccountClientImpl implements AccountClient { async loginOtp (email: string): Promise { const request = { method: 'loginOtp' as const, - params: [email] + params: { email } } return await this.rpc(request) @@ -223,7 +236,7 @@ class AccountClientImpl implements AccountClient { async getLoginInfoByToken (): Promise { const request = { method: 'getLoginInfoByToken' as const, - params: [] + params: {} } return await this.rpc(request) @@ -232,7 +245,7 @@ class AccountClientImpl implements AccountClient { async restorePassword (password: string): Promise { const request = { method: 'restorePassword' as const, - params: [password] + params: { password } } return await this.rpc(request) @@ -241,7 +254,7 @@ class AccountClientImpl implements AccountClient { async confirm (): Promise { const request = { method: 'confirm' as const, - params: [] + params: {} } return await this.rpc(request) @@ -250,7 +263,7 @@ class AccountClientImpl implements AccountClient { async requestPasswordReset (email: string): Promise { const request = { method: 'requestPasswordReset' as const, - params: [email] + params: { email } } await this.rpc(request) @@ -259,7 +272,7 @@ class AccountClientImpl implements AccountClient { async sendInvite (email: string, role: AccountRole): Promise { const request = { method: 'sendInvite' as const, - params: [email, role] + params: { email, role } } await this.rpc(request) @@ -277,7 +290,7 @@ class AccountClientImpl implements AccountClient { async leaveWorkspace (account: string): Promise { const request = { method: 'leaveWorkspace' as const, - params: [account] + params: { account } } return await this.rpc(request) @@ -286,7 +299,7 @@ class AccountClientImpl implements AccountClient { async changeUsername (first: string, last: string): Promise { const request = { method: 'changeUsername' as const, - params: [first, last] + params: { first, last } } await this.rpc(request) @@ -295,7 +308,7 @@ class AccountClientImpl implements AccountClient { async changePassword (oldPassword: string, newPassword: string): Promise { const request = { method: 'changePassword' as const, - params: [oldPassword, newPassword] + params: { oldPassword, newPassword } } await this.rpc(request) @@ -310,7 +323,7 @@ class AccountClientImpl implements AccountClient { ): Promise { const request = { method: 'signUpJoin' as const, - params: [email, password, first, last, inviteId] + params: { email, password, first, last, inviteId } } return await this.rpc(request) @@ -319,7 +332,7 @@ class AccountClientImpl implements AccountClient { async join (email: string, password: string, inviteId: string): Promise { const request = { method: 'join' as const, - params: [email, password, inviteId] + params: { email, password, inviteId } } return await this.rpc(request) @@ -334,7 +347,7 @@ class AccountClientImpl implements AccountClient { ): Promise { const request = { method: 'createInviteLink' as const, - params: [exp, emailMask, limit, role, personId] + params: { exp, emailMask, limit, role, personId } } return await this.rpc(request) @@ -343,7 +356,7 @@ class AccountClientImpl implements AccountClient { async checkJoin (inviteId: string): Promise { const request = { method: 'checkJoin' as const, - params: [inviteId] + params: { inviteId } } return await this.rpc(request) @@ -352,7 +365,7 @@ class AccountClientImpl implements AccountClient { async getWorkspaceInfo (updateLastVisit: boolean = false): Promise { const request = { method: 'getWorkspaceInfo' as const, - params: updateLastVisit ? [true] : [] + params: updateLastVisit ? { updateLastVisit: true } : {} } return this.flattenStatus(await this.rpc(request)) @@ -361,34 +374,34 @@ class AccountClientImpl implements AccountClient { async getRegionInfo (): Promise { const request = { method: 'getRegionInfo' as const, - params: [] + params: {} } return await this.rpc(request) } - async createWorkspace (name: string, region?: string): Promise { + async createWorkspace (workspaceName: string, region?: string): Promise { const request = { method: 'createWorkspace' as const, - params: [name, region] + params: { workspaceName, region } } return await this.rpc(request) } - async signUpOtp (email: string, first: string, last: string): Promise { + async signUpOtp (email: string, firstName: string, lastName: string): Promise { const request = { method: 'signUpOtp' as const, - params: [email, first, last] + params: { email, firstName, lastName } } return await this.rpc(request) } - async signUp (email: string, password: string, first: string, last: string): Promise { + async signUp (email: string, password: string, firstName: string, lastName: string): Promise { const request = { method: 'signUp' as const, - params: [email, password, first, last] + params: { email, password, firstName, lastName } } return await this.rpc(request) @@ -397,7 +410,7 @@ class AccountClientImpl implements AccountClient { async login (email: string, password: string): Promise { const request = { method: 'login' as const, - params: [email, password] + params: { email, password } } return await this.rpc(request) @@ -406,7 +419,7 @@ class AccountClientImpl implements AccountClient { async getPerson (): Promise { const request = { method: 'getPerson' as const, - params: [] + params: {} } return await this.rpc(request) @@ -415,7 +428,7 @@ class AccountClientImpl implements AccountClient { async getPersonInfo (account: PersonUuid): Promise { const request = { method: 'getPersonInfo' as const, - params: [account] + params: { account } } return await this.rpc(request) @@ -424,7 +437,7 @@ class AccountClientImpl implements AccountClient { async getSocialIds (): Promise { const request = { method: 'getSocialIds' as const, - params: [] + params: {} } return await this.rpc(request) @@ -433,7 +446,7 @@ class AccountClientImpl implements AccountClient { async workerHandshake (region: string, version: Data, operation: WorkspaceOperation): Promise { const request = { method: 'workerHandshake' as const, - params: [region, version, operation] + params: { region, version, operation } } await this.rpc(request) @@ -446,7 +459,7 @@ class AccountClientImpl implements AccountClient { ): Promise { const request = { method: 'getPendingWorkspace' as const, - params: [region, version, operation] + params: { region, version, operation } } const result = await this.rpc(request) @@ -458,7 +471,7 @@ class AccountClientImpl implements AccountClient { } async updateWorkspaceInfo ( - wsUuid: string, + workspaceUuid: string, event: string, version: Data, progress: number, @@ -466,7 +479,7 @@ class AccountClientImpl implements AccountClient { ): Promise { const request = { method: 'updateWorkspaceInfo' as const, - params: [wsUuid, event, version, progress, message] + params: { workspaceUuid, event, version, progress, message } } await this.rpc(request) @@ -475,16 +488,16 @@ class AccountClientImpl implements AccountClient { async getWorkspaceMembers (): Promise { const request = { method: 'getWorkspaceMembers' as const, - params: [] + params: {} } return await this.rpc(request) } - async updateWorkspaceRole (account: string, role: AccountRole): Promise { + async updateWorkspaceRole (targetAccount: string, targetRole: AccountRole): Promise { const request = { method: 'updateWorkspaceRole' as const, - params: [account, role] + params: { targetAccount, targetRole } } await this.rpc(request) @@ -493,7 +506,7 @@ class AccountClientImpl implements AccountClient { async updateWorkspaceName (name: string): Promise { const request = { method: 'updateWorkspaceName' as const, - params: [name] + params: { name } } await this.rpc(request) @@ -502,7 +515,7 @@ class AccountClientImpl implements AccountClient { async deleteWorkspace (): Promise { const request = { method: 'deleteWorkspace' as const, - params: [] + params: {} } await this.rpc(request) @@ -511,7 +524,7 @@ class AccountClientImpl implements AccountClient { async findPerson (socialString: string): Promise { const request = { method: 'findPerson' as const, - params: [socialString] + params: { socialString } } return await this.rpc(request) @@ -520,7 +533,7 @@ class AccountClientImpl implements AccountClient { async listWorkspaces (region?: string | null, mode: WorkspaceMode | null = null): Promise { const request = { method: 'listWorkspaces' as const, - params: [region, mode] + params: { region, mode } } return ((await this.rpc(request)) ?? []).map((ws) => this.flattenStatus(ws)) @@ -533,16 +546,16 @@ class AccountClientImpl implements AccountClient { ): Promise { const request = { method: 'performWorkspaceOperation' as const, - params: [workspaceId, event, ...params] + params: { workspaceId, event, params } } return await this.rpc(request) } - async updateBackupInfo (info: BackupStatus): Promise { + async updateBackupInfo (backupInfo: BackupStatus): Promise { const request = { method: 'updateBackupInfo' as const, - params: [info] + params: { backupInfo } } await this.rpc(request) @@ -551,7 +564,7 @@ class AccountClientImpl implements AccountClient { async assignWorkspace (email: string, workspaceUuid: string, role: AccountRole): Promise { const request = { method: 'assignWorkspace' as const, - params: [email, workspaceUuid, role] + params: { email, workspaceUuid, role } } await this.rpc(request) @@ -560,11 +573,35 @@ class AccountClientImpl implements AccountClient { async updateWorkspaceRoleBySocialId (socialKey: string, targetRole: AccountRole): Promise { const request = { method: 'updateWorkspaceRoleBySocialId' as const, - params: [socialKey, targetRole] + params: { socialKey, targetRole } } await this.rpc(request) } + + async setCookie (): Promise { + const url = concatLink(this.url, '/cookie') + const response = await fetch(url, { ...this.request, method: 'PUT' }) + + if (!response.ok) { + const result = await response.json() + if (result.error != null) { + throw new PlatformError(result.error) + } + } + } + + async deleteCookie (): Promise { + const url = concatLink(this.url, '/cookie') + const response = await fetch(url, { ...this.request, method: 'DELETE' }) + + if (!response.ok) { + const result = await response.json() + if (result.error != null) { + throw new PlatformError(result.error) + } + } + } } async function retry (retries: number, op: () => Promise, delay: number = 100): Promise { diff --git a/packages/api-client/package.json b/packages/api-client/package.json index 52baa57bd7..7666e529d9 100644 --- a/packages/api-client/package.json +++ b/packages/api-client/package.json @@ -39,7 +39,8 @@ "ts-node": "^10.8.0", "@types/node": "~20.11.16", "@types/jest": "^29.5.5", - "@types/ws": "^8.5.11" + "@types/ws": "^8.5.11", + "@types/snappyjs": "^0.7.1" }, "dependencies": { "@hcengineering/core": "^0.6.32", @@ -48,7 +49,8 @@ "@hcengineering/collaborator-client": "^0.6.4", "@hcengineering/account-client": "^0.6.0", "@hcengineering/platform": "^0.6.11", - "@hcengineering/text": "^0.6.5" + "@hcengineering/text": "^0.6.5", + "snappyjs": "^0.7.0" }, "repository": "https://github.com/hcengineering/platform", "publishConfig": { diff --git a/packages/api-client/src/index.ts b/packages/api-client/src/index.ts index 2dd51ba8f5..911f155e01 100644 --- a/packages/api-client/src/index.ts +++ b/packages/api-client/src/index.ts @@ -17,3 +17,4 @@ export * from './client' export * from './markup/types' export * from './socket' export * from './types' +export * from './rest' diff --git a/packages/api-client/src/rest.ts b/packages/api-client/src/rest.ts new file mode 100644 index 0000000000..23648ca2d1 --- /dev/null +++ b/packages/api-client/src/rest.ts @@ -0,0 +1,130 @@ +// +// Copyright © 2025 Hardcore Engineering Inc. +// +// Licensed under the Eclipse Public License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. You may +// obtain a copy of the License at https://www.eclipse.org/legal/epl-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// +// See the License for the specific language governing permissions and +// limitations under the License. +// + +import { + type Account, + type Class, + type Doc, + type DocumentQuery, + type FindOptions, + type FindResult, + type Ref, + type Storage, + type Tx, + type TxResult, + type WithLookup, + concatLink +} from '@hcengineering/core' + +import { PlatformError, unknownError } from '@hcengineering/platform' + +import { uncompress } from 'snappyjs' + +export interface RestClient extends Storage { + getAccount: () => Promise + + findOne: ( + _class: Ref>, + query: DocumentQuery, + options?: FindOptions + ) => Promise | undefined> +} + +export async function createRestClient (endpoint: string, workspaceId: string, token: string): Promise { + return new RestClientImpl(endpoint, workspaceId, token) +} + +class RestClientImpl implements RestClient { + constructor ( + readonly endpoint: string, + readonly workspace: string, + readonly token: string + ) {} + + async findAll( + _class: Ref>, + query: DocumentQuery, + options?: FindOptions + ): Promise> { + const params = new URLSearchParams() + params.append('class', _class) + if (query !== undefined && Object.keys(query).length > 0) { + params.append('query', JSON.stringify(query)) + } + if (options !== undefined && Object.keys(options).length > 0) { + params.append('options', JSON.stringify(options)) + } + const response = await fetch(concatLink(this.endpoint, `/api/v1/find-all/${this.workspace}?${params.toString()}`), { + method: 'GET', + headers: { + 'Content-Type': 'application/json', + Authorization: 'Bearer ' + this.token, + 'accept-encoding': 'snappy, gzip' + }, + keepalive: true + }) + if (!response.ok) { + throw new PlatformError(unknownError(response.statusText)) + } + const encoding = response.headers.get('content-encoding') + if (encoding === 'snappy') { + const buffer = await response.arrayBuffer() + const decompressed = uncompress(buffer) + const decoder = new TextDecoder() + const jsonString = decoder.decode(decompressed) + return JSON.parse(jsonString) as FindResult + } + return (await response.json()) as FindResult + } + + async getAccount (): Promise { + const response = await fetch(concatLink(this.endpoint, `/api/v1/account/${this.workspace}`), { + method: 'GET', + headers: { + 'Content-Type': 'application/json', + Authorization: 'Bearer ' + this.token + }, + keepalive: true + }) + if (!response.ok) { + throw new PlatformError(unknownError(response.statusText)) + } + return (await response.json()) as Account + } + + async findOne( + _class: Ref>, + query: DocumentQuery, + options?: FindOptions + ): Promise | undefined> { + return (await this.findAll(_class, query, { ...options, limit: 1 })).shift() + } + + async tx (tx: Tx): Promise { + const response = await fetch(concatLink(this.endpoint, `/api/v1/tx/${this.workspace}`), { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + Authorization: 'Bearer ' + this.token + }, + keepalive: true, + body: JSON.stringify(tx) + }) + if (!response.ok) { + throw new PlatformError(unknownError(response.statusText)) + } + return (await response.json()) as TxResult + } +} diff --git a/packages/core/src/measurements/metrics.ts b/packages/core/src/measurements/metrics.ts index 09ab8fb7e0..0fe3267f3d 100644 --- a/packages/core/src/measurements/metrics.ts +++ b/packages/core/src/measurements/metrics.ts @@ -234,6 +234,28 @@ function toString (name: string, m: Metrics, offset: number, length: number): st return r } +function toJson (m: Metrics): any { + const obj: any = { + $total: m.value, + $ops: m.operations + } + if (m.operations > 1) { + obj.avg = Math.round((m.value / (m.operations > 0 ? m.operations : 1)) * 100) / 100 + } + if (Object.keys(m.params).length > 0) { + obj.params = m.params + } + for (const [k, v] of Object.entries(m.measurements ?? {})) { + obj[ + `${k} ${v.value} ${v.operations} ${ + v.operations > 1 ? Math.round((v.value / (v.operations > 0 ? m.operations : 1)) * 100) / 100 : '' + }` + ] = toJson(v) + } + + return obj +} + /** * @public */ @@ -241,6 +263,10 @@ export function metricsToString (metrics: Metrics, name = 'System', length: numb return toString(name, metricsAggregate(metrics, 50, true), 0, length) } +export function metricsToJson (metrics: Metrics): any { + return toJson(metricsAggregate(metrics)) +} + function printMetricsParamsRows ( params: Record>, offset: number diff --git a/packages/ui/src/components/Component.svelte b/packages/ui/src/components/Component.svelte index e83560e83e..4ea4888512 100644 --- a/packages/ui/src/components/Component.svelte +++ b/packages/ui/src/components/Component.svelte @@ -73,7 +73,7 @@ .then((res) => { if (current === counter) { Ctor = res - _props = props + _props = filterDefaultUndefined(props, props) loading = false } }) @@ -85,11 +85,11 @@ } else { loading = false Ctor = component - _props = props + _props = filterDefaultUndefined(props, props) } } else { Ctor = _is - _props = props + _props = filterDefaultUndefined(props, props) } } diff --git a/plugins/attachment-resources/src/components/AttachmentImagePreview.svelte b/plugins/attachment-resources/src/components/AttachmentImagePreview.svelte index 7a8c2bd7fd..53db098025 100644 --- a/plugins/attachment-resources/src/components/AttachmentImagePreview.svelte +++ b/plugins/attachment-resources/src/components/AttachmentImagePreview.svelte @@ -42,7 +42,7 @@ $: dimensions = getDimensions(value, size) function getDimensions (value: Attachment, size: AttachmentImageSize): Dimensions { - if (size === 'auto') { + if (size === 'auto' || size == null) { return { width: 300, height: 300, diff --git a/plugins/guest-resources/src/connect.ts b/plugins/guest-resources/src/connect.ts index a6a099f126..ffad8416a5 100644 --- a/plugins/guest-resources/src/connect.ts +++ b/plugins/guest-resources/src/connect.ts @@ -15,20 +15,14 @@ import { setCurrentEmployee, type Employee } from '@hcengineering/contact' import login, { loginId } from '@hcengineering/login' import { getMetadata, getResource, setMetadata } from '@hcengineering/platform' import presentation, { - closeClient, loadServerConfig, refreshClient, setClient, setPresentationCookie, upgradeDownloadProgress } from '@hcengineering/presentation' -import { - desktopPlatform, - fetchMetadataLocalStorage, - getCurrentLocation, - navigate, - setMetadataLocalStorage -} from '@hcengineering/ui' +import { desktopPlatform, getCurrentLocation, navigate } from '@hcengineering/ui' +import { logOut } from '@hcengineering/workbench' import { writable, get } from 'svelte/store' export const versionError = writable(undefined) @@ -48,7 +42,6 @@ export async function connect (title: string): Promise { }) return } - setMetadata(presentation.metadata.Token, token) const selectWorkspace = await getResource(login.function.SelectWorkspace) const workspaceLoginInfo = (await selectWorkspace(wsUrl, token))[1] @@ -57,10 +50,8 @@ export async function connect (title: string): Promise { `Error selecting workspace ${wsUrl}. There might be something wrong with the token. Please try to log in again.` ) // something went wrong with selecting workspace with the selected token - clearMetadata(wsUrl) - navigate({ - path: [loginId] - }) + await logOut() + navigate({ path: [loginId] }) return } @@ -126,10 +117,11 @@ export async function connect (title: string): Promise { location.reload() }, onUnauthorized: () => { - clearMetadata(wsUrl) - navigate({ - path: [loginId], - query: {} + void logOut().then(() => { + navigate({ + path: [loginId], + query: {} + }) }) }, // We need to refresh all active live queries and clear old queries. @@ -240,22 +232,3 @@ export async function connect (title: string): Promise { return _client } - -function clearMetadata (ws: string): void { - const tokens = fetchMetadataLocalStorage(login.metadata.LoginTokensV2) - if (tokens !== null) { - const loc = getCurrentLocation() - // eslint-disable-next-line - delete tokens[loc.path[1]] - setMetadataLocalStorage(login.metadata.LoginTokensV2, tokens) - } - const currentWorkspace = getMetadata(presentation.metadata.WorkspaceUuid) - if (currentWorkspace !== undefined) { - setPresentationCookie('', currentWorkspace) - } - - setMetadata(presentation.metadata.Token, null) - setMetadataLocalStorage(login.metadata.LastToken, null) - setMetadataLocalStorage(login.metadata.LoginAccount, null) - void closeClient() -} diff --git a/plugins/guest-resources/src/utils.ts b/plugins/guest-resources/src/utils.ts index 7c98303d1c..30e15b4653 100644 --- a/plugins/guest-resources/src/utils.ts +++ b/plugins/guest-resources/src/utils.ts @@ -1,9 +1,9 @@ import client from '@hcengineering/client' -import { type Doc } from '@hcengineering/core' +import { type Doc, AccountRole } from '@hcengineering/core' import login from '@hcengineering/login' -import { getMetadata, getResource, setMetadata } from '@hcengineering/platform' +import { getMetadata, getResource } from '@hcengineering/platform' import presentation from '@hcengineering/presentation' -import { fetchMetadataLocalStorage, getCurrentLocation, navigate } from '@hcengineering/ui' +import { getCurrentLocation, navigate } from '@hcengineering/ui' import view from '@hcengineering/view' import { getObjectLinkFragment } from '@hcengineering/view-resources' import { workbenchId } from '@hcengineering/workbench' @@ -11,10 +11,15 @@ import { workbenchId } from '@hcengineering/workbench' export async function checkAccess (doc: Doc): Promise { const loc = getCurrentLocation() const ws = loc.path[1] - const tokens: Record = fetchMetadataLocalStorage(login.metadata.LoginTokensV2) ?? {} - const token = tokens[ws] + + const selectWorkspace = await getResource(login.function.SelectWorkspace) + const wsLoginInfo = (await selectWorkspace(ws, null))[1] + if (wsLoginInfo === undefined || wsLoginInfo.role === AccountRole.DocGuest) return + + const token = wsLoginInfo.token const endpoint = getMetadata(presentation.metadata.Endpoint) if (token === undefined || endpoint === undefined) return + const clientFactory = await getResource(client.function.GetClient) const _client = await clientFactory(token, endpoint) @@ -28,7 +33,7 @@ export async function checkAccess (doc: Doc): Promise { loc.path[0] = workbenchId loc.path[1] = ws // We have access, let's set correct tokens and redirect) - setMetadata(presentation.metadata.Token, token) + // setMetadata(presentation.metadata.Token, token) navigate(loc) } } diff --git a/plugins/login-resources/src/actions.ts b/plugins/login-resources/src/actions.ts index 7dbb32e473..36905f800e 100644 --- a/plugins/login-resources/src/actions.ts +++ b/plugins/login-resources/src/actions.ts @@ -1,7 +1,6 @@ import { goTo } from './utils' import login from './plugin' import { type BottomAction } from '.' -import { setMetadataLocalStorage } from '@hcengineering/ui' import { setMetadata } from '@hcengineering/platform' import presentation from '@hcengineering/presentation' @@ -20,7 +19,6 @@ export const loginAction: BottomAction = { page: 'login', func: () => { setMetadata(presentation.metadata.Token, null) - setMetadataLocalStorage(login.metadata.LastToken, null) goTo('login', true) } } diff --git a/plugins/login-resources/src/components/Auth.svelte b/plugins/login-resources/src/components/Auth.svelte index d191e14bf2..25d589a004 100644 --- a/plugins/login-resources/src/components/Auth.svelte +++ b/plugins/login-resources/src/components/Auth.svelte @@ -1,24 +1,21 @@