Remove openapi from frontend
This commit is contained in:
parent
9753eaeff5
commit
7956a92bec
10 changed files with 157 additions and 1062 deletions
|
|
@ -51,7 +51,10 @@ export class ConnectionStatus {
|
|||
logger: Logger,
|
||||
fetch: typeof globalThis.fetch = globalThis.fetch
|
||||
): typeof globalThis.fetch {
|
||||
return async (input: RequestInfo | URL): Promise<Response> => {
|
||||
return async (
|
||||
input: RequestInfo | URL,
|
||||
init?: RequestInit
|
||||
): Promise<Response> => {
|
||||
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;
|
||||
|
|
|
|||
|
|
@ -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<paths>;
|
||||
private pingClient: Client<paths>;
|
||||
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<components["schemas"]["DocumentVersionWithoutContent"]> {
|
||||
const { vaultName } = this.settings.getSettings();
|
||||
|
||||
}): Promise<DocumentVersionWithoutContent> {
|
||||
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<components["schemas"]["DocumentUpdateResponse"]> {
|
||||
const { vaultName } = this.settings.getSettings();
|
||||
|
||||
}): Promise<DocumentUpdateResponse> {
|
||||
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<components["schemas"]["DocumentVersionWithoutContent"]> {
|
||||
}): Promise<DocumentVersionWithoutContent> {
|
||||
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<components["schemas"]["DocumentVersion"]> {
|
||||
const { vaultName } = this.settings.getSettings();
|
||||
|
||||
}): Promise<DocumentVersion> {
|
||||
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<components["schemas"]["FetchLatestDocumentsResponse"]> {
|
||||
): Promise<FetchLatestDocumentsResponse> {
|
||||
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<CheckConnectionResult> {
|
||||
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<paths>, Client<paths>] {
|
||||
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 getDefaultHeaders(): Record<string, string> {
|
||||
return {
|
||||
"device-id": this.deviceId,
|
||||
authorization: `Bearer ${this.settings.getSettings().token}`
|
||||
};
|
||||
}
|
||||
|
||||
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.
|
||||
|
||||
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 { 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<DocumentId>;
|
||||
|
|
@ -255,7 +255,7 @@ export class Syncer {
|
|||
}
|
||||
|
||||
public async syncRemotelyUpdatedFile(
|
||||
remoteVersion: components["schemas"]["DocumentVersionWithoutContent"]
|
||||
remoteVersion: DocumentVersionWithoutContent
|
||||
): Promise<void> {
|
||||
let document = this.database.getDocumentByDocumentId(
|
||||
remoteVersion.documentId
|
||||
|
|
|
|||
|
|
@ -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<void> {
|
||||
const updateDetails: SyncCreateDetails = {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue