Restructure packages

This commit is contained in:
Andras Schmelczer 2025-11-22 11:06:06 +00:00
parent 812eb7a644
commit 56c1f4d58b
19 changed files with 30 additions and 73 deletions

View file

@ -1,7 +1,7 @@
import type { RelativePath } from "../persistence/database"; import type { RelativePath } from "../persistence/database";
import type { FileSystemOperations } from "./filesystem-operations"; import type { FileSystemOperations } from "./filesystem-operations";
import type { Logger } from "../tracing/logger"; 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 { FileNotFoundError } from "./file-not-found-error";
import type { TextWithCursors } from "reconcile-text"; import type { TextWithCursors } from "reconcile-text";

View file

@ -1,6 +1,6 @@
import { logToConsole } from "./debugging/log-to-console"; import { logToConsole } from "./utils/debugging/log-to-console";
import { slowFetchFactory } from "./debugging/slow-fetch-factory"; import { slowFetchFactory } from "./utils/debugging/slow-fetch-factory";
import { slowWebSocketFactory } from "./debugging/slow-web-socket-factory"; import { slowWebSocketFactory } from "./utils/debugging/slow-web-socket-factory";
import { getRandomColor } from "./utils/get-random-color"; import { getRandomColor } from "./utils/get-random-color";
import { lineAndColumnToPosition } from "./utils/line-and-column-to-position"; import { lineAndColumnToPosition } from "./utils/line-and-column-to-position";
import { positionToLineAndColumn } from "./utils/position-to-line-and-column"; import { positionToLineAndColumn } from "./utils/position-to-line-and-column";

View file

@ -1,6 +1,6 @@
import type { Logger } from "../tracing/logger"; import type { Logger } from "../tracing/logger";
import { EMPTY_HASH } from "../utils/hash"; 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 VaultUpdateId = number;
export type DocumentId = string; export type DocumentId = string;

View file

@ -21,7 +21,7 @@ import { CursorTracker } from "./sync-operations/cursor-tracker";
import type { CursorSpan } from "./services/types/CursorSpan"; import type { CursorSpan } from "./services/types/CursorSpan";
import type { MaybeOutdatedClientCursors } from "./types/maybe-outdated-client-cursors"; import type { MaybeOutdatedClientCursors } from "./types/maybe-outdated-client-cursors";
import { FileChangeNotifier } from "./sync-operations/file-change-notifier"; 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"; import { setUpTelemetry } from "./utils/set-up-telemetry";
export class SyncClient { export class SyncClient {

View file

@ -8,7 +8,7 @@ import type { MaybeOutdatedClientCursors } from "../types/maybe-outdated-client-
import { DocumentUpToDateness } from "../types/document-up-to-dateness"; import { DocumentUpToDateness } from "../types/document-up-to-dateness";
import { hash } from "../utils/hash"; import { hash } from "../utils/hash";
import type { FileChangeNotifier } from "./file-change-notifier"; 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 // 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 // valid within a certain version of the document it belongs to. This class tracks previous and the latest

View file

@ -15,9 +15,9 @@ import { findMatchingFile } from "../utils/find-matching-file";
import type { UnrestrictedSyncer } from "./unrestricted-syncer"; 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/data-structures/locks";
import type { DocumentVersionWithoutContent } from "../services/types/DocumentVersionWithoutContent"; 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 { export class Syncer {
private readonly remoteDocumentsLock: Locks<DocumentId>; private readonly remoteDocumentsLock: Locks<DocumentId>;

View file

@ -18,7 +18,8 @@ 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 { deserialize } from "../utils/deserialize";
import { base64ToBytes } from "byte-base64";
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";
import { createPromise } from "../utils/create-promise"; 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 { DocumentVersion } from "../services/types/DocumentVersion";
import type { DocumentUpdateResponse } from "../services/types/DocumentUpdateResponse"; import type { DocumentUpdateResponse } from "../services/types/DocumentUpdateResponse";
import type { DocumentVersionWithoutContent } from "../services/types/DocumentVersionWithoutContent"; 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 { isFileTypeMergable } from "../utils/is-file-type-mergable";
import { isBinary } from "../utils/is-binary"; import { isBinary } from "../utils/is-binary";
@ -292,7 +293,7 @@ export class UnrestrictedSyncer {
} }
if (!("type" in response) || response.type === "MergingUpdate") { if (!("type" in response) || response.type === "MergingUpdate") {
const responseBytes = deserialize(response.contentBase64); const responseBytes = base64ToBytes(response.contentBase64);
contentHash = hash(responseBytes); contentHash = hash(responseBytes);
this.database.updateDocumentMetadata( this.database.updateDocumentMetadata(
@ -439,7 +440,7 @@ export class UnrestrictedSyncer {
return; return;
} }
const contentBytes = deserialize(content); const contentBytes = base64ToBytes(content);
await this.operations.ensureClearPath(remoteVersion.relativePath); await this.operations.ensureClearPath(remoteVersion.relativePath);

View file

@ -1,6 +1,6 @@
// Implements an in-memory fixed-size cache for document contents, // 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 // Doubly-linked list node for O(1) LRU operations
class LRUNode { class LRUNode {

View file

@ -1,7 +1,7 @@
import { describe, it, beforeEach } from "node:test"; import { describe, it, beforeEach } from "node:test";
import assert from "node:assert"; import assert from "node:assert";
import { Logger } from "../tracing/logger"; import { Logger } from "../../tracing/logger";
import type { RelativePath } from "../persistence/database"; import type { RelativePath } from "../../persistence/database";
import { Locks } from "./locks"; import { Locks } from "./locks";
describe("withLock", () => { describe("withLock", () => {

View file

@ -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. * Manages exclusive locks on items to prevent concurrent modifications.

View file

@ -1,6 +1,6 @@
import type { SyncClient } from "../sync-client"; import type { SyncClient } from "../../sync-client";
import type { LogLine } from "../tracing/logger"; import type { LogLine } from "../../tracing/logger";
import { LogLevel } from "../tracing/logger"; import { LogLevel } from "../../tracing/logger";
export function logToConsole(client: SyncClient): void { export function logToConsole(client: SyncClient): void {
client.logger.addOnMessageListener((logLine: LogLine) => { client.logger.addOnMessageListener((logLine: LogLine) => {

View file

@ -1,4 +1,4 @@
import { sleep } from "../utils/sleep"; import { sleep } from "../sleep";
export const slowFetchFactory = export const slowFetchFactory =
(jitterScaleInSeconds: number) => (jitterScaleInSeconds: number) =>
@ -7,10 +7,14 @@ export const slowFetchFactory =
init?: RequestInit init?: RequestInit
): Promise<Response> => { ): Promise<Response> => {
if (jitterScaleInSeconds > 0) { if (jitterScaleInSeconds > 0) {
await sleep(Math.random() * jitterScaleInSeconds * 1000); await sleep(((Math.random() * jitterScaleInSeconds) / 2) * 1000);
} }
const response = await fetch(input, init); const response = await fetch(input, init);
if (jitterScaleInSeconds > 0) {
await sleep(((Math.random() * jitterScaleInSeconds) / 2) * 1000);
}
return response; return response;
}; };

View file

@ -1,12 +1,11 @@
import { sleep } from "../utils/sleep"; import { sleep } from "../sleep";
import { Locks } from "../utils/locks"; import { Locks } from "../data-structures/locks";
import type { Logger } from "../tracing/logger"; import type { Logger } from "../../tracing/logger";
export function slowWebSocketFactory( export function slowWebSocketFactory(
jitterScaleInSeconds: number, jitterScaleInSeconds: number,
logger: Logger logger: Logger
): typeof WebSocket { ): typeof WebSocket {
// eslint-disable-next-line
return class FlakyWebSocket extends WebSocket { return class FlakyWebSocket extends WebSocket {
private static readonly RECEIVE_KEY = "websocket-receive"; private static readonly RECEIVE_KEY = "websocket-receive";
private static readonly SEND_KEY = "websocket-send"; private static readonly SEND_KEY = "websocket-send";

View file

@ -1,5 +0,0 @@
import { base64ToBytes } from "byte-base64";
export function deserialize(data: string): Uint8Array {
return base64ToBytes(data);
}

View file

@ -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);
});
});

View file

@ -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;
}