import { PatchId, ModuleFilePath, ValModules } from "@valbuild/core"; import { AuthorId, BaseSha, BinaryFileType, GenericErrorMessage, MetadataOfType, OpsMetadata, PreparedCommit, ValOps, ValOpsOptions, WithGenericError, SaveSourceFilePatchResult, type PatchGroupMembership, SchemaSha, CommitSha, OrderedPatches, OrderedPatchesMetadata, SourcesSha } from "./ValOps.js"; import { Patch, ParentRef, ValCommit } from "@valbuild/shared/internal"; import type { HistoryError } from "./history/HistoryError.js"; import type { AffectedFile, StoredModuleVersion, CommitPage, CommitPatch, HistoricalCommit } from "./history/types.js"; import { result } from "@valbuild/core/fp"; import { Buffer } from "buffer"; export declare class ValOpsFS extends ValOps { private readonly contentUrl; private readonly rootDir; private static readonly VAL_DIR; private readonly host; /** The developer's own working tree. See {@link ValOps.patchesAreLocal}. */ readonly patchesAreLocal = true; /** * The developer's own machine, where there is no credential to require and * nothing to protect it from. See {@link ValOps.requiresAuth}. */ readonly requiresAuth = false; constructor(contentUrl: string, rootDir: string, valModules: ValModules, options?: ValOpsOptions); /** * Change detection for `.jsonValues()` entry files, which no sha can see (their * content lives behind a thunk that `JSON.stringify` drops). */ private readonly jsonEntryFilesFingerprint; /** * Unpublished changes repair threw away, waiting to be told to somebody. * * Held here and drained by the next `getStat`, because stat is the channel * that always flows. The case worth reporting is a repair that removed * EVERYTHING - which is what an old store looks like - and then there is * nothing left for the studio to fetch, so a notice riding on `fetchPatches` * would never be collected. Drained rather than kept, because this has to be * said once: a permanent flag would put a toast on the screen forever. * * Held in memory only: a restart loses it, and that is the right trade. The * durable record is `patches.repair.log`. */ private readonly removedPatchNotices; onInit(): Promise; getPresignedAuthNonce(project: string, corsOrigin: string, auth: { pat: string; } | { apiKey: string; }): Promise<{ status: "success"; data: { nonce: string; baseUrl: string; }; } | { status: "error"; statusCode: 401 | 500; error: GenericErrorMessage; }>; getStat(params: { baseSha: BaseSha; schemaSha: SchemaSha; sourcesSha: SourcesSha; patches: PatchId[]; profileId?: AuthorId; jsonEntriesSha?: string; } | null): Promise<{ type: "request-again" | "no-change" | "did-change"; baseSha: BaseSha; schemaSha: SchemaSha; sourcesSha: SourcesSha; patches: PatchId[]; removed?: { patchId: PatchId; reason: string; }[]; jsonEntriesSha?: string; } | { type: "use-websocket"; url: string; nonce: string; baseSha: BaseSha; schemaSha: SchemaSha; sourcesSha: SourcesSha; commitSha: CommitSha; commits: ValCommit[]; patches: PatchId[]; } | { type: "error"; error: GenericErrorMessage; unauthorized?: boolean; networkError?: boolean; }>; /** * The one read every other read comes out of. * * `getStat` announces from this and `fetchPatches` delivers from this, so the * two cannot disagree. They used to: `getStat` counted the directories on disk * while `fetchPatches` walked the parent links between them, and when a single * record went missing the first said 410 and the second said 359 — with no * error anywhere, because a walk that runs out of links just stops. * * Anything wrong is reported, then repaired, and reset only if repair does not * settle it. In that order, and never silently. */ private readStore; /** * Report, repair, and reset only if repair did not take. * * Reached only when something is actually wrong, so the healthy path — which * is every stat poll — never touches the lock. */ private repairStore; fetchPatches(filters: { patchIds?: PatchId[]; excludePatchOps: ExcludePatchOps; }): Promise; private parseJsonFile; protected saveSourceFilePatch(path: ModuleFilePath, patch: Patch, patchId: PatchId, _parentRef: ParentRef, authorId: AuthorId | null, sessionId: string | null, _patchGroup?: PatchGroupMembership): Promise; protected getSourceFile(path: string): Promise>; protected saveSourceFile(path: ModuleFilePath, data: string): Promise>; saveBase64EncodedBinaryFileFromPatch(filePath: string, _parentRef: ParentRef, patchId: PatchId, data: string | null, _type: BinaryFileType, metadata: MetadataOfType | undefined): Promise>; /** * Which of the two places a patch's file can be, if either. * * The bytes are in the store once the patch's record is, and in the staging * area before that — see `uploadsDir`. Every reader has to accept both, and * they decide it here rather than each on its own, so two readers of the same * file cannot disagree about whether it exists. */ private wherePatchFileIs; protected getBase64EncodedBinaryFileMetadataFromPatch(filePath: string, type: T, patchId: PatchId): Promise>; getBase64EncodedBinaryFileFromPatch(filePath: string, patchId: PatchId): Promise; deletePatches(patchIds: PatchId[]): Promise<{ deleted: PatchId[]; errors?: undefined; error?: undefined; } | { deleted: PatchId[]; errors: Record; } | { error: GenericErrorMessage; errors?: undefined; deleted?: undefined; }>; deleteAllPatches(): Promise<{ error?: GenericErrorMessage; }>; saveOrUploadFiles(preparedCommit: PreparedCommit, mode: "skip-remote" | "upload-remote", auth?: { apiKey: string; } | { pat: string; }): Promise<{ updatedFiles: string[]; uploadedRemoteRefs: string[]; errors: Record; }>; getBinaryFile(filePath: string): Promise; protected getBinaryFileMetadata(filePath: string, type: T): Promise>; private getPatchesDir; /** * Deliberately outside the patches directory: delete-all and reset rename that * whole directory, and a lock that moves away with it is not holding anything. */ private getPatchLockFile; listCommits(): Promise>; getCommitPatches(): Promise>; getCommitModules(): Promise>; getCommitAffectedFiles(): Promise>; getFileAtCommit(): Promise>; gitPathOfModule(_moduleFilePath: ModuleFilePath): result.Result; }