Initial Commit

This commit is contained in:
2026-05-27 23:47:53 +01:00
parent fbc70f96e6
commit 9b28db724f
18103 changed files with 1600554 additions and 0 deletions

View File

@@ -0,0 +1,71 @@
import { SYNC_QUEUE_SCHEMA_VERSION } from "../constants/index";
import type { SyncQueueEntry } from "../types/common";
/** A single forward migrator from `fromVersion` to `fromVersion + 1`. */
export interface VersionMigrator {
readonly fromVersion: number;
upgrade(entry: Record<string, unknown>): Record<string, unknown>;
}
/** v1 → v2: legacy entries lacked `schemaVersion`; assume retryCount/maxRetries defaults if absent. */
const V1_TO_V2: VersionMigrator = {
fromVersion: 1,
upgrade(entry) {
const rc = entry["retryCount"];
const mr = entry["maxRetries"];
return {
...entry,
retryCount: typeof rc === "number" ? rc : 0,
maxRetries: typeof mr === "number" ? mr : 3,
schemaVersion: 2,
};
},
};
/** Default migrator registry shipped with the package. */
export const DEFAULT_MIGRATORS: readonly VersionMigrator[] = Object.freeze([
V1_TO_V2,
]);
/**
* Forward-migrate a single raw entry record to the current schema version.
* Idempotent: entries already at the current version pass through unchanged.
*/
export function migrateEntry(
raw: Record<string, unknown>,
migrators: readonly VersionMigrator[] = DEFAULT_MIGRATORS
): Record<string, unknown> {
const startVersion =
typeof raw["schemaVersion"] === "number" ? raw["schemaVersion"] : 1;
let current: Record<string, unknown> = {
...raw,
schemaVersion: startVersion,
};
while (true) {
const v = current["schemaVersion"];
if (typeof v !== "number" || v >= SYNC_QUEUE_SCHEMA_VERSION) break;
const migrator = migrators.find((m) => m.fromVersion === v);
if (migrator === undefined) {
throw new Error(
`No sync-queue migrator registered for schemaVersion=${String(v)}`
);
}
current = migrator.upgrade(current);
}
return current;
}
/** Migrate a batch of raw entries. */
export function migrateBatch(
raws: readonly Record<string, unknown>[],
migrators: readonly VersionMigrator[] = DEFAULT_MIGRATORS
): Record<string, unknown>[] {
return raws.map((r) => migrateEntry(r, migrators));
}
/** Type-narrowing helper to cast a migrated record into a {@link SyncQueueEntry}. */
export function asSyncQueueEntry(
record: Record<string, unknown>
): SyncQueueEntry {
return record as unknown as SyncQueueEntry;
}