72 lines
2.4 KiB
TypeScript
72 lines
2.4 KiB
TypeScript
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;
|
|
}
|