@noego/proper 0.1.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@noego/proper",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
4
4
  "description": "",
5
5
  "main": "bin/index.js",
6
6
  "module": "bin/index.mjs",
@@ -64,6 +64,7 @@
64
64
  "source-map-support": "^0.5.21",
65
65
  "sqlite": "^5.1.1",
66
66
  "sqlite3": "^5.1.7",
67
- "tsx": "^4.19.4"
67
+ "tsx": "^4.19.4",
68
+ "yaml": "^2.9.0"
68
69
  }
69
70
  }
package/readme.md CHANGED
@@ -266,6 +266,98 @@ describe('Database Tests', () => {
266
266
 
267
267
  ---
268
268
 
269
+ ## Ledger Patches (`proper patch`)
270
+
271
+ Ledger patches are one-shot, versioned YAML files that repair `proper_migrations`
272
+ history **without executing schema SQL**. Use them when applied migration files
273
+ were renamed after installation, when a ledger row is missing for schema that
274
+ already exists, or when a ledger row wrongly claims success.
275
+
276
+ Patches are discovered and applied automatically before Proper reads migration
277
+ completion state (CLI and `MigrationRunnerFactory.create()` alike), are
278
+ transactional, are applied at most once per configured migration ledger, and
279
+ work identically for MySQL/MariaDB, SQLite, and PostgreSQL.
280
+
281
+ ### Creating a patch
282
+
283
+ ```bash
284
+ proper patch fix_renamed_keys
285
+ proper patch --name fix_renamed_keys
286
+ ```
287
+
288
+ This scaffolds `<patch_folder>/<timestamp>_fix_renamed_keys.yaml` without
289
+ opening a database. The scaffold's `operations: []` is intentionally not
290
+ runnable — complete the file before running another database-backed command.
291
+
292
+ ### Configuration
293
+
294
+ ```jsonc
295
+ {
296
+ "patch_folder": "patches", // default: a `patches` sibling of migration_folder
297
+ "patch_table": "proper_patches" // default
298
+ }
299
+ ```
300
+
301
+ ### Patch file format (version 1)
302
+
303
+ ```yaml
304
+ version: 1
305
+ description: fix hand-stamped migration names
306
+ operations:
307
+ - rename_migration:
308
+ from: 1787905000000_create_conversation_run_lifecycle
309
+ to: 1787941600000_create_conversation_run_lifecycle
310
+ - mark_applied:
311
+ key: 1787941700000_existing_schema_baseline
312
+ - unmark_applied:
313
+ key: 1787941800000_incorrect_ledger_row
314
+ ```
315
+
316
+ Operations run in file order, then operation order. Each is a conditional
317
+ bookkeeping repair:
318
+
319
+ - `rename_migration` — moves a ledger row from `from` to `to`; a no-op when the
320
+ database already converged; a hard conflict when both keys exist.
321
+ - `mark_applied` — inserts a ledger row without running `up` SQL (you are
322
+ responsible for verifying the schema already matches).
323
+ - `unmark_applied` — deletes a ledger row without running `down` SQL, making
324
+ the migration pending again.
325
+
326
+ Parsing is strict: unknown fields/verbs, duplicate keys, YAML anchors/aliases,
327
+ merge keys, and custom tags are rejected. There is no raw SQL escape hatch.
328
+
329
+ ### Immutability
330
+
331
+ **Patch files are permanent, append-only migration history.** Once any database
332
+ records a patch, the file must never be edited, renamed, or deleted — Proper
333
+ stores a SHA-256 checksum at application time and refuses to run migrations if
334
+ an applied patch's file is missing or changed. A correction is a new, later
335
+ patch (`A -> B -> C` and `A -> B -> A` chains are supported and validated
336
+ against the current migration files).
337
+
338
+ ### Deployment and rollback warning
339
+
340
+ A history rename must ship the renamed migration files, the patch file(s), and
341
+ a patch-aware Proper version **in the same application artifact**. Do not run
342
+ old and new application versions' migration startup concurrently during the
343
+ first deployment of a rename. After a rename patch commits, rolling back to an
344
+ artifact that only contains the old migration filenames is unsafe — that old
345
+ runner can attempt the old migration again. Roll back only to artifacts
346
+ consistent with the repaired ledger, or restore the database separately.
347
+
348
+ `proper down` and `proper reset` never touch patch history; destructive
349
+ `terminate()` drops both the migration table and the patch table.
350
+
351
+ ### Programmatic API
352
+
353
+ ```ts
354
+ const runner = await MigrationRunnerFactory.create("proper.json"); // patches already applied
355
+ const results: PatchApplyResult[] = await runner.applyPendingPatches(); // idempotent
356
+ const path: string = runner.createPatch("fix_renamed_keys"); // scaffold, no DB
357
+ ```
358
+
359
+ ---
360
+
269
361
  ## Seeding
270
362
 
271
363
  SQL Proper supports a powerful seeding feature that allows you to populate your database with initial data (reference data, test users, etc.). Seeds can be SQL files or JavaScript/TypeScript modules.