Format & lint
This commit is contained in:
parent
fefac224b0
commit
7f62273e72
179 changed files with 2210 additions and 1319 deletions
|
|
@ -19,7 +19,11 @@ export class FetchController {
|
|||
private _canFetch: boolean,
|
||||
private readonly logger: Logger
|
||||
) {
|
||||
({ promise: this.until, resolve: this.resolveUntil, reject: this.rejectUntil } = Promise.withResolvers<symbol>());
|
||||
({
|
||||
promise: this.until,
|
||||
resolve: this.resolveUntil,
|
||||
reject: this.rejectUntil
|
||||
} = Promise.withResolvers<symbol>());
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -40,7 +44,11 @@ export class FetchController {
|
|||
|
||||
if (!this.isResetting) {
|
||||
const previousResolve = this.resolveUntil;
|
||||
({ promise: this.until, resolve: this.resolveUntil, reject: this.rejectUntil } = Promise.withResolvers<symbol>());
|
||||
({
|
||||
promise: this.until,
|
||||
resolve: this.resolveUntil,
|
||||
reject: this.rejectUntil
|
||||
} = Promise.withResolvers<symbol>());
|
||||
previousResolve(FetchController.UNTIL_RESOLUTION);
|
||||
}
|
||||
}
|
||||
|
|
@ -78,7 +86,11 @@ export class FetchController {
|
|||
}
|
||||
|
||||
this.isResetting = false;
|
||||
({ promise: this.until, resolve: this.resolveUntil, reject: this.rejectUntil } = Promise.withResolvers<symbol>());
|
||||
({
|
||||
promise: this.until,
|
||||
resolve: this.resolveUntil,
|
||||
reject: this.rejectUntil
|
||||
} = Promise.withResolvers<symbol>());
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -66,6 +66,42 @@ export class SyncService {
|
|||
return result;
|
||||
}
|
||||
|
||||
private static async throwIfNotOk(
|
||||
response: Response,
|
||||
operation: string
|
||||
): Promise<void> {
|
||||
if (response.ok) return;
|
||||
const message = `Failed to ${operation}: ${await SyncService.errorFromResponse(response)}`;
|
||||
// 429 is the only 4xx the server uses for *transient* contention
|
||||
// (`WriteBusyError` → HTTP 429). Every other 4xx means the request
|
||||
// is permanently rejected and shouldn't be retried.
|
||||
if (response.status === 429) {
|
||||
throw new Error(message);
|
||||
}
|
||||
if (response.status >= 400 && response.status < 500) {
|
||||
throw new HttpClientError(response.status, message);
|
||||
}
|
||||
throw new Error(message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Signal that the service is shutting down so any in-flight
|
||||
* `retryForever` exits at its next iteration instead of looping
|
||||
* indefinitely after the rest of the client has stopped. Idempotent.
|
||||
*/
|
||||
public stop(): void {
|
||||
this.isStopped = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Re-enable the service after a `stop()`. Used when the client pauses
|
||||
* and resumes syncing within the same lifecycle (e.g. user toggles
|
||||
* sync off and on).
|
||||
*/
|
||||
public resume(): void {
|
||||
this.isStopped = false;
|
||||
}
|
||||
|
||||
public async create({
|
||||
relativePath,
|
||||
lastSeenVaultUpdateId,
|
||||
|
|
@ -146,8 +182,7 @@ export class SyncService {
|
|||
(await response.json()) as DocumentUpdateResponse; // eslint-disable-line @typescript-eslint/no-unsafe-type-assertion
|
||||
|
||||
this.logger.debug(
|
||||
`Updated document ${JSON.stringify(result)} with id ${
|
||||
result.documentId
|
||||
`Updated document ${JSON.stringify(result)} with id ${result.documentId
|
||||
}}`
|
||||
);
|
||||
|
||||
|
|
@ -193,8 +228,7 @@ export class SyncService {
|
|||
(await response.json()) as DocumentUpdateResponse; // eslint-disable-line @typescript-eslint/no-unsafe-type-assertion
|
||||
|
||||
this.logger.debug(
|
||||
`Updated document ${JSON.stringify(result)} with id ${
|
||||
result.documentId
|
||||
`Updated document ${JSON.stringify(result)} with id ${result.documentId
|
||||
}}`
|
||||
);
|
||||
|
||||
|
|
@ -284,7 +318,10 @@ export class SyncService {
|
|||
}
|
||||
);
|
||||
|
||||
await SyncService.throwIfNotOk(response, "get document version content");
|
||||
await SyncService.throwIfNotOk(
|
||||
response,
|
||||
"get document version content"
|
||||
);
|
||||
|
||||
const result = await response.bytes();
|
||||
this.logger.debug(
|
||||
|
|
@ -300,7 +337,7 @@ export class SyncService {
|
|||
return this.retryForever(async () => {
|
||||
this.logger.debug(
|
||||
"Getting all documents" +
|
||||
(since != null ? ` since ${since}` : "")
|
||||
(since != null ? ` since ${since}` : "")
|
||||
);
|
||||
|
||||
const url = new URL(this.getUrl("/documents"));
|
||||
|
|
@ -369,30 +406,10 @@ export class SyncService {
|
|||
return headers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Signal that the service is shutting down so any in-flight
|
||||
* `retryForever` exits at its next iteration instead of looping
|
||||
* indefinitely after the rest of the client has stopped. Idempotent.
|
||||
*/
|
||||
public stop(): void {
|
||||
this.isStopped = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Re-enable the service after a `stop()`. Used when the client pauses
|
||||
* and resumes syncing within the same lifecycle (e.g. user toggles
|
||||
* sync off and on).
|
||||
*/
|
||||
public resume(): void {
|
||||
this.isStopped = false;
|
||||
}
|
||||
|
||||
private async retryForever<T>(fn: () => Promise<T>): Promise<T> {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
||||
while (true) {
|
||||
if (this.isStopped) {
|
||||
throw new SyncResetError();
|
||||
}
|
||||
this.throwIfStopped();
|
||||
try {
|
||||
return await fn();
|
||||
} catch (e) {
|
||||
|
|
@ -402,9 +419,7 @@ export class SyncService {
|
|||
) {
|
||||
throw e;
|
||||
}
|
||||
if (this.isStopped) {
|
||||
throw new SyncResetError();
|
||||
}
|
||||
this.throwIfStopped();
|
||||
|
||||
const retryInterval =
|
||||
this.settings.getSettings().networkRetryIntervalMs;
|
||||
|
|
@ -416,21 +431,9 @@ export class SyncService {
|
|||
}
|
||||
}
|
||||
|
||||
private static async throwIfNotOk(
|
||||
response: Response,
|
||||
operation: string
|
||||
): Promise<void> {
|
||||
if (response.ok) return;
|
||||
const message = `Failed to ${operation}: ${await SyncService.errorFromResponse(response)}`;
|
||||
// 429 is the only 4xx the server uses for *transient* contention
|
||||
// (`WriteBusyError` → HTTP 429). Every other 4xx means the request
|
||||
// is permanently rejected and shouldn't be retried.
|
||||
if (response.status === 429) {
|
||||
throw new Error(message);
|
||||
private throwIfStopped(): void {
|
||||
if (this.isStopped) {
|
||||
throw new SyncResetError();
|
||||
}
|
||||
if (response.status >= 400 && response.status < 500) {
|
||||
throw new HttpClientError(response.status, message);
|
||||
}
|
||||
throw new Error(message);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,8 @@
|
|||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
import type { DocumentWithCursors } from "./DocumentWithCursors";
|
||||
|
||||
export interface ClientCursors { userName: string, deviceId: string, documentsWithCursors: DocumentWithCursors[], }
|
||||
export interface ClientCursors {
|
||||
userName: string;
|
||||
deviceId: string;
|
||||
documentsWithCursors: DocumentWithCursors[];
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,3 +1,7 @@
|
|||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
|
||||
export interface CreateDocumentVersion { relative_path: string, last_seen_vault_update_id: number, content: number[], }
|
||||
export interface CreateDocumentVersion {
|
||||
relative_path: string;
|
||||
last_seen_vault_update_id: number;
|
||||
content: number[];
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,6 @@
|
|||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
import type { DocumentWithCursors } from "./DocumentWithCursors";
|
||||
|
||||
export interface CursorPositionFromClient { documentsWithCursors: DocumentWithCursors[], }
|
||||
export interface CursorPositionFromClient {
|
||||
documentsWithCursors: DocumentWithCursors[];
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,6 @@
|
|||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
import type { ClientCursors } from "./ClientCursors";
|
||||
|
||||
export interface CursorPositionFromServer { clients: ClientCursors[], }
|
||||
export interface CursorPositionFromServer {
|
||||
clients: ClientCursors[];
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,3 +1,6 @@
|
|||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
|
||||
export interface CursorSpan { start: number, end: number, }
|
||||
export interface CursorSpan {
|
||||
start: number;
|
||||
end: number;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,4 +5,6 @@ import type { DocumentVersionWithoutContent } from "./DocumentVersionWithoutCont
|
|||
/**
|
||||
* Response to a create/update document request.
|
||||
*/
|
||||
export type DocumentUpdateResponse = { "type": "FastForwardUpdate" } & DocumentVersionWithoutContent | { "type": "MergingUpdate" } & DocumentVersion;
|
||||
export type DocumentUpdateResponse =
|
||||
| ({ type: "FastForwardUpdate" } & DocumentVersionWithoutContent)
|
||||
| ({ type: "MergingUpdate" } & DocumentVersion);
|
||||
|
|
|
|||
|
|
@ -1,3 +1,12 @@
|
|||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
|
||||
export interface DocumentVersion { vaultUpdateId: number, documentId: string, relativePath: string, updatedDate: string, contentBase64: string, isDeleted: boolean, userId: string, deviceId: string, }
|
||||
export interface DocumentVersion {
|
||||
vaultUpdateId: number;
|
||||
documentId: string;
|
||||
relativePath: string;
|
||||
updatedDate: string;
|
||||
contentBase64: string;
|
||||
isDeleted: boolean;
|
||||
userId: string;
|
||||
deviceId: string;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,3 +1,12 @@
|
|||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
|
||||
export interface DocumentVersionWithoutContent { vaultUpdateId: number, documentId: string, relativePath: string, updatedDate: string, isDeleted: boolean, userId: string, deviceId: string, contentSize: number, }
|
||||
export interface DocumentVersionWithoutContent {
|
||||
vaultUpdateId: number;
|
||||
documentId: string;
|
||||
relativePath: string;
|
||||
updatedDate: string;
|
||||
isDeleted: boolean;
|
||||
userId: string;
|
||||
deviceId: string;
|
||||
contentSize: number;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,9 @@
|
|||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
import type { CursorSpan } from "./CursorSpan";
|
||||
|
||||
export interface DocumentWithCursors { vaultUpdateId: number | null, documentId: string, relativePath: string, cursors: CursorSpan[], }
|
||||
export interface DocumentWithCursors {
|
||||
vaultUpdateId: number | null;
|
||||
documentId: string;
|
||||
relativePath: string;
|
||||
cursors: CursorSpan[];
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,8 +4,10 @@ import type { DocumentVersionWithoutContent } from "./DocumentVersionWithoutCont
|
|||
/**
|
||||
* Response to a fetch latest documents request.
|
||||
*/
|
||||
export interface FetchLatestDocumentsResponse { latestDocuments: DocumentVersionWithoutContent[],
|
||||
/**
|
||||
* The update ID of the latest document in the response.
|
||||
*/
|
||||
lastUpdateId: bigint, }
|
||||
export interface FetchLatestDocumentsResponse {
|
||||
latestDocuments: DocumentVersionWithoutContent[];
|
||||
/**
|
||||
* The update ID of the latest document in the response.
|
||||
*/
|
||||
lastUpdateId: bigint;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,4 +4,8 @@ import type { VaultInfo } from "./VaultInfo";
|
|||
/**
|
||||
* Response to listing vaults accessible to the authenticated user.
|
||||
*/
|
||||
export interface ListVaultsResponse { vaults: VaultInfo[], hasMore: boolean, userName: string, }
|
||||
export interface ListVaultsResponse {
|
||||
vaults: VaultInfo[];
|
||||
hasMore: boolean;
|
||||
userName: string;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,22 +3,23 @@
|
|||
/**
|
||||
* Response to a ping request.
|
||||
*/
|
||||
export interface PingResponse {
|
||||
/**
|
||||
* Semantic version of the server.
|
||||
*/
|
||||
serverVersion: string,
|
||||
/**
|
||||
* Whether the client is authenticated based on the sent Authorization
|
||||
* header.
|
||||
*/
|
||||
isAuthenticated: boolean,
|
||||
/**
|
||||
* List of file extensions that are allowed to be merged.
|
||||
*/
|
||||
mergeableFileExtensions: string[],
|
||||
/**
|
||||
* API version ensuring backwards & forwards compatibility between the client
|
||||
* and server.
|
||||
*/
|
||||
supportedApiVersion: number, }
|
||||
export interface PingResponse {
|
||||
/**
|
||||
* Semantic version of the server.
|
||||
*/
|
||||
serverVersion: string;
|
||||
/**
|
||||
* Whether the client is authenticated based on the sent Authorization
|
||||
* header.
|
||||
*/
|
||||
isAuthenticated: boolean;
|
||||
/**
|
||||
* List of file extensions that are allowed to be merged.
|
||||
*/
|
||||
mergeableFileExtensions: string[];
|
||||
/**
|
||||
* API version ensuring backwards & forwards compatibility between the client
|
||||
* and server.
|
||||
*/
|
||||
supportedApiVersion: number;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,3 +1,7 @@
|
|||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
|
||||
export interface SerializedError { errorType: string, message: string, causes: string[], }
|
||||
export interface SerializedError {
|
||||
errorType: string;
|
||||
message: string;
|
||||
causes: string[];
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,3 +1,7 @@
|
|||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
|
||||
export interface UpdateTextDocumentVersion { parentVersionId: number, relativePath: string, content: (number | string)[], }
|
||||
export interface UpdateTextDocumentVersion {
|
||||
parentVersionId: number;
|
||||
relativePath: string;
|
||||
content: (number | string)[];
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,4 +4,7 @@ import type { DocumentVersionWithoutContent } from "./DocumentVersionWithoutCont
|
|||
/**
|
||||
* Response to a vault history request (paginated).
|
||||
*/
|
||||
export interface VaultHistoryResponse { versions: DocumentVersionWithoutContent[], hasMore: boolean, }
|
||||
export interface VaultHistoryResponse {
|
||||
versions: DocumentVersionWithoutContent[];
|
||||
hasMore: boolean;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,4 +3,8 @@
|
|||
/**
|
||||
* Summary of a single vault returned by the list-vaults endpoint.
|
||||
*/
|
||||
export interface VaultInfo { name: string, documentCount: number, createdAt: string | null, }
|
||||
export interface VaultInfo {
|
||||
name: string;
|
||||
documentCount: number;
|
||||
createdAt: string | null;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,4 +2,6 @@
|
|||
import type { CursorPositionFromClient } from "./CursorPositionFromClient";
|
||||
import type { WebSocketHandshake } from "./WebSocketHandshake";
|
||||
|
||||
export type WebSocketClientMessage = { "type": "handshake" } & WebSocketHandshake | { "type": "cursorPositions" } & CursorPositionFromClient;
|
||||
export type WebSocketClientMessage =
|
||||
| ({ type: "handshake" } & WebSocketHandshake)
|
||||
| ({ type: "cursorPositions" } & CursorPositionFromClient);
|
||||
|
|
|
|||
|
|
@ -1,3 +1,7 @@
|
|||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
|
||||
export interface WebSocketHandshake { token: string, deviceId: string, lastSeenVaultUpdateId: number | null, }
|
||||
export interface WebSocketHandshake {
|
||||
token: string;
|
||||
deviceId: string;
|
||||
lastSeenVaultUpdateId: number | null;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,4 +2,6 @@
|
|||
import type { CursorPositionFromServer } from "./CursorPositionFromServer";
|
||||
import type { WebSocketVaultUpdate } from "./WebSocketVaultUpdate";
|
||||
|
||||
export type WebSocketServerMessage = { "type": "vaultUpdate" } & WebSocketVaultUpdate | { "type": "cursorPositions" } & CursorPositionFromServer;
|
||||
export type WebSocketServerMessage =
|
||||
| ({ type: "vaultUpdate" } & WebSocketVaultUpdate)
|
||||
| ({ type: "cursorPositions" } & CursorPositionFromServer);
|
||||
|
|
|
|||
|
|
@ -1,4 +1,6 @@
|
|||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
import type { DocumentVersionWithoutContent } from "./DocumentVersionWithoutContent";
|
||||
|
||||
export interface WebSocketVaultUpdate { document: DocumentVersionWithoutContent, }
|
||||
export interface WebSocketVaultUpdate {
|
||||
document: DocumentVersionWithoutContent;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -58,8 +58,10 @@ export class WebSocketManager {
|
|||
}
|
||||
|
||||
public async stop(): Promise<void> {
|
||||
const { promise, resolve } = Promise.withResolvers<void>();
|
||||
this.resolveDisconnectingPromise = resolve;
|
||||
const { promise, resolve } = Promise.withResolvers<undefined>();
|
||||
this.resolveDisconnectingPromise = (): void => {
|
||||
resolve(undefined);
|
||||
};
|
||||
|
||||
this.isStopped = true;
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue