Add API for propagating cursor locations #61
10 changed files with 156 additions and 1061 deletions
Remove openapi from frontend
commit
7956a92bec
|
|
@ -8,6 +8,7 @@ use axum::{
|
||||||
use log::{debug, error};
|
use log::{debug, error};
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
use ts_rs::TS;
|
||||||
|
|
||||||
#[derive(Error, Debug)]
|
#[derive(Error, Debug)]
|
||||||
pub enum SyncServerError {
|
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 struct SerializedError {
|
||||||
|
pub error_type: &'static str,
|
||||||
pub message: String,
|
pub message: String,
|
||||||
pub causes: Vec<String>,
|
pub causes: Vec<String>,
|
||||||
}
|
}
|
||||||
|
|
@ -88,6 +92,17 @@ impl From<&anyhow::Error> for SerializedError {
|
||||||
}
|
}
|
||||||
|
|
||||||
SerializedError {
|
SerializedError {
|
||||||
|
error_type: error.downcast_ref::<SyncServerError>().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(),
|
message: error.to_string(),
|
||||||
causes,
|
causes,
|
||||||
}
|
}
|
||||||
|
|
|
||||||
245
frontend/package-lock.json
generated
245
frontend/package-lock.json
generated
|
|
@ -43,6 +43,7 @@
|
||||||
"version": "7.26.2",
|
"version": "7.26.2",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.26.2.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.26.2.tgz",
|
||||||
"integrity": "sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ==",
|
"integrity": "sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ==",
|
||||||
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/helper-validator-identifier": "^7.25.9",
|
"@babel/helper-validator-identifier": "^7.25.9",
|
||||||
|
|
@ -204,6 +205,7 @@
|
||||||
"version": "7.25.9",
|
"version": "7.25.9",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.25.9.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.25.9.tgz",
|
||||||
"integrity": "sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==",
|
"integrity": "sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==",
|
||||||
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=6.9.0"
|
"node": ">=6.9.0"
|
||||||
|
|
@ -1620,76 +1622,6 @@
|
||||||
"url": "https://opencollective.com/parcel"
|
"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": {
|
"node_modules/@sinclair/typebox": {
|
||||||
"version": "0.27.8",
|
"version": "0.27.8",
|
||||||
"resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz",
|
"resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz",
|
||||||
|
|
@ -2375,15 +2307,6 @@
|
||||||
"node": ">=8.9"
|
"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": {
|
"node_modules/ajv": {
|
||||||
"version": "6.12.6",
|
"version": "6.12.6",
|
||||||
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
|
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
|
||||||
|
|
@ -2453,15 +2376,6 @@
|
||||||
"ajv": "^6.9.1"
|
"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": {
|
"node_modules/ansi-escapes": {
|
||||||
"version": "4.3.2",
|
"version": "4.3.2",
|
||||||
"resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz",
|
"resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz",
|
||||||
|
|
@ -2522,6 +2436,7 @@
|
||||||
"version": "2.0.1",
|
"version": "2.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
|
||||||
"integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
|
"integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
|
||||||
|
"dev": true,
|
||||||
"license": "Python-2.0"
|
"license": "Python-2.0"
|
||||||
},
|
},
|
||||||
"node_modules/async": {
|
"node_modules/async": {
|
||||||
|
|
@ -2882,12 +2797,6 @@
|
||||||
"node": ">=8"
|
"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": {
|
"node_modules/char-regex": {
|
||||||
"version": "1.0.2",
|
"version": "1.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz",
|
||||||
|
|
@ -3015,12 +2924,6 @@
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT"
|
"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": {
|
"node_modules/commander": {
|
||||||
"version": "2.20.3",
|
"version": "2.20.3",
|
||||||
"resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
|
"resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
|
||||||
|
|
@ -3169,6 +3072,7 @@
|
||||||
"version": "4.4.0",
|
"version": "4.4.0",
|
||||||
"resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz",
|
"resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz",
|
||||||
"integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==",
|
"integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==",
|
||||||
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"ms": "^2.1.3"
|
"ms": "^2.1.3"
|
||||||
|
|
@ -3671,6 +3575,7 @@
|
||||||
"version": "3.1.3",
|
"version": "3.1.3",
|
||||||
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
|
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
|
||||||
"integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
|
"integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
|
||||||
|
"dev": true,
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/fast-glob": {
|
"node_modules/fast-glob": {
|
||||||
|
|
@ -4146,19 +4051,6 @@
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT"
|
"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": {
|
"node_modules/human-signals": {
|
||||||
"version": "2.1.0",
|
"version": "2.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz",
|
||||||
|
|
@ -4246,18 +4138,6 @@
|
||||||
"node": ">=0.8.19"
|
"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": {
|
"node_modules/inflight": {
|
||||||
"version": "1.0.6",
|
"version": "1.0.6",
|
||||||
"resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
|
"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": "^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": {
|
"node_modules/js-tokens": {
|
||||||
"version": "4.0.0",
|
"version": "4.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
|
||||||
"integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
|
"integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
|
||||||
|
"dev": true,
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/js-yaml": {
|
"node_modules/js-yaml": {
|
||||||
"version": "4.1.0",
|
"version": "4.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz",
|
||||||
"integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==",
|
"integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==",
|
||||||
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"argparse": "^2.0.1"
|
"argparse": "^2.0.1"
|
||||||
|
|
@ -5515,6 +5388,7 @@
|
||||||
"version": "2.1.3",
|
"version": "2.1.3",
|
||||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
|
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
|
||||||
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
|
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
|
||||||
|
"dev": true,
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/nanoid": {
|
"node_modules/nanoid": {
|
||||||
|
|
@ -5676,82 +5550,6 @@
|
||||||
"url": "https://github.com/sponsors/sindresorhus"
|
"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": {
|
"node_modules/optionator": {
|
||||||
"version": "0.9.4",
|
"version": "0.9.4",
|
||||||
"resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz",
|
"resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz",
|
||||||
|
|
@ -5913,6 +5711,7 @@
|
||||||
"version": "1.1.1",
|
"version": "1.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
|
||||||
"integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==",
|
"integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==",
|
||||||
|
"dev": true,
|
||||||
"license": "ISC"
|
"license": "ISC"
|
||||||
},
|
},
|
||||||
"node_modules/picomatch": {
|
"node_modules/picomatch": {
|
||||||
|
|
@ -6007,15 +5806,6 @@
|
||||||
"node": ">=8"
|
"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": {
|
"node_modules/postcss": {
|
||||||
"version": "8.5.3",
|
"version": "8.5.3",
|
||||||
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.3.tgz",
|
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.3.tgz",
|
||||||
|
|
@ -6333,6 +6123,7 @@
|
||||||
"version": "2.0.2",
|
"version": "2.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz",
|
"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==",
|
"integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==",
|
||||||
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=0.10.0"
|
"node": ">=0.10.0"
|
||||||
|
|
@ -7276,6 +7067,7 @@
|
||||||
"version": "5.8.3",
|
"version": "5.8.3",
|
||||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.3.tgz",
|
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.3.tgz",
|
||||||
"integrity": "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==",
|
"integrity": "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==",
|
||||||
|
"dev": true,
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"bin": {
|
"bin": {
|
||||||
"tsc": "bin/tsc",
|
"tsc": "bin/tsc",
|
||||||
|
|
@ -7366,12 +7158,6 @@
|
||||||
"punycode": "^2.1.0"
|
"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": {
|
"node_modules/url": {
|
||||||
"version": "0.11.4",
|
"version": "0.11.4",
|
||||||
"resolved": "https://registry.npmjs.org/url/-/url-0.11.4.tgz",
|
"resolved": "https://registry.npmjs.org/url/-/url-0.11.4.tgz",
|
||||||
|
|
@ -7814,12 +7600,6 @@
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "ISC"
|
"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": {
|
"node_modules/yargs": {
|
||||||
"version": "17.7.2",
|
"version": "17.7.2",
|
||||||
"resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz",
|
"resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz",
|
||||||
|
|
@ -7843,6 +7623,7 @@
|
||||||
"version": "21.1.1",
|
"version": "21.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz",
|
||||||
"integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==",
|
"integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==",
|
||||||
|
"dev": true,
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=12"
|
"node": ">=12"
|
||||||
|
|
@ -7895,8 +7676,6 @@
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"byte-base64": "^1.1.0",
|
"byte-base64": "^1.1.0",
|
||||||
"minimatch": "^10.0.1",
|
"minimatch": "^10.0.1",
|
||||||
"openapi-fetch": "0.14.0",
|
|
||||||
"openapi-typescript": "7.6.1",
|
|
||||||
"p-queue": "^8.1.0",
|
"p-queue": "^8.1.0",
|
||||||
"uuid": "^11.1.0"
|
"uuid": "^11.1.0"
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -15,8 +15,6 @@
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"byte-base64": "^1.1.0",
|
"byte-base64": "^1.1.0",
|
||||||
"minimatch": "^10.0.1",
|
"minimatch": "^10.0.1",
|
||||||
"openapi-fetch": "0.14.0",
|
|
||||||
"openapi-typescript": "7.6.1",
|
|
||||||
"p-queue": "^8.1.0",
|
"p-queue": "^8.1.0",
|
||||||
"uuid": "^11.1.0"
|
"uuid": "^11.1.0"
|
||||||
},
|
},
|
||||||
|
|
@ -34,4 +32,4 @@
|
||||||
"webpack-merge": "^6.0.1",
|
"webpack-merge": "^6.0.1",
|
||||||
"ws": "^8.18.1"
|
"ws": "^8.18.1"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -51,7 +51,10 @@ export class ConnectionStatus {
|
||||||
logger: Logger,
|
logger: Logger,
|
||||||
fetch: typeof globalThis.fetch = globalThis.fetch
|
fetch: typeof globalThis.fetch = globalThis.fetch
|
||||||
): typeof globalThis.fetch {
|
): typeof globalThis.fetch {
|
||||||
return async (input: RequestInfo | URL): Promise<Response> => {
|
return async (
|
||||||
|
input: RequestInfo | URL,
|
||||||
|
init?: RequestInit
|
||||||
|
): Promise<Response> => {
|
||||||
while (!this.canFetch) {
|
while (!this.canFetch) {
|
||||||
await this.until;
|
await this.until;
|
||||||
}
|
}
|
||||||
|
|
@ -63,7 +66,7 @@ export class ConnectionStatus {
|
||||||
? input.clone()
|
? input.clone()
|
||||||
: input;
|
: input;
|
||||||
|
|
||||||
const fetchPromise = fetch(_input);
|
const fetchPromise = fetch(_input, init);
|
||||||
|
|
||||||
// We only want to catch rejections from `this.until`
|
// We only want to catch rejections from `this.until`
|
||||||
let result: symbol | Response | undefined = undefined;
|
let result: symbol | Response | undefined = undefined;
|
||||||
|
|
|
||||||
|
|
@ -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 {
|
import type {
|
||||||
DocumentId,
|
DocumentId,
|
||||||
RelativePath,
|
RelativePath,
|
||||||
VaultUpdateId
|
VaultUpdateId
|
||||||
} from "../persistence/database";
|
} from "../persistence/database";
|
||||||
|
|
||||||
import type { Logger } from "../tracing/logger";
|
import type { Logger } from "../tracing/logger";
|
||||||
import type { Settings } from "../persistence/settings";
|
import type { Settings } from "../persistence/settings";
|
||||||
import type { ConnectionStatus } from "./connection-status";
|
import type { ConnectionStatus } from "./connection-status";
|
||||||
import { sleep } from "../utils/sleep";
|
import { sleep } from "../utils/sleep";
|
||||||
import { SyncResetError } from "./sync-reset-error";
|
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 {
|
export interface CheckConnectionResult {
|
||||||
isSuccessful: boolean;
|
isSuccessful: boolean;
|
||||||
|
|
@ -19,34 +24,34 @@ export interface CheckConnectionResult {
|
||||||
|
|
||||||
export class SyncService {
|
export class SyncService {
|
||||||
private static readonly NETWORK_RETRY_INTERVAL_MS = 1000;
|
private static readonly NETWORK_RETRY_INTERVAL_MS = 1000;
|
||||||
private client: Client<paths>;
|
private client: typeof globalThis.fetch;
|
||||||
private pingClient: Client<paths>;
|
private pingClient: typeof globalThis.fetch;
|
||||||
|
|
||||||
public constructor(
|
public constructor(
|
||||||
private readonly deviceId: string,
|
private readonly deviceId: string,
|
||||||
private readonly connectionStatus: ConnectionStatus,
|
private readonly connectionStatus: ConnectionStatus,
|
||||||
private readonly settings: Settings,
|
private readonly settings: Settings,
|
||||||
private readonly logger: Logger,
|
private readonly logger: Logger,
|
||||||
private readonly fetchImplementation: typeof globalThis.fetch = globalThis.fetch
|
fetchImplementation: typeof globalThis.fetch = globalThis.fetch
|
||||||
) {
|
) {
|
||||||
[this.client, this.pingClient] = this.createClient(
|
// ensure that if it's called a method, `this` won't be bound to the instance
|
||||||
this.settings.getSettings().remoteUri
|
const unboundFetch: typeof globalThis.fetch = (...args) =>
|
||||||
|
fetchImplementation(...args);
|
||||||
|
|
||||||
|
this.client = this.connectionStatus.getFetchImplementation(
|
||||||
|
this.logger,
|
||||||
|
unboundFetch
|
||||||
);
|
);
|
||||||
|
this.pingClient = unboundFetch;
|
||||||
settings.addOnSettingsChangeListener((newSettings, oldSettings) => {
|
|
||||||
if (newSettings.remoteUri === oldSettings.remoteUri) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
[this.client, this.pingClient] = this.createClient(
|
|
||||||
newSettings.remoteUri
|
|
||||||
);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static formatError(
|
private getUrl(path: string): string {
|
||||||
error: components["schemas"]["SerializedError"]
|
let { vaultName, remoteUri } = this.settings.getSettings();
|
||||||
): string {
|
remoteUri = remoteUri.replace(/\/+$/, "");
|
||||||
|
return `${remoteUri}/vaults/${vaultName}${path}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static formatError(error: SerializedError): string {
|
||||||
let result = error.message;
|
let result = error.message;
|
||||||
if (error.causes.length > 0) {
|
if (error.causes.length > 0) {
|
||||||
const causes = error.causes.join(", ");
|
const causes = error.causes.join(", ");
|
||||||
|
|
@ -64,9 +69,7 @@ export class SyncService {
|
||||||
documentId?: DocumentId;
|
documentId?: DocumentId;
|
||||||
relativePath: RelativePath;
|
relativePath: RelativePath;
|
||||||
contentBytes: Uint8Array;
|
contentBytes: Uint8Array;
|
||||||
}): Promise<components["schemas"]["DocumentVersionWithoutContent"]> {
|
}): Promise<DocumentVersionWithoutContent> {
|
||||||
const { vaultName } = this.settings.getSettings();
|
|
||||||
|
|
||||||
return this.withRetries(async () => {
|
return this.withRetries(async () => {
|
||||||
const formData = new FormData();
|
const formData = new FormData();
|
||||||
if (documentId !== undefined) {
|
if (documentId !== undefined) {
|
||||||
|
|
@ -75,35 +78,28 @@ export class SyncService {
|
||||||
formData.append("relative_path", relativePath);
|
formData.append("relative_path", relativePath);
|
||||||
formData.append("content", new Blob([contentBytes]));
|
formData.append("content", new Blob([contentBytes]));
|
||||||
|
|
||||||
const response = await this.client.POST(
|
const response = await this.client(this.getUrl("/documents"), {
|
||||||
"/vaults/{vault_id}/documents",
|
method: "POST",
|
||||||
{
|
body: formData,
|
||||||
params: {
|
headers: this.getDefaultHeaders()
|
||||||
path: {
|
});
|
||||||
vault_id: vaultName
|
|
||||||
},
|
|
||||||
header: {
|
|
||||||
"device-id": this.deviceId
|
|
||||||
}
|
|
||||||
},
|
|
||||||
// eslint-disable-next-line
|
|
||||||
body: formData as any // FormData is not supported by openapi-fetch
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
if (!response.data) {
|
const result: SerializedError | DocumentVersionWithoutContent =
|
||||||
|
await response.json();
|
||||||
|
|
||||||
|
if ("errorType" in result) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`Failed to create document: ${SyncService.formatError(response.error)}`
|
`Failed to create document: ${SyncService.formatError(result)}`
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.logger.debug(
|
this.logger.debug(
|
||||||
`Created document ${JSON.stringify(response.data)} with id ${
|
`Created document ${JSON.stringify(result)} with id ${
|
||||||
response.data.documentId
|
result.documentId
|
||||||
}`
|
}`
|
||||||
);
|
);
|
||||||
|
|
||||||
return response.data;
|
return result;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -117,9 +113,7 @@ export class SyncService {
|
||||||
documentId: DocumentId;
|
documentId: DocumentId;
|
||||||
relativePath: RelativePath;
|
relativePath: RelativePath;
|
||||||
contentBytes: Uint8Array;
|
contentBytes: Uint8Array;
|
||||||
}): Promise<components["schemas"]["DocumentUpdateResponse"]> {
|
}): Promise<DocumentUpdateResponse> {
|
||||||
const { vaultName } = this.settings.getSettings();
|
|
||||||
|
|
||||||
return this.withRetries(async () => {
|
return this.withRetries(async () => {
|
||||||
this.logger.debug(
|
this.logger.debug(
|
||||||
`Updating document ${documentId} with parent version ${parentVersionId} and relative path ${relativePath}`
|
`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("relative_path", relativePath);
|
||||||
formData.append("content", new Blob([contentBytes]));
|
formData.append("content", new Blob([contentBytes]));
|
||||||
|
|
||||||
const response = await this.client.PUT(
|
const response = await this.client(
|
||||||
"/vaults/{vault_id}/documents/{document_id}",
|
this.getUrl(`/documents/${documentId}`),
|
||||||
{
|
{
|
||||||
params: {
|
method: "PUT",
|
||||||
path: {
|
body: formData,
|
||||||
vault_id: vaultName,
|
headers: this.getDefaultHeaders()
|
||||||
document_id: documentId
|
|
||||||
},
|
|
||||||
header: {
|
|
||||||
"device-id": this.deviceId
|
|
||||||
}
|
|
||||||
},
|
|
||||||
// eslint-disable-next-line
|
|
||||||
body: formData as any // FormData is not supported by openapi-fetch
|
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!response.data) {
|
const result: SerializedError | DocumentUpdateResponse =
|
||||||
|
await response.json();
|
||||||
|
|
||||||
|
if ("errorType" in result) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`Failed to update document: ${SyncService.formatError(response.error)}`
|
`Failed to update document: ${SyncService.formatError(result)}`
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.logger.debug(
|
this.logger.debug(
|
||||||
`Updated document ${JSON.stringify(response.data)} with id ${
|
`Updated document ${JSON.stringify(result)} with id ${
|
||||||
response.data.documentId
|
result.documentId
|
||||||
}`
|
}}`
|
||||||
);
|
);
|
||||||
|
|
||||||
return response.data;
|
return result;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -168,38 +157,37 @@ export class SyncService {
|
||||||
}: {
|
}: {
|
||||||
documentId: DocumentId;
|
documentId: DocumentId;
|
||||||
relativePath: RelativePath;
|
relativePath: RelativePath;
|
||||||
}): Promise<components["schemas"]["DocumentVersionWithoutContent"]> {
|
}): Promise<DocumentVersionWithoutContent> {
|
||||||
return this.withRetries(async () => {
|
return this.withRetries(async () => {
|
||||||
const { vaultName } = this.settings.getSettings();
|
const request: DeleteDocumentVersion = {
|
||||||
|
relativePath
|
||||||
const response = await this.client.DELETE(
|
};
|
||||||
"/vaults/{vault_id}/documents/{document_id}",
|
const response = await this.client(
|
||||||
|
this.getUrl(`/documents/${documentId}`),
|
||||||
{
|
{
|
||||||
params: {
|
method: "DELETE",
|
||||||
path: {
|
body: JSON.stringify(request),
|
||||||
vault_id: vaultName,
|
headers: {
|
||||||
document_id: documentId
|
"Content-Type": "application/json",
|
||||||
},
|
...this.getDefaultHeaders()
|
||||||
header: {
|
|
||||||
"device-id": this.deviceId
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
body: {
|
|
||||||
relativePath
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
if (response.error) {
|
const result: SerializedError | DocumentVersionWithoutContent =
|
||||||
throw new Error(`Failed to delete document`);
|
await response.json();
|
||||||
|
|
||||||
|
if ("errorType" in result) {
|
||||||
|
throw new Error(
|
||||||
|
`Failed to delete document: ${SyncService.formatError(result)}`
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.logger.debug(
|
this.logger.debug(
|
||||||
`Deleted document ${relativePath} with id ${documentId}`
|
`Deleted document ${relativePath} with id ${documentId}`
|
||||||
);
|
);
|
||||||
|
|
||||||
return response.data;
|
return result;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -207,100 +195,75 @@ export class SyncService {
|
||||||
documentId
|
documentId
|
||||||
}: {
|
}: {
|
||||||
documentId: DocumentId;
|
documentId: DocumentId;
|
||||||
}): Promise<components["schemas"]["DocumentVersion"]> {
|
}): Promise<DocumentVersion> {
|
||||||
const { vaultName } = this.settings.getSettings();
|
|
||||||
|
|
||||||
return this.withRetries(async () => {
|
return this.withRetries(async () => {
|
||||||
const response = await this.client.GET(
|
const response = await this.client(
|
||||||
"/vaults/{vault_id}/documents/{document_id}",
|
this.getUrl(`/documents/${documentId}`),
|
||||||
{
|
{
|
||||||
params: {
|
headers: this.getDefaultHeaders()
|
||||||
path: {
|
|
||||||
vault_id: vaultName,
|
|
||||||
document_id: documentId
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!response.data) {
|
const result: SerializedError | DocumentVersion =
|
||||||
|
await response.json();
|
||||||
|
|
||||||
|
if ("errorType" in result) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`Failed to get document: ${SyncService.formatError(response.error)}`
|
`Failed to get document: ${SyncService.formatError(result)}`
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.logger.debug(
|
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(
|
public async getAll(
|
||||||
since?: VaultUpdateId
|
since?: VaultUpdateId
|
||||||
): Promise<components["schemas"]["FetchLatestDocumentsResponse"]> {
|
): Promise<FetchLatestDocumentsResponse> {
|
||||||
return this.withRetries(async () => {
|
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(
|
const result: SerializedError | FetchLatestDocumentsResponse =
|
||||||
"/vaults/{vault_id}/documents",
|
await response.json();
|
||||||
{
|
|
||||||
params: {
|
|
||||||
path: {
|
|
||||||
vault_id: vaultName
|
|
||||||
},
|
|
||||||
query: {
|
|
||||||
since_update_id: since
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
const { error } = response;
|
if ("errorType" in result) {
|
||||||
if (error) {
|
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`Failed to get documents: ${SyncService.formatError(response.error)}`
|
`Failed to get documents: ${SyncService.formatError(result)}`
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.logger.debug(
|
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<CheckConnectionResult> {
|
public async checkConnection(): Promise<CheckConnectionResult> {
|
||||||
const { vaultName } = this.settings.getSettings();
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const response = await this.pingClient.GET(
|
const response = await this.pingClient(this.getUrl("/ping"), {
|
||||||
"/vaults/{vault_id}/ping",
|
headers: this.getDefaultHeaders()
|
||||||
{
|
});
|
||||||
params: {
|
const result: PingResponse | SerializedError =
|
||||||
header: {
|
await response.json();
|
||||||
authorization: `Bearer ${this.settings.getSettings().token}`
|
|
||||||
},
|
|
||||||
path: {
|
|
||||||
vault_id: vaultName
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
this.logger.debug(
|
if ("errorType" in result) {
|
||||||
`Ping response: ${JSON.stringify(response.data)}`
|
|
||||||
);
|
|
||||||
|
|
||||||
if (!response.data) {
|
|
||||||
throw new Error(
|
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) {
|
if (result.isAuthenticated) {
|
||||||
return {
|
return {
|
||||||
isSuccessful: true,
|
isSuccessful: true,
|
||||||
|
|
@ -320,29 +283,11 @@ export class SyncService {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
private getDefaultHeaders(): Record<string, string> {
|
||||||
* Create a client and a ping client for the given remote URI.
|
return {
|
||||||
*/
|
"device-id": this.deviceId,
|
||||||
private createClient(remoteUri: string): [Client<paths>, Client<paths>] {
|
authorization: `Bearer ${this.settings.getSettings().token}`
|
||||||
return [
|
};
|
||||||
createClient<paths>({
|
|
||||||
baseUrl: remoteUri,
|
|
||||||
fetch: this.connectionStatus.getFetchImplementation(
|
|
||||||
this.logger,
|
|
||||||
this.fetchImplementation
|
|
||||||
),
|
|
||||||
headers: {
|
|
||||||
authorization: `Bearer ${this.settings.getSettings().token}`
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
createClient<paths>({
|
|
||||||
baseUrl: remoteUri,
|
|
||||||
fetch: this.fetchImplementation,
|
|
||||||
headers: {
|
|
||||||
authorization: `Bearer ${this.settings.getSettings().token}`
|
|
||||||
}
|
|
||||||
})
|
|
||||||
];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private async withRetries<T>(fn: () => Promise<T>): Promise<T> {
|
private async withRetries<T>(fn: () => Promise<T>): Promise<T> {
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,3 @@
|
||||||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
// 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, };
|
||||||
|
|
|
||||||
|
|
@ -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<string>, };
|
||||||
|
|
@ -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<string, never>;
|
|
||||||
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<string, never>;
|
|
||||||
export type operations = Record<string, never>;
|
|
||||||
|
|
@ -9,7 +9,6 @@ import type { Logger } from "../tracing/logger";
|
||||||
import PQueue from "p-queue";
|
import PQueue from "p-queue";
|
||||||
import { hash } from "../utils/hash";
|
import { hash } from "../utils/hash";
|
||||||
import { v4 as uuidv4 } from "uuid";
|
import { v4 as uuidv4 } from "uuid";
|
||||||
import type { components } from "../services/types/http-api";
|
|
||||||
import type { Settings, SyncSettings } from "../persistence/settings";
|
import type { Settings, SyncSettings } from "../persistence/settings";
|
||||||
import type { FileOperations } from "../file-operations/file-operations";
|
import type { FileOperations } from "../file-operations/file-operations";
|
||||||
import { findMatchingFile } from "../utils/find-matching-file";
|
import { findMatchingFile } from "../utils/find-matching-file";
|
||||||
|
|
@ -17,6 +16,7 @@ import type { UnrestrictedSyncer } from "./unrestricted-syncer";
|
||||||
import { createPromise } from "../utils/create-promise";
|
import { createPromise } from "../utils/create-promise";
|
||||||
import { SyncResetError } from "../services/sync-reset-error";
|
import { SyncResetError } from "../services/sync-reset-error";
|
||||||
import { Locks } from "../utils/locks";
|
import { Locks } from "../utils/locks";
|
||||||
|
import { DocumentVersionWithoutContent } from "../services/types/DocumentVersionWithoutContent";
|
||||||
|
|
||||||
export class Syncer {
|
export class Syncer {
|
||||||
private readonly remoteDocumentsLock: Locks<DocumentId>;
|
private readonly remoteDocumentsLock: Locks<DocumentId>;
|
||||||
|
|
@ -255,7 +255,7 @@ export class Syncer {
|
||||||
}
|
}
|
||||||
|
|
||||||
public async syncRemotelyUpdatedFile(
|
public async syncRemotelyUpdatedFile(
|
||||||
remoteVersion: components["schemas"]["DocumentVersionWithoutContent"]
|
remoteVersion: DocumentVersionWithoutContent
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
let document = this.database.getDocumentByDocumentId(
|
let document = this.database.getDocumentByDocumentId(
|
||||||
remoteVersion.documentId
|
remoteVersion.documentId
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,6 @@ import type {
|
||||||
} from "../tracing/sync-history";
|
} from "../tracing/sync-history";
|
||||||
import { SyncStatus, SyncType } from "../tracing/sync-history";
|
import { SyncStatus, SyncType } from "../tracing/sync-history";
|
||||||
import { EMPTY_HASH, hash } from "../utils/hash";
|
import { EMPTY_HASH, hash } from "../utils/hash";
|
||||||
import type { components } from "../services/types/http-api";
|
|
||||||
import { deserialize } from "../utils/deserialize";
|
import { deserialize } from "../utils/deserialize";
|
||||||
import type { Settings } from "../persistence/settings";
|
import type { Settings } from "../persistence/settings";
|
||||||
import type { FileOperations } from "../file-operations/file-operations";
|
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 { FileNotFoundError } from "../file-operations/file-not-found-error";
|
||||||
import { SyncResetError } from "../services/sync-reset-error";
|
import { SyncResetError } from "../services/sync-reset-error";
|
||||||
import { globsToRegexes } from "../utils/globs-to-regexes";
|
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 {
|
export class UnrestrictedSyncer {
|
||||||
private ignorePatterns: RegExp[];
|
private ignorePatterns: RegExp[];
|
||||||
|
|
@ -172,10 +174,8 @@ export class UnrestrictedSyncer {
|
||||||
document.metadata.hash === contentHash && oldPath === undefined
|
document.metadata.hash === contentHash && oldPath === undefined
|
||||||
);
|
);
|
||||||
|
|
||||||
let response:
|
let response: DocumentVersion | DocumentUpdateResponse | undefined =
|
||||||
| components["schemas"]["DocumentVersion"]
|
undefined;
|
||||||
| components["schemas"]["DocumentUpdateResponse"]
|
|
||||||
| undefined = undefined;
|
|
||||||
|
|
||||||
if (areThereLocalChanges) {
|
if (areThereLocalChanges) {
|
||||||
response = await this.syncService.put({
|
response = await this.syncService.put({
|
||||||
|
|
@ -332,7 +332,7 @@ export class UnrestrictedSyncer {
|
||||||
}
|
}
|
||||||
|
|
||||||
public async unrestrictedSyncRemotelyUpdatedFile(
|
public async unrestrictedSyncRemotelyUpdatedFile(
|
||||||
remoteVersion: components["schemas"]["DocumentVersionWithoutContent"],
|
remoteVersion: DocumentVersionWithoutContent,
|
||||||
document?: DocumentRecord
|
document?: DocumentRecord
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
const updateDetails: SyncCreateDetails = {
|
const updateDetails: SyncCreateDetails = {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue