tina4-nodejs 3.13.71 → 3.13.73

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.
Files changed (27) hide show
  1. package/CLAUDE.md +3 -3
  2. package/package.json +1 -1
  3. package/packages/core/gallery/auth/src/routes/api/gallery/auth/login/post.ts +2 -2
  4. package/packages/core/gallery/auth/src/routes/api/gallery/auth/verify/get.ts +2 -2
  5. package/packages/core/gallery/auth/src/routes/gallery/auth/get.ts +2 -2
  6. package/packages/core/gallery/database/src/routes/api/gallery/db/notes/get.ts +3 -3
  7. package/packages/core/gallery/database/src/routes/api/gallery/db/notes/post.ts +3 -3
  8. package/packages/core/gallery/database/src/routes/api/gallery/db/tables/get.ts +3 -3
  9. package/packages/core/gallery/error-overlay/src/routes/api/gallery/crash/get.ts +1 -1
  10. package/packages/core/gallery/orm/src/routes/api/gallery/products/get.ts +1 -1
  11. package/packages/core/gallery/orm/src/routes/api/gallery/products/post.ts +1 -1
  12. package/packages/core/gallery/queue/src/lib/queueDb.ts +2 -2
  13. package/packages/core/gallery/queue/src/routes/api/gallery/queue/consume/post.ts +1 -1
  14. package/packages/core/gallery/queue/src/routes/api/gallery/queue/fail/post.ts +1 -1
  15. package/packages/core/gallery/queue/src/routes/api/gallery/queue/produce/post.ts +1 -1
  16. package/packages/core/gallery/queue/src/routes/api/gallery/queue/retry/post.ts +1 -1
  17. package/packages/core/gallery/queue/src/routes/api/gallery/queue/status/get.ts +1 -1
  18. package/packages/core/gallery/queue/src/routes/gallery/queue/get.ts +1 -1
  19. package/packages/core/gallery/rest-api/src/routes/api/gallery/hello/get.ts +1 -1
  20. package/packages/core/gallery/rest-api/src/routes/api/gallery/hello/post.ts +1 -1
  21. package/packages/core/gallery/templates/src/routes/gallery/page/get.ts +1 -1
  22. package/packages/core/public/js/tina4-dev-admin.js +203 -170
  23. package/packages/core/public/js/tina4-dev-admin.min.js +203 -170
  24. package/packages/core/src/devAdmin.ts +263 -38
  25. package/packages/core/src/request.ts +32 -6
  26. package/packages/frond/src/engine.ts +157 -4
  27. package/packages/orm/src/migration.ts +50 -30
@@ -437,32 +437,66 @@ export async function isMigrationApplied(name: string): Promise<boolean> {
437
437
  }
438
438
 
439
439
  /**
440
- * Record a migration as applied. Writes the canonical columns: migration_name,
441
- * a derived description, batch, an explicit ISO-8601 executed_at timestamp, and
442
- * passed (default 1). Preserves the Firebird generator-id branch.
440
+ * Write the canonical "applied" bookkeeping row for a migration.
441
+ *
442
+ * DELETEs any existing row for this migration_name FIRST, then INSERTs the
443
+ * fresh row. A leftover passed=0 row (a prior failure recorded via the public
444
+ * recordMigration() API, or one carried over from a <= 3.13.54 upgrade) is
445
+ * therefore superseded, so the migration re-applies cleanly instead of colliding
446
+ * on the UNIQUE migration_name constraint when the fresh passed=1 row is
447
+ * INSERTed (that collision used to wedge a previously-failed migration).
448
+ * DELETE+INSERT is portable across every engine (no UPSERT dialect variance) and
449
+ * holds the invariant that the table carries AT MOST ONE row per migration_name -
450
+ * latest state wins.
451
+ *
452
+ * Operates on the passed adapter so both migrate() (its own adapter) and
453
+ * recordMigration() (the global adapter) share ONE implementation - mirrors the
454
+ * Python master's single _record_applied(). Preserves the Firebird generator-id
455
+ * branch (no AUTOINCREMENT on Firebird). Writes the canonical columns:
456
+ * migration_name, a derived description, batch, an explicit ISO-8601 executed_at
457
+ * timestamp, and passed (default 1).
443
458
  */
444
- export async function recordMigration(name: string, batch: number, passed: number = 1): Promise<void> {
445
- const adapter = getAdapter();
459
+ async function recordApplied(
460
+ db: DatabaseAdapter,
461
+ name: string,
462
+ batch: number,
463
+ passed: number = 1,
464
+ ): Promise<void> {
446
465
  const now = new Date().toISOString();
447
466
  const description = deriveDescription(name);
448
- if (isFirebirdAdapter(adapter)) {
449
- // Firebird: generate ID from sequence
450
- const rows = await adapterQuery<{ NEXT_ID: number }>(adapter,
467
+ // Delete-before-insert: supersede any leftover row for this migration_name so
468
+ // the INSERT below never collides on the UNIQUE migration_name.
469
+ await adapterExecute(db,
470
+ `DELETE FROM "${MIGRATION_TABLE}" WHERE migration_name = ?`,
471
+ [name],
472
+ );
473
+ if (isFirebirdAdapter(db)) {
474
+ // Firebird: generate the id from the sequence.
475
+ const rows = await adapterQuery<{ NEXT_ID: number }>(db,
451
476
  "SELECT GEN_ID(GEN_TINA4_MIGRATION_ID, 1) AS NEXT_ID FROM RDB$DATABASE",
452
477
  );
453
478
  const nextId = rows[0]?.NEXT_ID ?? 1;
454
- await adapterExecute(adapter,
479
+ await adapterExecute(db,
455
480
  `INSERT INTO "${MIGRATION_TABLE}" (id, migration_name, description, batch, executed_at, passed) VALUES (?, ?, ?, ?, ?, ?)`,
456
481
  [nextId, name, description, batch, now, passed],
457
482
  );
458
483
  } else {
459
- await adapterExecute(adapter,
484
+ await adapterExecute(db,
460
485
  `INSERT INTO "${MIGRATION_TABLE}" (migration_name, description, batch, executed_at, passed) VALUES (?, ?, ?, ?, ?)`,
461
486
  [name, description, batch, now, passed],
462
487
  );
463
488
  }
464
489
  }
465
490
 
491
+ /**
492
+ * Record a migration as applied (public API). Routes through recordApplied() so
493
+ * a leftover passed=0 row for the same migration_name is deleted before the
494
+ * fresh row is written (at most one row per migration_name).
495
+ */
496
+ export async function recordMigration(name: string, batch: number, passed: number = 1): Promise<void> {
497
+ await recordApplied(getAdapter(), name, batch, passed);
498
+ }
499
+
466
500
  /**
467
501
  * Apply a migration (run its up function and record it).
468
502
  */
@@ -981,26 +1015,12 @@ export async function migrate(
981
1015
  await adapterExecute(db, stmt);
982
1016
  }
983
1017
 
984
- // Record as applied (passed = 1) with the canonical columns and an
985
- // explicit ISO-8601 executed_at timestamp.
986
- const now = new Date().toISOString();
987
- const description = deriveDescription(migrationId);
988
- if (isFirebirdAdapter(db)) {
989
- // Firebird: generate ID from sequence
990
- const idRows = await adapterQuery<{ NEXT_ID: number }>(db,
991
- "SELECT GEN_ID(GEN_TINA4_MIGRATION_ID, 1) AS NEXT_ID FROM RDB$DATABASE",
992
- );
993
- const nextId = idRows[0]?.NEXT_ID ?? 1;
994
- await adapterExecute(db,
995
- `INSERT INTO "${MIGRATION_TABLE}" (id, migration_name, description, batch, executed_at, passed) VALUES (?, ?, ?, ?, ?, 1)`,
996
- [nextId, migrationId, description, currentBatch, now],
997
- );
998
- } else {
999
- await adapterExecute(db,
1000
- `INSERT INTO "${MIGRATION_TABLE}" (migration_name, description, batch, executed_at, passed) VALUES (?, ?, ?, ?, 1)`,
1001
- [migrationId, description, currentBatch, now],
1002
- );
1003
- }
1018
+ // Record as applied (passed = 1) via recordApplied(), which DELETEs any
1019
+ // leftover row for this migration_name before the fresh INSERT - so a
1020
+ // previously-failed migration (a leftover passed=0 row) re-applies
1021
+ // cleanly instead of colliding on the UNIQUE migration_name. Both the
1022
+ // DELETE and INSERT run inside this file's open transaction.
1023
+ await recordApplied(db, migrationId, currentBatch);
1004
1024
 
1005
1025
  await adapterCommit(db);
1006
1026
  result.applied.push(file);