From 56c1f4d58b19bdf8d36c4dd116d4c61a9987bfce Mon Sep 17 00:00:00 2001 From: Andras Schmelczer Date: Sat, 22 Nov 2025 11:06:06 +0000 Subject: [PATCH] Restructure packages --- .../safe-filesystem-operations.ts | 2 +- frontend/sync-client/src/index.ts | 6 ++-- .../sync-client/src/persistence/database.ts | 2 +- frontend/sync-client/src/sync-client.ts | 2 +- .../src/sync-operations/cursor-tracker.ts | 2 +- .../sync-client/src/sync-operations/syncer.ts | 4 +-- .../sync-operations/unrestricted-syncer.ts | 9 +++--- .../fix-sized-cache.test.ts | 0 .../{ => data-structures}/fix-sized-cache.ts | 2 +- .../utils/{ => data-structures}/locks.test.ts | 4 +-- .../src/utils/{ => data-structures}/locks.ts | 2 +- .../{ => data-structures}/min-covered.test.ts | 0 .../{ => data-structures}/min-covered.ts | 0 .../{ => utils}/debugging/log-to-console.ts | 6 ++-- .../debugging/slow-fetch-factory.ts | 8 +++-- .../debugging/slow-web-socket-factory.ts | 7 ++--- frontend/sync-client/src/utils/deserialize.ts | 5 ---- .../src/utils/is-equal-bytes.test.ts | 29 ------------------- .../sync-client/src/utils/is-equal-bytes.ts | 13 --------- 19 files changed, 30 insertions(+), 73 deletions(-) rename frontend/sync-client/src/utils/{ => data-structures}/fix-sized-cache.test.ts (100%) rename frontend/sync-client/src/utils/{ => data-structures}/fix-sized-cache.ts (97%) rename frontend/sync-client/src/utils/{ => data-structures}/locks.test.ts (98%) rename frontend/sync-client/src/utils/{ => data-structures}/locks.ts (98%) rename frontend/sync-client/src/utils/{ => data-structures}/min-covered.test.ts (100%) rename frontend/sync-client/src/utils/{ => data-structures}/min-covered.ts (100%) rename frontend/sync-client/src/{ => utils}/debugging/log-to-console.ts (76%) rename frontend/sync-client/src/{ => utils}/debugging/slow-fetch-factory.ts (56%) rename frontend/sync-client/src/{ => utils}/debugging/slow-web-socket-factory.ts (92%) delete mode 100644 frontend/sync-client/src/utils/deserialize.ts delete mode 100644 frontend/sync-client/src/utils/is-equal-bytes.test.ts delete mode 100644 frontend/sync-client/src/utils/is-equal-bytes.ts diff --git a/frontend/sync-client/src/file-operations/safe-filesystem-operations.ts b/frontend/sync-client/src/file-operations/safe-filesystem-operations.ts index 2c865c9f..10d8bae6 100644 --- a/frontend/sync-client/src/file-operations/safe-filesystem-operations.ts +++ b/frontend/sync-client/src/file-operations/safe-filesystem-operations.ts @@ -1,7 +1,7 @@ import type { RelativePath } from "../persistence/database"; import type { FileSystemOperations } from "./filesystem-operations"; import type { Logger } from "../tracing/logger"; -import { Locks } from "../utils/locks"; +import { Locks } from "../utils/data-structures/locks"; import { FileNotFoundError } from "./file-not-found-error"; import type { TextWithCursors } from "reconcile-text"; diff --git a/frontend/sync-client/src/index.ts b/frontend/sync-client/src/index.ts index a73f63dd..7a2014b8 100644 --- a/frontend/sync-client/src/index.ts +++ b/frontend/sync-client/src/index.ts @@ -1,6 +1,6 @@ -import { logToConsole } from "./debugging/log-to-console"; -import { slowFetchFactory } from "./debugging/slow-fetch-factory"; -import { slowWebSocketFactory } from "./debugging/slow-web-socket-factory"; +import { logToConsole } from "./utils/debugging/log-to-console"; +import { slowFetchFactory } from "./utils/debugging/slow-fetch-factory"; +import { slowWebSocketFactory } from "./utils/debugging/slow-web-socket-factory"; import { getRandomColor } from "./utils/get-random-color"; import { lineAndColumnToPosition } from "./utils/line-and-column-to-position"; import { positionToLineAndColumn } from "./utils/position-to-line-and-column"; diff --git a/frontend/sync-client/src/persistence/database.ts b/frontend/sync-client/src/persistence/database.ts index 9425c629..827cf164 100644 --- a/frontend/sync-client/src/persistence/database.ts +++ b/frontend/sync-client/src/persistence/database.ts @@ -1,6 +1,6 @@ import type { Logger } from "../tracing/logger"; import { EMPTY_HASH } from "../utils/hash"; -import { CoveredValues } from "../utils/min-covered"; +import { CoveredValues } from "../utils/data-structures/min-covered"; export type VaultUpdateId = number; export type DocumentId = string; diff --git a/frontend/sync-client/src/sync-client.ts b/frontend/sync-client/src/sync-client.ts index 9547af65..28843d3d 100644 --- a/frontend/sync-client/src/sync-client.ts +++ b/frontend/sync-client/src/sync-client.ts @@ -21,7 +21,7 @@ import { CursorTracker } from "./sync-operations/cursor-tracker"; import type { CursorSpan } from "./services/types/CursorSpan"; import type { MaybeOutdatedClientCursors } from "./types/maybe-outdated-client-cursors"; import { FileChangeNotifier } from "./sync-operations/file-change-notifier"; -import { FixedSizeDocumentCache } from "./utils/fix-sized-cache"; +import { FixedSizeDocumentCache } from "./utils/data-structures/fix-sized-cache"; import { setUpTelemetry } from "./utils/set-up-telemetry"; export class SyncClient { diff --git a/frontend/sync-client/src/sync-operations/cursor-tracker.ts b/frontend/sync-client/src/sync-operations/cursor-tracker.ts index 17f166c4..32048ba5 100644 --- a/frontend/sync-client/src/sync-operations/cursor-tracker.ts +++ b/frontend/sync-client/src/sync-operations/cursor-tracker.ts @@ -8,7 +8,7 @@ import type { MaybeOutdatedClientCursors } from "../types/maybe-outdated-client- import { DocumentUpToDateness } from "../types/document-up-to-dateness"; import { hash } from "../utils/hash"; import type { FileChangeNotifier } from "./file-change-notifier"; -import { Lock } from "../utils/locks"; +import { Lock } from "../utils/data-structures/locks"; // Cursor positions are updated separately from documents. However, a given cursor position is only // valid within a certain version of the document it belongs to. This class tracks previous and the latest diff --git a/frontend/sync-client/src/sync-operations/syncer.ts b/frontend/sync-client/src/sync-operations/syncer.ts index a4badd9a..920a6423 100644 --- a/frontend/sync-client/src/sync-operations/syncer.ts +++ b/frontend/sync-client/src/sync-operations/syncer.ts @@ -15,9 +15,9 @@ import { findMatchingFile } from "../utils/find-matching-file"; 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 { Locks } from "../utils/data-structures/locks"; import type { DocumentVersionWithoutContent } from "../services/types/DocumentVersionWithoutContent"; -import type { FixedSizeDocumentCache } from "../utils/fix-sized-cache"; +import type { FixedSizeDocumentCache } from "../utils/data-structures/fix-sized-cache"; export class Syncer { private readonly remoteDocumentsLock: Locks; diff --git a/frontend/sync-client/src/sync-operations/unrestricted-syncer.ts b/frontend/sync-client/src/sync-operations/unrestricted-syncer.ts index f9f6e2c1..daffe4bf 100644 --- a/frontend/sync-client/src/sync-operations/unrestricted-syncer.ts +++ b/frontend/sync-client/src/sync-operations/unrestricted-syncer.ts @@ -18,7 +18,8 @@ import type { } from "../tracing/sync-history"; import { SyncStatus, SyncType } from "../tracing/sync-history"; import { EMPTY_HASH, hash } from "../utils/hash"; -import { deserialize } from "../utils/deserialize"; + +import { base64ToBytes } from "byte-base64"; import type { Settings } from "../persistence/settings"; import type { FileOperations } from "../file-operations/file-operations"; import { createPromise } from "../utils/create-promise"; @@ -28,7 +29,7 @@ import { globsToRegexes } from "../utils/globs-to-regexes"; import type { DocumentVersion } from "../services/types/DocumentVersion"; import type { DocumentUpdateResponse } from "../services/types/DocumentUpdateResponse"; import type { DocumentVersionWithoutContent } from "../services/types/DocumentVersionWithoutContent"; -import type { FixedSizeDocumentCache } from "../utils/fix-sized-cache"; +import type { FixedSizeDocumentCache } from "../utils/data-structures/fix-sized-cache"; import { isFileTypeMergable } from "../utils/is-file-type-mergable"; import { isBinary } from "../utils/is-binary"; @@ -292,7 +293,7 @@ export class UnrestrictedSyncer { } if (!("type" in response) || response.type === "MergingUpdate") { - const responseBytes = deserialize(response.contentBase64); + const responseBytes = base64ToBytes(response.contentBase64); contentHash = hash(responseBytes); this.database.updateDocumentMetadata( @@ -439,7 +440,7 @@ export class UnrestrictedSyncer { return; } - const contentBytes = deserialize(content); + const contentBytes = base64ToBytes(content); await this.operations.ensureClearPath(remoteVersion.relativePath); diff --git a/frontend/sync-client/src/utils/fix-sized-cache.test.ts b/frontend/sync-client/src/utils/data-structures/fix-sized-cache.test.ts similarity index 100% rename from frontend/sync-client/src/utils/fix-sized-cache.test.ts rename to frontend/sync-client/src/utils/data-structures/fix-sized-cache.test.ts diff --git a/frontend/sync-client/src/utils/fix-sized-cache.ts b/frontend/sync-client/src/utils/data-structures/fix-sized-cache.ts similarity index 97% rename from frontend/sync-client/src/utils/fix-sized-cache.ts rename to frontend/sync-client/src/utils/data-structures/fix-sized-cache.ts index cf0ba47e..8984b790 100644 --- a/frontend/sync-client/src/utils/fix-sized-cache.ts +++ b/frontend/sync-client/src/utils/data-structures/fix-sized-cache.ts @@ -1,6 +1,6 @@ // Implements an in-memory fixed-size cache for document contents, -import type { VaultUpdateId } from "../persistence/database"; +import type { VaultUpdateId } from "../../persistence/database"; // Doubly-linked list node for O(1) LRU operations class LRUNode { diff --git a/frontend/sync-client/src/utils/locks.test.ts b/frontend/sync-client/src/utils/data-structures/locks.test.ts similarity index 98% rename from frontend/sync-client/src/utils/locks.test.ts rename to frontend/sync-client/src/utils/data-structures/locks.test.ts index 5626becc..460f984d 100644 --- a/frontend/sync-client/src/utils/locks.test.ts +++ b/frontend/sync-client/src/utils/data-structures/locks.test.ts @@ -1,7 +1,7 @@ import { describe, it, beforeEach } from "node:test"; import assert from "node:assert"; -import { Logger } from "../tracing/logger"; -import type { RelativePath } from "../persistence/database"; +import { Logger } from "../../tracing/logger"; +import type { RelativePath } from "../../persistence/database"; import { Locks } from "./locks"; describe("withLock", () => { diff --git a/frontend/sync-client/src/utils/locks.ts b/frontend/sync-client/src/utils/data-structures/locks.ts similarity index 98% rename from frontend/sync-client/src/utils/locks.ts rename to frontend/sync-client/src/utils/data-structures/locks.ts index e09da236..6a801e12 100644 --- a/frontend/sync-client/src/utils/locks.ts +++ b/frontend/sync-client/src/utils/data-structures/locks.ts @@ -1,4 +1,4 @@ -import type { Logger } from "../tracing/logger"; +import type { Logger } from "../../tracing/logger"; /** * Manages exclusive locks on items to prevent concurrent modifications. diff --git a/frontend/sync-client/src/utils/min-covered.test.ts b/frontend/sync-client/src/utils/data-structures/min-covered.test.ts similarity index 100% rename from frontend/sync-client/src/utils/min-covered.test.ts rename to frontend/sync-client/src/utils/data-structures/min-covered.test.ts diff --git a/frontend/sync-client/src/utils/min-covered.ts b/frontend/sync-client/src/utils/data-structures/min-covered.ts similarity index 100% rename from frontend/sync-client/src/utils/min-covered.ts rename to frontend/sync-client/src/utils/data-structures/min-covered.ts diff --git a/frontend/sync-client/src/debugging/log-to-console.ts b/frontend/sync-client/src/utils/debugging/log-to-console.ts similarity index 76% rename from frontend/sync-client/src/debugging/log-to-console.ts rename to frontend/sync-client/src/utils/debugging/log-to-console.ts index ace58db0..2d1a12e8 100644 --- a/frontend/sync-client/src/debugging/log-to-console.ts +++ b/frontend/sync-client/src/utils/debugging/log-to-console.ts @@ -1,6 +1,6 @@ -import type { SyncClient } from "../sync-client"; -import type { LogLine } from "../tracing/logger"; -import { LogLevel } from "../tracing/logger"; +import type { SyncClient } from "../../sync-client"; +import type { LogLine } from "../../tracing/logger"; +import { LogLevel } from "../../tracing/logger"; export function logToConsole(client: SyncClient): void { client.logger.addOnMessageListener((logLine: LogLine) => { diff --git a/frontend/sync-client/src/debugging/slow-fetch-factory.ts b/frontend/sync-client/src/utils/debugging/slow-fetch-factory.ts similarity index 56% rename from frontend/sync-client/src/debugging/slow-fetch-factory.ts rename to frontend/sync-client/src/utils/debugging/slow-fetch-factory.ts index cd07dd1a..4c2ddedb 100644 --- a/frontend/sync-client/src/debugging/slow-fetch-factory.ts +++ b/frontend/sync-client/src/utils/debugging/slow-fetch-factory.ts @@ -1,4 +1,4 @@ -import { sleep } from "../utils/sleep"; +import { sleep } from "../sleep"; export const slowFetchFactory = (jitterScaleInSeconds: number) => @@ -7,10 +7,14 @@ export const slowFetchFactory = init?: RequestInit ): Promise => { if (jitterScaleInSeconds > 0) { - await sleep(Math.random() * jitterScaleInSeconds * 1000); + await sleep(((Math.random() * jitterScaleInSeconds) / 2) * 1000); } const response = await fetch(input, init); + if (jitterScaleInSeconds > 0) { + await sleep(((Math.random() * jitterScaleInSeconds) / 2) * 1000); + } + return response; }; diff --git a/frontend/sync-client/src/debugging/slow-web-socket-factory.ts b/frontend/sync-client/src/utils/debugging/slow-web-socket-factory.ts similarity index 92% rename from frontend/sync-client/src/debugging/slow-web-socket-factory.ts rename to frontend/sync-client/src/utils/debugging/slow-web-socket-factory.ts index 51a27a5f..ea77117a 100644 --- a/frontend/sync-client/src/debugging/slow-web-socket-factory.ts +++ b/frontend/sync-client/src/utils/debugging/slow-web-socket-factory.ts @@ -1,12 +1,11 @@ -import { sleep } from "../utils/sleep"; -import { Locks } from "../utils/locks"; -import type { Logger } from "../tracing/logger"; +import { sleep } from "../sleep"; +import { Locks } from "../data-structures/locks"; +import type { Logger } from "../../tracing/logger"; export function slowWebSocketFactory( jitterScaleInSeconds: number, logger: Logger ): typeof WebSocket { - // eslint-disable-next-line return class FlakyWebSocket extends WebSocket { private static readonly RECEIVE_KEY = "websocket-receive"; private static readonly SEND_KEY = "websocket-send"; diff --git a/frontend/sync-client/src/utils/deserialize.ts b/frontend/sync-client/src/utils/deserialize.ts deleted file mode 100644 index 4255479f..00000000 --- a/frontend/sync-client/src/utils/deserialize.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { base64ToBytes } from "byte-base64"; - -export function deserialize(data: string): Uint8Array { - return base64ToBytes(data); -} diff --git a/frontend/sync-client/src/utils/is-equal-bytes.test.ts b/frontend/sync-client/src/utils/is-equal-bytes.test.ts deleted file mode 100644 index a887309f..00000000 --- a/frontend/sync-client/src/utils/is-equal-bytes.test.ts +++ /dev/null @@ -1,29 +0,0 @@ -import { describe, it } from "node:test"; -import assert from "node:assert"; -import { isEqualBytes } from "./is-equal-bytes"; - -describe("isEqualBytes", () => { - it("should return true for equal byte arrays", () => { - const bytes1 = new Uint8Array([1, 2, 3, 4]); - const bytes2 = new Uint8Array([1, 2, 3, 4]); - assert.strictEqual(isEqualBytes(bytes1, bytes2), true); - }); - - it("should return false for byte arrays of different lengths", () => { - const bytes1 = new Uint8Array([1, 2, 3, 4]); - const bytes2 = new Uint8Array([1, 2, 3]); - assert.strictEqual(isEqualBytes(bytes1, bytes2), false); - }); - - it("should return true for empty byte arrays", () => { - const bytes1 = new Uint8Array([]); - const bytes2 = new Uint8Array([]); - assert.strictEqual(isEqualBytes(bytes1, bytes2), true); - }); - - it("should return false for byte arrays with same length but different content", () => { - const bytes1 = new Uint8Array([1, 2, 3, 4]); - const bytes2 = new Uint8Array([4, 3, 2, 1]); - assert.strictEqual(isEqualBytes(bytes1, bytes2), false); - }); -}); diff --git a/frontend/sync-client/src/utils/is-equal-bytes.ts b/frontend/sync-client/src/utils/is-equal-bytes.ts deleted file mode 100644 index d0688d44..00000000 --- a/frontend/sync-client/src/utils/is-equal-bytes.ts +++ /dev/null @@ -1,13 +0,0 @@ -export function isEqualBytes(bytes1: Uint8Array, bytes2: Uint8Array): boolean { - if (bytes1.length !== bytes2.length) { - return false; - } - - for (let i = 0; i < bytes1.length; i++) { - if (bytes1[i] !== bytes2[i]) { - return false; - } - } - - return true; -}