Initial Commit
This commit is contained in:
@@ -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;
|
||||
}
|
||||
Reference in New Issue
Block a user