Skip to content

Kody is live

Watch the launch video — what Kody is, and why it exists.

← Public packages

@kentcdodds/package-app-kit

Design tokens, PWA install/update, About/version, cache helpers, and optional realtime notes sync for Kody package apps.

src/storage-migrations.ts

95 lines · 3.3 KB · TypeScript
/**
 * Stable kit subpath for packageStorage schema migrations.
 *
 * Implementation lives in `@kentcdodds/package-storage-migrations`. This module
 * re-exports / thin-wraps that package so consumers keep importing
 * `kody:@kentcdodds/package-app-kit/storage-migrations`. Callers must always
 * pass their own `storage` — never call `packageStorage()` inside the
 * migrations package.
 */

export type {
	PackageStorageLike,
	StorageMigration,
	RunPackageStorageMigrationsInput,
	AppliedMigration,
	RunPackageStorageMigrationsResult,
} from 'kody:@kentcdodds/package-storage-migrations'

import {
	createMigrationRunner as createMigrationRunnerImpl,
	runPackageStorageMigrations as runPackageStorageMigrationsImpl,
} from 'kody:@kentcdodds/package-storage-migrations'
import type {
	RunPackageStorageMigrationsInput,
	RunPackageStorageMigrationsResult,
} from 'kody:@kentcdodds/package-storage-migrations'

/**
 * Run pending migrations in ascending version order. Idempotent: already-applied
 * versions are skipped; re-running after success is a no-op.
 *
 * Delegates to `@kentcdodds/package-storage-migrations`. Always pass the
 * caller's `packageStorage()` (or compatible) as `input.storage`.
 *
 * @param input.storage - Caller's storage bucket (required)
 * @param input.migrations - Ordered or unordered steps; sorted by version ascending
 * @param input.versionKey - Schema version key (default `pak:schema-version`)
 * @returns `{ fromVersion, toVersion, applied }` describing what ran
 *
 * @example
 * import { runPackageStorageMigrations } from 'kody:@kentcdodds/package-app-kit/storage-migrations'
 * import { packageStorage } from 'kody:runtime'
 *
 * await runPackageStorageMigrations({
 *   storage: packageStorage(),
 *   versionKey: 'my-app:schema-version',
 *   migrations: [
 *     {
 *       version: 1,
 *       name: 'notes-to-document',
 *       async up(storage) {
 *         const legacy = await storage.get('notes-v1')
 *         if (Array.isArray(legacy)) {
 *           await storage.set('notes', { items: legacy })
 *           await storage.delete?.('notes-v1')
 *         }
 *       },
 *     },
 *   ],
 * })
 */
export async function runPackageStorageMigrations(
	input: RunPackageStorageMigrationsInput,
): Promise<RunPackageStorageMigrationsResult> {
	return runPackageStorageMigrationsImpl(input)
}

/**
 * Memoize migrations for one Worker isolate — call `ensure()` at the start of
 * handlers (or once from middleware) so schema work runs at most once per boot.
 *
 * Delegates to `@kentcdodds/package-storage-migrations`. Always pass the
 * caller's storage.
 *
 * @param input - Same shape as `runPackageStorageMigrations` (caller must pass `storage`)
 * @returns `ensureMigrated()` that shares one in-flight / completed promise per isolate
 *
 * @example
 * import { createMigrationRunner } from 'kody:@kentcdodds/package-app-kit/storage-migrations'
 * import { packageStorage } from 'kody:runtime'
 *
 * const ensureSchema = createMigrationRunner({
 *   storage: packageStorage(),
 *   versionKey: 'my-app:schema-version',
 *   migrations: [ ... ],
 * })
 * // in a loader/action:
 * await ensureSchema()
 */
export function createMigrationRunner(input: RunPackageStorageMigrationsInput) {
	return createMigrationRunnerImpl(input)
}

/** Primary callable export for this subpath. */
export default runPackageStorageMigrations