@cosmicdrift/kumiko-framework 0.235.1 → 0.235.3
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 +3 -3
- package/src/__tests__/upgrade-cli.test.ts +85 -0
- package/src/db/queries/event-consumer.ts +27 -0
- package/src/engine/__tests__/build-app-schema.test.ts +2 -0
- package/src/engine/access.ts +4 -1
- package/src/engine/feature-ast/__tests__/parse.test.ts +95 -0
- package/src/engine/feature-ast/__tests__/render-roundtrip.test.ts +2 -2
- package/src/engine/feature-ast/extractors/handlers.ts +91 -14
- package/src/engine/feature-ast/patterns.ts +31 -1
- package/src/engine/feature-ast/render.ts +4 -0
- package/src/engine/feature-entity-handlers.ts +28 -2
- package/src/engine/index.ts +4 -1
- package/src/engine/pattern-library/mixed-schemas.ts +28 -0
- package/src/engine/registry-facade.ts +4 -0
- package/src/engine/types/index.ts +4 -0
- package/src/errors/__tests__/error-helpers.test.ts +15 -1
- package/src/errors/index.ts +2 -2
- package/src/errors/reasons.ts +30 -0
- package/src/migrations/__tests__/pending-rebuilds.integration.test.ts +36 -2
- package/src/migrations/pending-rebuilds.ts +16 -10
- package/src/pipeline/__tests__/event-dispatcher-pass-failure.integration.test.ts +266 -0
- package/src/pipeline/event-dispatcher-delivery.ts +14 -0
- package/src/pipeline/event-dispatcher.ts +68 -1
- package/src/ui-types/index.ts +2 -2
- package/src/ui-types/list-row-meta.ts +16 -0
- package/src/upgrade-cli.ts +37 -10
package/src/ui-types/index.ts
CHANGED
|
@@ -107,5 +107,5 @@ export type {
|
|
|
107
107
|
QualifiedContentCollection,
|
|
108
108
|
WorkspaceSchema,
|
|
109
109
|
} from "./app-schema";
|
|
110
|
-
export type { ListRowMetaColumnType } from "./list-row-meta";
|
|
111
|
-
export { LIST_ROW_META_COLUMNS } from "./list-row-meta";
|
|
110
|
+
export type { ListRowMetaColumnType, ListRowMetaReference } from "./list-row-meta";
|
|
111
|
+
export { LIST_ROW_META_COLUMNS, LIST_ROW_META_REFERENCES } from "./list-row-meta";
|
|
@@ -23,3 +23,19 @@ export const LIST_ROW_META_COLUMNS: Readonly<Record<string, ListRowMetaColumnTyp
|
|
|
23
23
|
insertedById: "text",
|
|
24
24
|
modifiedById: "text",
|
|
25
25
|
};
|
|
26
|
+
|
|
27
|
+
export type ListRowMetaReference = {
|
|
28
|
+
readonly refFeature: string;
|
|
29
|
+
readonly refEntity: string;
|
|
30
|
+
readonly refLabelField: string;
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
// tenantId would otherwise render the raw GUID; the lookup query is
|
|
34
|
+
// `tenant:query:tenant:list`, cross-tenant because the feature is
|
|
35
|
+
// `r.systemScope()`.
|
|
36
|
+
// ponytail: bulk lookup is capped at REFERENCE_LIST_LOOKUP_LIMIT (200) —
|
|
37
|
+
// above that, rows fall back to the GUID; paginate the lookup if an install
|
|
38
|
+
// ever exceeds it.
|
|
39
|
+
export const LIST_ROW_META_REFERENCES: Readonly<Record<string, ListRowMetaReference>> = {
|
|
40
|
+
tenantId: { refFeature: "tenant", refEntity: "tenant", refLabelField: "name" },
|
|
41
|
+
};
|
package/src/upgrade-cli.ts
CHANGED
|
@@ -288,6 +288,22 @@ function writeUpgradeMarker(targetDir: string, marker: UpgradeMarker): void {
|
|
|
288
288
|
writeFileSync(join(dir, "upgrade-state.json"), `${JSON.stringify(marker, null, 2)}\n`, "utf-8");
|
|
289
289
|
}
|
|
290
290
|
|
|
291
|
+
// Missing, unreadable, or invalid marker means no baseline was ever recorded
|
|
292
|
+
// — most commonly a bootstrap app that never ran `--apply` (fw#2299) — so
|
|
293
|
+
// this reports "no marker" instead of throwing.
|
|
294
|
+
function readMarkerVersion(targetDir: string): string | null {
|
|
295
|
+
const markerPath = join(targetDir, ".kumiko", "upgrade-state.json");
|
|
296
|
+
if (!existsSync(markerPath)) return null;
|
|
297
|
+
try {
|
|
298
|
+
const parsed = JSON.parse(readFileSync(markerPath, "utf-8")) as { version?: unknown };
|
|
299
|
+
return typeof parsed.version === "string" && SEMVER_RE.test(parsed.version)
|
|
300
|
+
? parsed.version
|
|
301
|
+
: null;
|
|
302
|
+
} catch {
|
|
303
|
+
return null;
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
|
|
291
307
|
/** Highest pending version strictly below the earliest open manual breaking
|
|
292
308
|
* entry (no codemod). Falls back to highest non-breaking pending when every
|
|
293
309
|
* pending version is at/after that manual — never advances onto the manual. */
|
|
@@ -444,10 +460,29 @@ export async function runUpgradeCli(
|
|
|
444
460
|
const verbose = getFlag(args, "verbose");
|
|
445
461
|
const fromFlag = getStringFlag(args, "from");
|
|
446
462
|
|
|
463
|
+
// Resolved once here (not just inside --apply) so both the filter
|
|
464
|
+
// baseline below and the --apply codemod run target the same directory.
|
|
465
|
+
const dirFlag = getStringFlag(args, "dir");
|
|
466
|
+
const targetDir = dirFlag ? resolve(dirFlag) : cwd;
|
|
467
|
+
if (!existsSync(targetDir) || !statSync(targetDir).isDirectory()) {
|
|
468
|
+
out.err("");
|
|
469
|
+
out.err(` --dir path is not a directory: ${targetDir}`);
|
|
470
|
+
out.err("");
|
|
471
|
+
return 1;
|
|
472
|
+
}
|
|
473
|
+
|
|
447
474
|
// Always resolve the actually installed version, even when --from is set,
|
|
448
475
|
// so --json can report both the filter baseline and what's really there.
|
|
449
476
|
const installedVersion = readCurrentVersion(cwd);
|
|
450
|
-
|
|
477
|
+
// Filter baseline: explicit --from wins, otherwise the marker recorded
|
|
478
|
+
// under targetDir (what was last actually applied there), falling back to
|
|
479
|
+
// the installed version only when no marker exists yet (bootstrap,
|
|
480
|
+
// fw#2299). Baselining on installedVersion here would silently treat every
|
|
481
|
+
// changelog entry up to the installed version as already handled, even
|
|
482
|
+
// when the marker says otherwise — a bare `--apply` would then always
|
|
483
|
+
// report "Nothing new" and bootstrap the marker onto the installed
|
|
484
|
+
// version, hiding breaking changes the marker never actually saw.
|
|
485
|
+
const currentVersion = fromFlag ?? readMarkerVersion(targetDir) ?? installedVersion;
|
|
451
486
|
if (!currentVersion) {
|
|
452
487
|
out.err("");
|
|
453
488
|
out.err(" Could not detect Kumiko version.");
|
|
@@ -483,16 +518,8 @@ export async function runUpgradeCli(
|
|
|
483
518
|
const pending = sortEntries(filterEntriesAfter(allEntries, currentVersion));
|
|
484
519
|
|
|
485
520
|
if (getFlag(args, "apply")) {
|
|
486
|
-
const dirFlag = getStringFlag(args, "dir");
|
|
487
|
-
const targetDir = dirFlag ? resolve(dirFlag) : cwd;
|
|
488
|
-
if (!existsSync(targetDir) || !statSync(targetDir).isDirectory()) {
|
|
489
|
-
out.err("");
|
|
490
|
-
out.err(` --dir path is not a directory: ${targetDir}`);
|
|
491
|
-
out.err("");
|
|
492
|
-
return 1;
|
|
493
|
-
}
|
|
494
521
|
// Marker must reflect what is actually installed under the target (or
|
|
495
|
-
// cwd), not
|
|
522
|
+
// cwd), not the filter baseline above — otherwise CI stays green forever.
|
|
496
523
|
const markerVersion =
|
|
497
524
|
(dirFlag ? readCurrentVersion(targetDir) : null) ?? installedVersion ?? currentVersion;
|
|
498
525
|
const dryRun = getFlag(args, "dry-run");
|