From 7956a92bec236cf9dd383408b6ee62d232314f0d Mon Sep 17 00:00:00 2001 From: Andras Schmelczer Date: Sat, 7 Jun 2025 21:33:47 +0100 Subject: [PATCH] Remove openapi from frontend --- backend/sync_server/src/errors.rs | 17 +- frontend/package-lock.json | 245 +------ frontend/sync-client/package.json | 4 +- .../src/services/connection-status.ts | 7 +- .../sync-client/src/services/sync-service.ts | 277 +++----- .../src/services/types/DocumentVersion.ts | 2 +- .../src/services/types/SerializedError.ts | 3 + .../src/services/types/http-api.ts | 648 ------------------ .../sync-client/src/sync-operations/syncer.ts | 4 +- .../sync-operations/unrestricted-syncer.ts | 12 +- 10 files changed, 157 insertions(+), 1062 deletions(-) create mode 100644 frontend/sync-client/src/services/types/SerializedError.ts delete mode 100644 frontend/sync-client/src/services/types/http-api.ts diff --git a/backend/sync_server/src/errors.rs b/backend/sync_server/src/errors.rs index aa1421ef..987c3011 100644 --- a/backend/sync_server/src/errors.rs +++ b/backend/sync_server/src/errors.rs @@ -8,6 +8,7 @@ use axum::{ use log::{debug, error}; use serde::Serialize; use thiserror::Error; +use ts_rs::TS; #[derive(Error, Debug)] pub enum SyncServerError { @@ -43,8 +44,11 @@ impl SyncServerError { } } -#[derive(Debug, Clone, Serialize)] +#[derive(TS, Debug, Clone, Serialize)] +#[serde(rename_all = "camelCase")] +#[ts(export)] pub struct SerializedError { + pub error_type: &'static str, pub message: String, pub causes: Vec, } @@ -88,6 +92,17 @@ impl From<&anyhow::Error> for SerializedError { } SerializedError { + error_type: error.downcast_ref::().map_or( + "UnknownError", + |e| match e { + SyncServerError::InitError(_) => "InitError", + SyncServerError::ClientError(_) => "ClientError", + SyncServerError::ServerError(_) => "ServerError", + SyncServerError::NotFound(_) => "NotFound", + SyncServerError::Unauthenticated(_) => "Unauthenticated", + SyncServerError::PermissionDeniedError(_) => "PermissionDeniedError", + }, + ), message: error.to_string(), causes, } diff --git a/frontend/package-lock.json b/frontend/package-lock.json index a7b5cc01..a2220c54 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -43,6 +43,7 @@ "version": "7.26.2", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.26.2.tgz", "integrity": "sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ==", + "dev": true, "license": "MIT", "dependencies": { "@babel/helper-validator-identifier": "^7.25.9", @@ -204,6 +205,7 @@ "version": "7.25.9", "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.25.9.tgz", "integrity": "sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==", + "dev": true, "license": "MIT", "engines": { "node": ">=6.9.0" @@ -1620,76 +1622,6 @@ "url": "https://opencollective.com/parcel" } }, - "node_modules/@redocly/ajv": { - "version": "8.11.2", - "resolved": "https://registry.npmjs.org/@redocly/ajv/-/ajv-8.11.2.tgz", - "integrity": "sha512-io1JpnwtIcvojV7QKDUSIuMN/ikdOUd1ReEnUnMKGfDVridQZ31J0MmIuqwuRjWDZfmvr+Q0MqCcfHM2gTivOg==", - "license": "MIT", - "dependencies": { - "fast-deep-equal": "^3.1.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js-replace": "^1.0.1" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/@redocly/ajv/node_modules/json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "license": "MIT" - }, - "node_modules/@redocly/config": { - "version": "0.22.1", - "resolved": "https://registry.npmjs.org/@redocly/config/-/config-0.22.1.tgz", - "integrity": "sha512-1CqQfiG456v9ZgYBG9xRQHnpXjt8WoSnDwdkX6gxktuK69v2037hTAR1eh0DGIqpZ1p4k82cGH8yTNwt7/pI9g==", - "license": "MIT" - }, - "node_modules/@redocly/openapi-core": { - "version": "1.34.0", - "resolved": "https://registry.npmjs.org/@redocly/openapi-core/-/openapi-core-1.34.0.tgz", - "integrity": "sha512-Ji00EiLQRXq0pJIz5pAjGF9MfQvQVsQehc6uIis6sqat8tG/zh25Zi64w6HVGEDgJEzUeq/CuUlD0emu3Hdaqw==", - "license": "MIT", - "dependencies": { - "@redocly/ajv": "^8.11.2", - "@redocly/config": "^0.22.0", - "colorette": "^1.2.0", - "https-proxy-agent": "^7.0.5", - "js-levenshtein": "^1.1.6", - "js-yaml": "^4.1.0", - "minimatch": "^5.0.1", - "pluralize": "^8.0.0", - "yaml-ast-parser": "0.0.43" - }, - "engines": { - "node": ">=18.17.0", - "npm": ">=9.5.0" - } - }, - "node_modules/@redocly/openapi-core/node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/@redocly/openapi-core/node_modules/minimatch": { - "version": "5.1.6", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", - "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", - "license": "ISC", - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/@sinclair/typebox": { "version": "0.27.8", "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz", @@ -2375,15 +2307,6 @@ "node": ">=8.9" } }, - "node_modules/agent-base": { - "version": "7.1.3", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.3.tgz", - "integrity": "sha512-jRR5wdylq8CkOe6hei19GGZnxM6rBGwFl3Bg0YItGDimvjGtAvdZk4Pu6Cl4u4Igsws4a1fd1Vq3ezrhn4KmFw==", - "license": "MIT", - "engines": { - "node": ">= 14" - } - }, "node_modules/ajv": { "version": "6.12.6", "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", @@ -2453,15 +2376,6 @@ "ajv": "^6.9.1" } }, - "node_modules/ansi-colors": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz", - "integrity": "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==", - "license": "MIT", - "engines": { - "node": ">=6" - } - }, "node_modules/ansi-escapes": { "version": "4.3.2", "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", @@ -2522,6 +2436,7 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true, "license": "Python-2.0" }, "node_modules/async": { @@ -2882,12 +2797,6 @@ "node": ">=8" } }, - "node_modules/change-case": { - "version": "5.4.4", - "resolved": "https://registry.npmjs.org/change-case/-/change-case-5.4.4.tgz", - "integrity": "sha512-HRQyTk2/YPEkt9TnUPbOpr64Uw3KOicFWPVBb+xiHvd6eBx/qPr9xqfBFDT8P2vWsvvz4jbEkfDe71W3VyNu2w==", - "license": "MIT" - }, "node_modules/char-regex": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz", @@ -3015,12 +2924,6 @@ "dev": true, "license": "MIT" }, - "node_modules/colorette": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/colorette/-/colorette-1.4.0.tgz", - "integrity": "sha512-Y2oEozpomLn7Q3HFP7dpww7AtMJplbM9lGZP6RDfHqmbeRjiwRg4n6VM6j4KLmRke85uWEI7JqF17f3pqdRA0g==", - "license": "MIT" - }, "node_modules/commander": { "version": "2.20.3", "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", @@ -3169,6 +3072,7 @@ "version": "4.4.0", "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz", "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==", + "dev": true, "license": "MIT", "dependencies": { "ms": "^2.1.3" @@ -3671,6 +3575,7 @@ "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true, "license": "MIT" }, "node_modules/fast-glob": { @@ -4146,19 +4051,6 @@ "dev": true, "license": "MIT" }, - "node_modules/https-proxy-agent": { - "version": "7.0.6", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", - "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==", - "license": "MIT", - "dependencies": { - "agent-base": "^7.1.2", - "debug": "4" - }, - "engines": { - "node": ">= 14" - } - }, "node_modules/human-signals": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", @@ -4246,18 +4138,6 @@ "node": ">=0.8.19" } }, - "node_modules/index-to-position": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/index-to-position/-/index-to-position-1.0.0.tgz", - "integrity": "sha512-sCO7uaLVhRJ25vz1o8s9IFM3nVS4DkuQnyjMwiQPKvQuBYBDmb8H7zx8ki7nVh4HJQOdVWebyvLE0qt+clruxA==", - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/inflight": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", @@ -5076,25 +4956,18 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/js-levenshtein": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/js-levenshtein/-/js-levenshtein-1.1.6.tgz", - "integrity": "sha512-X2BB11YZtrRqY4EnQcLX5Rh373zbK4alC1FW7D7MBhL2gtcC17cTnr6DmfHZeS0s2rTHjUTMMHfG7gO8SSdw+g==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true, "license": "MIT" }, "node_modules/js-yaml": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, "license": "MIT", "dependencies": { "argparse": "^2.0.1" @@ -5515,6 +5388,7 @@ "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, "license": "MIT" }, "node_modules/nanoid": { @@ -5676,82 +5550,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/openapi-fetch": { - "version": "0.14.0", - "resolved": "https://registry.npmjs.org/openapi-fetch/-/openapi-fetch-0.14.0.tgz", - "integrity": "sha512-PshIdm1NgdLvb05zp8LqRQMNSKzIlPkyMxYFxwyHR+UlKD4t2nUjkDhNxeRbhRSEd3x5EUNh2w5sJYwkhOH4fg==", - "license": "MIT", - "dependencies": { - "openapi-typescript-helpers": "^0.0.15" - } - }, - "node_modules/openapi-typescript": { - "version": "7.6.1", - "resolved": "https://registry.npmjs.org/openapi-typescript/-/openapi-typescript-7.6.1.tgz", - "integrity": "sha512-F7RXEeo/heF3O9lOXo2bNjCOtfp7u+D6W3a3VNEH2xE6v+fxLtn5nq0uvUcA1F5aT+CMhNeC5Uqtg5tlXFX/ag==", - "license": "MIT", - "dependencies": { - "@redocly/openapi-core": "^1.28.0", - "ansi-colors": "^4.1.3", - "change-case": "^5.4.4", - "parse-json": "^8.1.0", - "supports-color": "^9.4.0", - "yargs-parser": "^21.1.1" - }, - "bin": { - "openapi-typescript": "bin/cli.js" - }, - "peerDependencies": { - "typescript": "^5.x" - } - }, - "node_modules/openapi-typescript-helpers": { - "version": "0.0.15", - "resolved": "https://registry.npmjs.org/openapi-typescript-helpers/-/openapi-typescript-helpers-0.0.15.tgz", - "integrity": "sha512-opyTPaunsklCBpTK8JGef6mfPhLSnyy5a0IN9vKtx3+4aExf+KxEqYwIy3hqkedXIB97u357uLMJsOnm3GVjsw==", - "license": "MIT" - }, - "node_modules/openapi-typescript/node_modules/parse-json": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-8.2.0.tgz", - "integrity": "sha512-eONBZy4hm2AgxjNFd8a4nyDJnzUAH0g34xSQAwWEVGCjdZ4ZL7dKZBfq267GWP/JaS9zW62Xs2FeAdDvpHHJGQ==", - "license": "MIT", - "dependencies": { - "@babel/code-frame": "^7.26.2", - "index-to-position": "^1.0.0", - "type-fest": "^4.37.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/openapi-typescript/node_modules/supports-color": { - "version": "9.4.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-9.4.0.tgz", - "integrity": "sha512-VL+lNrEoIXww1coLPOmiEmK/0sGigko5COxI09KzHc2VJXJsQ37UaQ+8quuxjDeA7+KnLGTWRyOXSLLR2Wb4jw==", - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/supports-color?sponsor=1" - } - }, - "node_modules/openapi-typescript/node_modules/type-fest": { - "version": "4.38.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.38.0.tgz", - "integrity": "sha512-2dBz5D5ycHIoliLYLi0Q2V7KRaDlH0uWIvmk7TYlAg5slqwiPv1ezJdZm1QEM0xgk29oYWMCbIG7E6gHpvChlg==", - "license": "(MIT OR CC0-1.0)", - "engines": { - "node": ">=16" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/optionator": { "version": "0.9.4", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", @@ -5913,6 +5711,7 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "dev": true, "license": "ISC" }, "node_modules/picomatch": { @@ -6007,15 +5806,6 @@ "node": ">=8" } }, - "node_modules/pluralize": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-8.0.0.tgz", - "integrity": "sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==", - "license": "MIT", - "engines": { - "node": ">=4" - } - }, "node_modules/postcss": { "version": "8.5.3", "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.3.tgz", @@ -6333,6 +6123,7 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" @@ -7276,6 +7067,7 @@ "version": "5.8.3", "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.3.tgz", "integrity": "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==", + "dev": true, "license": "Apache-2.0", "bin": { "tsc": "bin/tsc", @@ -7366,12 +7158,6 @@ "punycode": "^2.1.0" } }, - "node_modules/uri-js-replace": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/uri-js-replace/-/uri-js-replace-1.0.1.tgz", - "integrity": "sha512-W+C9NWNLFOoBI2QWDp4UT9pv65r2w5Cx+3sTYFvtMdDBxkKt1syCqsUdSFAChbEe1uK5TfS04wt/nGwmaeIQ0g==", - "license": "MIT" - }, "node_modules/url": { "version": "0.11.4", "resolved": "https://registry.npmjs.org/url/-/url-0.11.4.tgz", @@ -7814,12 +7600,6 @@ "dev": true, "license": "ISC" }, - "node_modules/yaml-ast-parser": { - "version": "0.0.43", - "resolved": "https://registry.npmjs.org/yaml-ast-parser/-/yaml-ast-parser-0.0.43.tgz", - "integrity": "sha512-2PTINUwsRqSd+s8XxKaJWQlUuEMHJQyEuh2edBbW8KNJz0SJPwUSD2zRWqezFEdN7IzAgeuYHFUCF7o8zRdZ0A==", - "license": "Apache-2.0" - }, "node_modules/yargs": { "version": "17.7.2", "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", @@ -7843,6 +7623,7 @@ "version": "21.1.1", "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "dev": true, "license": "ISC", "engines": { "node": ">=12" @@ -7895,8 +7676,6 @@ "dependencies": { "byte-base64": "^1.1.0", "minimatch": "^10.0.1", - "openapi-fetch": "0.14.0", - "openapi-typescript": "7.6.1", "p-queue": "^8.1.0", "uuid": "^11.1.0" }, diff --git a/frontend/sync-client/package.json b/frontend/sync-client/package.json index 655dd8a4..ab01b233 100644 --- a/frontend/sync-client/package.json +++ b/frontend/sync-client/package.json @@ -15,8 +15,6 @@ "dependencies": { "byte-base64": "^1.1.0", "minimatch": "^10.0.1", - "openapi-fetch": "0.14.0", - "openapi-typescript": "7.6.1", "p-queue": "^8.1.0", "uuid": "^11.1.0" }, @@ -34,4 +32,4 @@ "webpack-merge": "^6.0.1", "ws": "^8.18.1" } -} +} \ No newline at end of file diff --git a/frontend/sync-client/src/services/connection-status.ts b/frontend/sync-client/src/services/connection-status.ts index 572d8895..3934639f 100644 --- a/frontend/sync-client/src/services/connection-status.ts +++ b/frontend/sync-client/src/services/connection-status.ts @@ -51,7 +51,10 @@ export class ConnectionStatus { logger: Logger, fetch: typeof globalThis.fetch = globalThis.fetch ): typeof globalThis.fetch { - return async (input: RequestInfo | URL): Promise => { + return async ( + input: RequestInfo | URL, + init?: RequestInit + ): Promise => { while (!this.canFetch) { await this.until; } @@ -63,7 +66,7 @@ export class ConnectionStatus { ? input.clone() : input; - const fetchPromise = fetch(_input); + const fetchPromise = fetch(_input, init); // We only want to catch rejections from `this.until` let result: symbol | Response | undefined = undefined; diff --git a/frontend/sync-client/src/services/sync-service.ts b/frontend/sync-client/src/services/sync-service.ts index bbb559ff..3d1cfadb 100644 --- a/frontend/sync-client/src/services/sync-service.ts +++ b/frontend/sync-client/src/services/sync-service.ts @@ -1,16 +1,21 @@ -import type { Client } from "openapi-fetch"; -import createClient from "openapi-fetch"; -import type { components, paths } from "./types/http-api"; // generated by openapi-typescript import type { DocumentId, RelativePath, VaultUpdateId } from "../persistence/database"; + import type { Logger } from "../tracing/logger"; import type { Settings } from "../persistence/settings"; import type { ConnectionStatus } from "./connection-status"; import { sleep } from "../utils/sleep"; import { SyncResetError } from "./sync-reset-error"; +import { SerializedError } from "./types/SerializedError"; +import { DocumentVersionWithoutContent } from "./types/DocumentVersionWithoutContent"; +import { DocumentUpdateResponse } from "./types/DocumentUpdateResponse"; +import { DocumentVersion } from "./types/DocumentVersion"; +import { FetchLatestDocumentsResponse } from "./types/FetchLatestDocumentsResponse"; +import { PingResponse } from "./types/PingResponse"; +import { DeleteDocumentVersion } from "./types/DeleteDocumentVersion"; export interface CheckConnectionResult { isSuccessful: boolean; @@ -19,34 +24,34 @@ export interface CheckConnectionResult { export class SyncService { private static readonly NETWORK_RETRY_INTERVAL_MS = 1000; - private client: Client; - private pingClient: Client; + private client: typeof globalThis.fetch; + private pingClient: typeof globalThis.fetch; public constructor( private readonly deviceId: string, private readonly connectionStatus: ConnectionStatus, private readonly settings: Settings, private readonly logger: Logger, - private readonly fetchImplementation: typeof globalThis.fetch = globalThis.fetch + fetchImplementation: typeof globalThis.fetch = globalThis.fetch ) { - [this.client, this.pingClient] = this.createClient( - this.settings.getSettings().remoteUri + // ensure that if it's called a method, `this` won't be bound to the instance + const unboundFetch: typeof globalThis.fetch = (...args) => + fetchImplementation(...args); + + this.client = this.connectionStatus.getFetchImplementation( + this.logger, + unboundFetch ); - - settings.addOnSettingsChangeListener((newSettings, oldSettings) => { - if (newSettings.remoteUri === oldSettings.remoteUri) { - return; - } - - [this.client, this.pingClient] = this.createClient( - newSettings.remoteUri - ); - }); + this.pingClient = unboundFetch; } - private static formatError( - error: components["schemas"]["SerializedError"] - ): string { + private getUrl(path: string): string { + let { vaultName, remoteUri } = this.settings.getSettings(); + remoteUri = remoteUri.replace(/\/+$/, ""); + return `${remoteUri}/vaults/${vaultName}${path}`; + } + + private static formatError(error: SerializedError): string { let result = error.message; if (error.causes.length > 0) { const causes = error.causes.join(", "); @@ -64,9 +69,7 @@ export class SyncService { documentId?: DocumentId; relativePath: RelativePath; contentBytes: Uint8Array; - }): Promise { - const { vaultName } = this.settings.getSettings(); - + }): Promise { return this.withRetries(async () => { const formData = new FormData(); if (documentId !== undefined) { @@ -75,35 +78,28 @@ export class SyncService { formData.append("relative_path", relativePath); formData.append("content", new Blob([contentBytes])); - const response = await this.client.POST( - "/vaults/{vault_id}/documents", - { - params: { - path: { - vault_id: vaultName - }, - header: { - "device-id": this.deviceId - } - }, - // eslint-disable-next-line - body: formData as any // FormData is not supported by openapi-fetch - } - ); + const response = await this.client(this.getUrl("/documents"), { + method: "POST", + body: formData, + headers: this.getDefaultHeaders() + }); - if (!response.data) { + const result: SerializedError | DocumentVersionWithoutContent = + await response.json(); + + if ("errorType" in result) { throw new Error( - `Failed to create document: ${SyncService.formatError(response.error)}` + `Failed to create document: ${SyncService.formatError(result)}` ); } this.logger.debug( - `Created document ${JSON.stringify(response.data)} with id ${ - response.data.documentId + `Created document ${JSON.stringify(result)} with id ${ + result.documentId }` ); - return response.data; + return result; }); } @@ -117,9 +113,7 @@ export class SyncService { documentId: DocumentId; relativePath: RelativePath; contentBytes: Uint8Array; - }): Promise { - const { vaultName } = this.settings.getSettings(); - + }): Promise { return this.withRetries(async () => { this.logger.debug( `Updating document ${documentId} with parent version ${parentVersionId} and relative path ${relativePath}` @@ -129,36 +123,31 @@ export class SyncService { formData.append("relative_path", relativePath); formData.append("content", new Blob([contentBytes])); - const response = await this.client.PUT( - "/vaults/{vault_id}/documents/{document_id}", + const response = await this.client( + this.getUrl(`/documents/${documentId}`), { - params: { - path: { - vault_id: vaultName, - document_id: documentId - }, - header: { - "device-id": this.deviceId - } - }, - // eslint-disable-next-line - body: formData as any // FormData is not supported by openapi-fetch + method: "PUT", + body: formData, + headers: this.getDefaultHeaders() } ); - if (!response.data) { + const result: SerializedError | DocumentUpdateResponse = + await response.json(); + + if ("errorType" in result) { throw new Error( - `Failed to update document: ${SyncService.formatError(response.error)}` + `Failed to update document: ${SyncService.formatError(result)}` ); } this.logger.debug( - `Updated document ${JSON.stringify(response.data)} with id ${ - response.data.documentId - }` + `Updated document ${JSON.stringify(result)} with id ${ + result.documentId + }}` ); - return response.data; + return result; }); } @@ -168,38 +157,37 @@ export class SyncService { }: { documentId: DocumentId; relativePath: RelativePath; - }): Promise { + }): Promise { return this.withRetries(async () => { - const { vaultName } = this.settings.getSettings(); - - const response = await this.client.DELETE( - "/vaults/{vault_id}/documents/{document_id}", + const request: DeleteDocumentVersion = { + relativePath + }; + const response = await this.client( + this.getUrl(`/documents/${documentId}`), { - params: { - path: { - vault_id: vaultName, - document_id: documentId - }, - header: { - "device-id": this.deviceId - } - }, - - body: { - relativePath + method: "DELETE", + body: JSON.stringify(request), + headers: { + "Content-Type": "application/json", + ...this.getDefaultHeaders() } } ); - if (response.error) { - throw new Error(`Failed to delete document`); + const result: SerializedError | DocumentVersionWithoutContent = + await response.json(); + + if ("errorType" in result) { + throw new Error( + `Failed to delete document: ${SyncService.formatError(result)}` + ); } this.logger.debug( `Deleted document ${relativePath} with id ${documentId}` ); - return response.data; + return result; }); } @@ -207,100 +195,75 @@ export class SyncService { documentId }: { documentId: DocumentId; - }): Promise { - const { vaultName } = this.settings.getSettings(); - + }): Promise { return this.withRetries(async () => { - const response = await this.client.GET( - "/vaults/{vault_id}/documents/{document_id}", + const response = await this.client( + this.getUrl(`/documents/${documentId}`), { - params: { - path: { - vault_id: vaultName, - document_id: documentId - } - } + headers: this.getDefaultHeaders() } ); - if (!response.data) { + const result: SerializedError | DocumentVersion = + await response.json(); + + if ("errorType" in result) { throw new Error( - `Failed to get document: ${SyncService.formatError(response.error)}` + `Failed to get document: ${SyncService.formatError(result)}` ); } this.logger.debug( - `Get document ${response.data.relativePath} with id ${response.data.documentId}` + `Get document ${result.relativePath} with id ${result.documentId}` ); - return response.data; + return result; }); } public async getAll( since?: VaultUpdateId - ): Promise { + ): Promise { return this.withRetries(async () => { - const { vaultName } = this.settings.getSettings(); + const url = new URL(this.getUrl("/documents")); + if (since !== undefined) { + url.searchParams.append("since", since.toString()); + } + const response = await this.client(url.toString(), { + headers: this.getDefaultHeaders() + }); - const response = await this.client.GET( - "/vaults/{vault_id}/documents", - { - params: { - path: { - vault_id: vaultName - }, - query: { - since_update_id: since - } - } - } - ); + const result: SerializedError | FetchLatestDocumentsResponse = + await response.json(); - const { error } = response; - if (error) { + if ("errorType" in result) { throw new Error( - `Failed to get documents: ${SyncService.formatError(response.error)}` + `Failed to get documents: ${SyncService.formatError(result)}` ); } this.logger.debug( - `Got ${response.data.latestDocuments.length} document metadata` + `Got ${result.latestDocuments.length} document metadata` ); - return response.data; + return result; }); } public async checkConnection(): Promise { - const { vaultName } = this.settings.getSettings(); - try { - const response = await this.pingClient.GET( - "/vaults/{vault_id}/ping", - { - params: { - header: { - authorization: `Bearer ${this.settings.getSettings().token}` - }, - path: { - vault_id: vaultName - } - } - } - ); + const response = await this.pingClient(this.getUrl("/ping"), { + headers: this.getDefaultHeaders() + }); + const result: PingResponse | SerializedError = + await response.json(); - this.logger.debug( - `Ping response: ${JSON.stringify(response.data)}` - ); - - if (!response.data) { + if ("errorType" in result) { throw new Error( - `Failed to ping server: ${SyncService.formatError(response.error)}` + `Failed to ping server: ${SyncService.formatError(result)}` ); } - const result = response.data; if (result.isAuthenticated) { return { isSuccessful: true, @@ -320,29 +283,11 @@ export class SyncService { } } - /** - * Create a client and a ping client for the given remote URI. - */ - private createClient(remoteUri: string): [Client, Client] { - return [ - createClient({ - baseUrl: remoteUri, - fetch: this.connectionStatus.getFetchImplementation( - this.logger, - this.fetchImplementation - ), - headers: { - authorization: `Bearer ${this.settings.getSettings().token}` - } - }), - createClient({ - baseUrl: remoteUri, - fetch: this.fetchImplementation, - headers: { - authorization: `Bearer ${this.settings.getSettings().token}` - } - }) - ]; + private getDefaultHeaders(): Record { + return { + "device-id": this.deviceId, + authorization: `Bearer ${this.settings.getSettings().token}` + }; } private async withRetries(fn: () => Promise): Promise { diff --git a/frontend/sync-client/src/services/types/DocumentVersion.ts b/frontend/sync-client/src/services/types/DocumentVersion.ts index 0bdad5c9..37bd32ca 100644 --- a/frontend/sync-client/src/services/types/DocumentVersion.ts +++ b/frontend/sync-client/src/services/types/DocumentVersion.ts @@ -1,3 +1,3 @@ // This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. -export type DocumentVersion = { vaultUpdateId: bigint, documentId: string, relativePath: string, updatedDate: string, contentBase64: string, isDeleted: boolean, userId: string, deviceId: string, }; +export type DocumentVersion = { vaultUpdateId: number, documentId: string, relativePath: string, updatedDate: string, contentBase64: string, isDeleted: boolean, userId: string, deviceId: string, }; diff --git a/frontend/sync-client/src/services/types/SerializedError.ts b/frontend/sync-client/src/services/types/SerializedError.ts new file mode 100644 index 00000000..5e3fa9b9 --- /dev/null +++ b/frontend/sync-client/src/services/types/SerializedError.ts @@ -0,0 +1,3 @@ +// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. + +export type SerializedError = { errorType: string, message: string, causes: Array, }; diff --git a/frontend/sync-client/src/services/types/http-api.ts b/frontend/sync-client/src/services/types/http-api.ts deleted file mode 100644 index 5f2c08f5..00000000 --- a/frontend/sync-client/src/services/types/http-api.ts +++ /dev/null @@ -1,648 +0,0 @@ -/** - * This file was auto-generated by openapi-typescript. - * Do not make direct changes to the file. - */ - -export interface paths { - "/vaults/{vault_id}/documents": { - parameters: { - query?: never; - header?: never; - path?: never; - cookie?: never; - }; - get: { - parameters: { - query?: { - since_update_id?: number | null; - }; - header?: never; - path: { - vault_id: string; - }; - cookie?: never; - }; - requestBody?: never; - responses: { - 200: { - headers: { - [name: string]: unknown; - }; - content: { - "application/json": components["schemas"]["FetchLatestDocumentsResponse"]; - }; - }; - default: { - headers: { - [name: string]: unknown; - }; - content: { - /** @example { - * "causes": [], - * "message": "An error has occurred" - * } */ - "application/json": components["schemas"]["SerializedError"]; - }; - }; - }; - }; - put?: never; - post: { - parameters: { - query?: never; - header: { - "device-id": string; - }; - path: { - vault_id: string; - }; - cookie?: never; - }; - requestBody: { - content: { - "multipart/form-data": components["schemas"]["CreateDocumentVersionMultipart"]; - }; - }; - responses: { - 200: { - headers: { - [name: string]: unknown; - }; - content: { - "application/json": components["schemas"]["DocumentVersionWithoutContent"]; - }; - }; - default: { - headers: { - [name: string]: unknown; - }; - content: { - /** @example { - * "causes": [], - * "message": "An error has occurred" - * } */ - "application/json": components["schemas"]["SerializedError"]; - }; - }; - }; - }; - delete?: never; - options?: never; - head?: never; - patch?: never; - trace?: never; - }; - "/vaults/{vault_id}/documents/json": { - parameters: { - query?: never; - header?: never; - path?: never; - cookie?: never; - }; - get?: never; - put?: never; - post: { - parameters: { - query?: never; - header: { - "device-id": string; - }; - path: { - vault_id: string; - }; - cookie?: never; - }; - requestBody: { - content: { - "application/json": components["schemas"]["CreateDocumentVersion"]; - }; - }; - responses: { - 200: { - headers: { - [name: string]: unknown; - }; - content: { - "application/json": components["schemas"]["DocumentVersionWithoutContent"]; - }; - }; - default: { - headers: { - [name: string]: unknown; - }; - content: { - /** @example { - * "causes": [], - * "message": "An error has occurred" - * } */ - "application/json": components["schemas"]["SerializedError"]; - }; - }; - }; - }; - delete?: never; - options?: never; - head?: never; - patch?: never; - trace?: never; - }; - "/vaults/{vault_id}/documents/{document_id}": { - parameters: { - query?: never; - header?: never; - path?: never; - cookie?: never; - }; - get: { - parameters: { - query?: never; - header?: never; - path: { - document_id: string; - vault_id: string; - }; - cookie?: never; - }; - requestBody?: never; - responses: { - 200: { - headers: { - [name: string]: unknown; - }; - content: { - "application/json": components["schemas"]["DocumentVersion"]; - }; - }; - default: { - headers: { - [name: string]: unknown; - }; - content: { - /** @example { - * "causes": [], - * "message": "An error has occurred" - * } */ - "application/json": components["schemas"]["SerializedError"]; - }; - }; - }; - }; - put: { - parameters: { - query?: never; - header: { - "device-id": string; - }; - path: { - document_id: string; - vault_id: string; - }; - cookie?: never; - }; - requestBody: { - content: { - "multipart/form-data": components["schemas"]["UpdateDocumentVersionMultipart"]; - }; - }; - responses: { - 200: { - headers: { - [name: string]: unknown; - }; - content: { - "application/json": components["schemas"]["DocumentUpdateResponse"]; - }; - }; - default: { - headers: { - [name: string]: unknown; - }; - content: { - /** @example { - * "causes": [], - * "message": "An error has occurred" - * } */ - "application/json": components["schemas"]["SerializedError"]; - }; - }; - }; - }; - post?: never; - delete: { - parameters: { - query?: never; - header: { - "device-id": string; - }; - path: { - document_id: string; - vault_id: string; - }; - cookie?: never; - }; - requestBody: { - content: { - "application/json": components["schemas"]["DeleteDocumentVersion"]; - }; - }; - responses: { - 200: { - headers: { - [name: string]: unknown; - }; - content: { - "application/json": components["schemas"]["DocumentVersionWithoutContent"]; - }; - }; - default: { - headers: { - [name: string]: unknown; - }; - content: { - /** @example { - * "causes": [], - * "message": "An error has occurred" - * } */ - "application/json": components["schemas"]["SerializedError"]; - }; - }; - }; - }; - options?: never; - head?: never; - patch?: never; - trace?: never; - }; - "/vaults/{vault_id}/documents/{document_id}/json": { - parameters: { - query?: never; - header?: never; - path?: never; - cookie?: never; - }; - get?: never; - put: { - parameters: { - query?: never; - header: { - "device-id": string; - }; - path: { - document_id: string; - vault_id: string; - }; - cookie?: never; - }; - requestBody: { - content: { - "application/json": components["schemas"]["UpdateDocumentVersion"]; - }; - }; - responses: { - 200: { - headers: { - [name: string]: unknown; - }; - content: { - "application/json": components["schemas"]["DocumentUpdateResponse"]; - }; - }; - default: { - headers: { - [name: string]: unknown; - }; - content: { - /** @example { - * "causes": [], - * "message": "An error has occurred" - * } */ - "application/json": components["schemas"]["SerializedError"]; - }; - }; - }; - }; - post?: never; - delete?: never; - options?: never; - head?: never; - patch?: never; - trace?: never; - }; - "/vaults/{vault_id}/documents/{document_id}/versions/{version_id}": { - parameters: { - query?: never; - header?: never; - path?: never; - cookie?: never; - }; - get?: never; - put: { - parameters: { - query?: never; - header?: never; - path: { - document_id: string; - vault_id: string; - vault_update_id: number; - }; - cookie?: never; - }; - requestBody?: never; - responses: { - 200: { - headers: { - [name: string]: unknown; - }; - content: { - "application/json": components["schemas"]["DocumentVersion"]; - }; - }; - default: { - headers: { - [name: string]: unknown; - }; - content: { - /** @example { - * "causes": [], - * "message": "An error has occurred" - * } */ - "application/json": components["schemas"]["SerializedError"]; - }; - }; - }; - }; - post?: never; - delete?: never; - options?: never; - head?: never; - patch?: never; - trace?: never; - }; - "/vaults/{vault_id}/documents/{document_id}/versions/{version_id}/content": { - parameters: { - query?: never; - header?: never; - path?: never; - cookie?: never; - }; - get?: never; - put: { - parameters: { - query?: never; - header?: never; - path: { - document_id: string; - vault_id: string; - vault_update_id: number; - }; - cookie?: never; - }; - requestBody?: never; - responses: { - /** @description byte stream */ - 200: { - headers: { - [name: string]: unknown; - }; - content: { - "application/octet-stream": unknown; - }; - }; - default: { - headers: { - [name: string]: unknown; - }; - content: { - /** @example { - * "causes": [], - * "message": "An error has occurred" - * } */ - "application/json": components["schemas"]["SerializedError"]; - }; - }; - }; - }; - post?: never; - delete?: never; - options?: never; - head?: never; - patch?: never; - trace?: never; - }; - "/vaults/{vault_id}/ping": { - parameters: { - query?: never; - header?: never; - path?: never; - cookie?: never; - }; - get: { - parameters: { - query?: never; - header?: { - authorization?: string; - }; - path: { - vault_id: string; - }; - cookie?: never; - }; - requestBody?: never; - responses: { - 200: { - headers: { - [name: string]: unknown; - }; - content: { - "application/json": components["schemas"]["PingResponse"]; - }; - }; - default: { - headers: { - [name: string]: unknown; - }; - content: { - /** @example { - * "causes": [], - * "message": "An error has occurred" - * } */ - "application/json": components["schemas"]["SerializedError"]; - }; - }; - }; - }; - put?: never; - post?: never; - delete?: never; - options?: never; - head?: never; - patch?: never; - trace?: never; - }; -} -export type webhooks = Record; -export interface components { - schemas: { - Array_of_uint8: number[]; - CreateDocumentPathParams: { - vault_id: string; - }; - CreateDocumentVersion: { - contentBase64: string; - /** - * Format: uuid - * @description The client can decide the document id (if it wishes to) in order to help with syncing. If the client does not provide a document id, the server will generate one. If the client provides a document id it must not already exist in the database. - */ - documentId?: string | null; - relativePath: string; - }; - CreateDocumentVersionMultipart: { - content: components["schemas"]["Array_of_uint8"]; - /** Format: uuid */ - document_id?: string | null; - relative_path: string; - }; - DeleteDocumentPathParams: { - /** Format: uuid */ - document_id: string; - vault_id: string; - }; - DeleteDocumentVersion: { - relativePath: string; - }; - /** @description Response to an update document request. */ - DocumentUpdateResponse: { - /** Format: uint64 */ - contentSize: number; - deviceId: string; - /** Format: uuid */ - documentId: string; - isDeleted: boolean; - relativePath: string; - /** @enum {string} */ - type: "FastForwardUpdate"; - /** Format: date-time */ - updatedDate: string; - userId: string; - /** Format: int64 */ - vaultUpdateId: number; - } | { - contentBase64: string; - deviceId: string; - /** Format: uuid */ - documentId: string; - isDeleted: boolean; - relativePath: string; - /** @enum {string} */ - type: "MergingUpdate"; - /** Format: date-time */ - updatedDate: string; - userId: string; - /** Format: int64 */ - vaultUpdateId: number; - }; - DocumentVersion: { - contentBase64: string; - deviceId: string; - /** Format: uuid */ - documentId: string; - isDeleted: boolean; - relativePath: string; - /** Format: date-time */ - updatedDate: string; - userId: string; - /** Format: int64 */ - vaultUpdateId: number; - }; - DocumentVersionWithoutContent: { - /** Format: uint64 */ - contentSize: number; - deviceId: string; - /** Format: uuid */ - documentId: string; - isDeleted: boolean; - relativePath: string; - /** Format: date-time */ - updatedDate: string; - userId: string; - /** Format: int64 */ - vaultUpdateId: number; - }; - FetchDocumentVersionContentPathParams: { - /** Format: uuid */ - document_id: string; - vault_id: string; - /** Format: int64 */ - vault_update_id: number; - }; - FetchDocumentVersionPathParams: { - /** Format: uuid */ - document_id: string; - vault_id: string; - /** Format: int64 */ - vault_update_id: number; - }; - FetchLatestDocumentVersionPathParams: { - /** Format: uuid */ - document_id: string; - vault_id: string; - }; - FetchLatestDocumentsPathParams: { - vault_id: string; - }; - /** @description Response to a fetch latest documents request. */ - FetchLatestDocumentsResponse: { - /** - * Format: int64 - * @description The update ID of the latest document in the response. - */ - lastUpdateId: number; - latestDocuments: components["schemas"]["DocumentVersionWithoutContent"][]; - }; - PingPathParams: { - vault_id: string; - }; - /** @description Response to a ping request. */ - PingResponse: { - /** @description Whether the client is authenticated based on the sent Authorization header. */ - isAuthenticated: boolean; - /** @description Semantic version of the server. */ - serverVersion: string; - }; - QueryParams: { - /** Format: int64 */ - since_update_id?: number | null; - }; - SerializedError: { - causes: string[]; - message: string; - }; - UpdateDocumentPathParams: { - /** Format: uuid */ - document_id: string; - vault_id: string; - }; - UpdateDocumentVersion: { - contentBase64: string; - /** Format: int64 */ - parentVersionId: number; - relativePath: string; - }; - UpdateDocumentVersionMultipart: { - content: components["schemas"]["Array_of_uint8"]; - /** Format: int64 */ - parentVersionId: number; - relativePath: string; - }; - WebSocketPathParams: { - vault_id: string; - }; - }; - responses: never; - parameters: never; - requestBodies: never; - headers: never; - pathItems: never; -} -export type $defs = Record; -export type operations = Record; diff --git a/frontend/sync-client/src/sync-operations/syncer.ts b/frontend/sync-client/src/sync-operations/syncer.ts index 57d99f14..9270a8ed 100644 --- a/frontend/sync-client/src/sync-operations/syncer.ts +++ b/frontend/sync-client/src/sync-operations/syncer.ts @@ -9,7 +9,6 @@ import type { Logger } from "../tracing/logger"; import PQueue from "p-queue"; import { hash } from "../utils/hash"; import { v4 as uuidv4 } from "uuid"; -import type { components } from "../services/types/http-api"; import type { Settings, SyncSettings } from "../persistence/settings"; import type { FileOperations } from "../file-operations/file-operations"; import { findMatchingFile } from "../utils/find-matching-file"; @@ -17,6 +16,7 @@ import type { UnrestrictedSyncer } from "./unrestricted-syncer"; import { createPromise } from "../utils/create-promise"; import { SyncResetError } from "../services/sync-reset-error"; import { Locks } from "../utils/locks"; +import { DocumentVersionWithoutContent } from "../services/types/DocumentVersionWithoutContent"; export class Syncer { private readonly remoteDocumentsLock: Locks; @@ -255,7 +255,7 @@ export class Syncer { } public async syncRemotelyUpdatedFile( - remoteVersion: components["schemas"]["DocumentVersionWithoutContent"] + remoteVersion: DocumentVersionWithoutContent ): Promise { let document = this.database.getDocumentByDocumentId( remoteVersion.documentId diff --git a/frontend/sync-client/src/sync-operations/unrestricted-syncer.ts b/frontend/sync-client/src/sync-operations/unrestricted-syncer.ts index 76470120..f892e640 100644 --- a/frontend/sync-client/src/sync-operations/unrestricted-syncer.ts +++ b/frontend/sync-client/src/sync-operations/unrestricted-syncer.ts @@ -17,7 +17,6 @@ import type { } from "../tracing/sync-history"; import { SyncStatus, SyncType } from "../tracing/sync-history"; import { EMPTY_HASH, hash } from "../utils/hash"; -import type { components } from "../services/types/http-api"; import { deserialize } from "../utils/deserialize"; import type { Settings } from "../persistence/settings"; import type { FileOperations } from "../file-operations/file-operations"; @@ -25,6 +24,9 @@ import { createPromise } from "../utils/create-promise"; import { FileNotFoundError } from "../file-operations/file-not-found-error"; import { SyncResetError } from "../services/sync-reset-error"; import { globsToRegexes } from "../utils/globs-to-regexes"; +import { DocumentVersion } from "../services/types/DocumentVersion"; +import { DocumentUpdateResponse } from "../services/types/DocumentUpdateResponse"; +import { DocumentVersionWithoutContent } from "../services/types/DocumentVersionWithoutContent"; export class UnrestrictedSyncer { private ignorePatterns: RegExp[]; @@ -172,10 +174,8 @@ export class UnrestrictedSyncer { document.metadata.hash === contentHash && oldPath === undefined ); - let response: - | components["schemas"]["DocumentVersion"] - | components["schemas"]["DocumentUpdateResponse"] - | undefined = undefined; + let response: DocumentVersion | DocumentUpdateResponse | undefined = + undefined; if (areThereLocalChanges) { response = await this.syncService.put({ @@ -332,7 +332,7 @@ export class UnrestrictedSyncer { } public async unrestrictedSyncRemotelyUpdatedFile( - remoteVersion: components["schemas"]["DocumentVersionWithoutContent"], + remoteVersion: DocumentVersionWithoutContent, document?: DocumentRecord ): Promise { const updateDetails: SyncCreateDetails = {