@proteinjs/db 1.45.0 → 1.46.1

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": "@proteinjs/db",
3
- "version": "1.45.0",
3
+ "version": "1.46.1",
4
4
  "main": "./dist/generated/index.js",
5
5
  "types": "./dist/generated/index.d.ts",
6
6
  "exports": {
@@ -66,5 +66,5 @@
66
66
  "ts-jest": "29.1.1",
67
67
  "typescript": "5.2.2"
68
68
  },
69
- "gitHead": "135045a9e4b16a75ea11f610a82fa7ff60751e8d"
69
+ "gitHead": "4b682624f85debf1243334024833744a0ef0d3f2"
70
70
  }
package/src/Table.ts CHANGED
@@ -139,6 +139,14 @@ export abstract class Table<T extends Record> implements Loadable, CustomSeriali
139
139
  * migration ledger reads most-recently-run first, never-run rows last.
140
140
  */
141
141
  sort?: SortCriteria<T>[];
142
+ /**
143
+ * A table whose rows have their OWN page instead of the generic record form: the record table
144
+ * links each row here (replacing the generic form link), draws no New button and no selection
145
+ * Delete button, and the generic form page replace-navigates stale
146
+ * `/record/form?table=<name>&record=<id>` URLs to this link. Built from the id alone so the
147
+ * redirect never needs a row load.
148
+ */
149
+ recordLink?: (row: Pick<T, 'id'>) => string;
142
150
  };
143
151
  };
144
152
  public auth?: {
@@ -79,20 +79,26 @@ export class MigrationTable extends Table<Migration> {
79
79
  service: { query: { permission: 'dev' }, update: { permission: 'dev' }, delete: { permission: 'dev' } },
80
80
  };
81
81
  /**
82
- * The row scan the founder actually reads (ruled 2026-09-02): WHICH migration (name — the
83
- * loader's class name), what it does, how the run went, WHEN it ran ("Ran at" = start_time,
84
- * the one timestamp that answers "when did it land"), how long, when it finished, and a
85
- * glimpse of its output (the mono JSON snippet; the record form carries the full value).
86
- * The declaration flags and the failure detail stay on the record form. Most recent run
87
- * first; never-run rows last — GoogleSQL orders NULL as the least value, so start_time DESC
88
- * places rows without a run after every real timestamp; ledger order (created) breaks ties.
82
+ * The row scan: WHICH migration (name — the loader's class name), what it does, how the run
83
+ * went, WHEN it ran ("Ran at" = start_time, the one timestamp that answers "when did it
84
+ * land"), how long, when it finished, and a glimpse of its output (the mono JSON snippet; the
85
+ * record form carries the full value). The declaration flags and the failure detail stay on
86
+ * the record form.
87
+ *
88
+ * Ordered as a ledger: newest first by `created` (id breaking ties — rows land in batches at
89
+ * one boot), the reverse of the order {@link MigrationRunner.runPendingMigrations} runs them
90
+ * in. Status plays no part: a row that never ran (`proposed`, a `manual` migration waiting
91
+ * for its operator) keeps its place among the rows that did, so the migrations that shipped
92
+ * together read together. An order by run time would push every never-run row below every
93
+ * run one (a never-run row has no start_time, and GoogleSQL orders NULL as the least value,
94
+ * last under DESC) — the pending manual migrations become the hardest rows to find.
89
95
  */
90
96
  public ui: Table<Migration>['ui'] = {
91
97
  recordTable: {
92
98
  columns: ['name', 'description', 'status', 'startTime', 'duration', 'endTime', 'output'],
93
99
  sort: [
94
- { field: 'startTime', desc: true },
95
- { field: 'created', desc: false },
100
+ { field: 'created', desc: true },
101
+ { field: 'id', desc: true },
96
102
  ],
97
103
  },
98
104
  };