@cosmicdrift/kumiko-framework 0.24.1 → 0.26.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 +1 -1
- package/src/bun-db/__tests__/extract-table-info.test.ts +22 -1
- package/src/bun-db/query.ts +5 -2
- package/src/db/__tests__/source-shadow-create.integration.test.ts +54 -0
- package/src/db/__tests__/sql-inventory.test.ts +26 -1
- package/src/db/__tests__/table-builder-indexes.test.ts +15 -0
- package/src/db/__tests__/tenant-db-where-merge.test.ts +81 -0
- package/src/db/entity-table-meta.ts +1 -1
- package/src/db/queries/event-store.ts +2 -7
- package/src/db/sql-inventory.ts +9 -0
- package/src/db/tenant-db.ts +5 -2
- package/src/engine/__tests__/boot-validator.test.ts +79 -0
- package/src/engine/__tests__/post-query-hook.test.ts +6 -6
- package/src/engine/__tests__/registry.test.ts +58 -0
- package/src/engine/__tests__/search-payload-extension.test.ts +49 -3
- package/src/engine/__tests__/unmanaged-table.test.ts +30 -1
- package/src/engine/boot-validator/api-ext.ts +1 -5
- package/src/engine/boot-validator/screens-nav.ts +18 -2
- package/src/engine/registry.ts +43 -12
- package/src/engine/types/fields.ts +2 -1
- package/src/engine/types/handlers.ts +1 -1
- package/src/engine/types/hooks.ts +4 -1
- package/src/engine/validate-projection-allowlist.ts +13 -3
- package/src/errors/__tests__/classes.test.ts +5 -0
- package/src/errors/classes.ts +4 -2
- package/src/files/__tests__/file-ref-entity.test.ts +34 -0
- package/src/files/__tests__/in-memory-provider.test.ts +94 -0
- package/src/logging/__tests__/fallback-logger.test.ts +47 -0
- package/src/pipeline/__tests__/dispatcher.test.ts +53 -0
- package/src/pipeline/dispatcher.ts +57 -57
- package/src/pipeline/system-hooks.ts +17 -5
- package/src/random/__tests__/words.test.ts +44 -0
- package/src/random/generate.ts +3 -3
- package/src/random/words.ts +3 -3
- package/src/stack/table-helpers.ts +2 -2
- package/src/stack/test-stack.ts +3 -4
- package/src/errors/__tests__/field-issue-compat.test.ts +0 -16
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
// words.ts Invarianten-Tests (Phase 1, test-luecken-integration).
|
|
2
|
+
//
|
|
3
|
+
// Schützt die Slug-Wortlisten gegen fehlerhafte Edits (Duplikate,
|
|
4
|
+
// Großbuchstaben, Bindestriche, Müll-Einträge). Bewusst NICHT an die
|
|
5
|
+
// veralteten Inline-Kommentare gebunden ("150 × 150", "4-8 Buchstaben") —
|
|
6
|
+
// real sind es mehr Wörter und weitere Längen; getestet werden die echten
|
|
7
|
+
// harten Invarianten + die dokumentierte Mindest-Diversität.
|
|
8
|
+
|
|
9
|
+
import { describe, expect, test } from "bun:test";
|
|
10
|
+
import { ADJECTIVES, NOUNS } from "../index";
|
|
11
|
+
|
|
12
|
+
const LISTS: ReadonlyArray<readonly [string, readonly string[]]> = [
|
|
13
|
+
["ADJECTIVES", ADJECTIVES],
|
|
14
|
+
["NOUNS", NOUNS],
|
|
15
|
+
];
|
|
16
|
+
|
|
17
|
+
describe("words — Slug-Wortlisten Invarianten", () => {
|
|
18
|
+
for (const [name, list] of LISTS) {
|
|
19
|
+
describe(name, () => {
|
|
20
|
+
test("nur lowercase a-z (keine Ziffern, Bindestriche, Whitespace, Umlaute)", () => {
|
|
21
|
+
const offenders = list.filter((w) => !/^[a-z]+$/.test(w));
|
|
22
|
+
expect(offenders).toEqual([]);
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
test("keine Duplikate", () => {
|
|
26
|
+
const dupes = list.filter((w, i) => list.indexOf(w) !== i);
|
|
27
|
+
expect(dupes).toEqual([]);
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
test("mindestens 150 Wörter (untere Schranke für Combo-Diversität)", () => {
|
|
31
|
+
expect(list.length).toBeGreaterThanOrEqual(150);
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
test("Wortlänge im Müll-Schutz-Korridor 3..12 (fängt leere/Satz-Einträge)", () => {
|
|
35
|
+
const outliers = list.filter((w) => w.length < 3 || w.length > 12);
|
|
36
|
+
expect(outliers).toEqual([]);
|
|
37
|
+
});
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
test("ergibt ≥ 22.500 saubere Kombinationen (dokumentierte Mindest-Diversität)", () => {
|
|
42
|
+
expect(ADJECTIVES.length * NOUNS.length).toBeGreaterThanOrEqual(22_500);
|
|
43
|
+
});
|
|
44
|
+
});
|
package/src/random/generate.ts
CHANGED
|
@@ -42,9 +42,9 @@ export type AdjNounNameOptions = {
|
|
|
42
42
|
* (no-confusable-Alphabet). Empfohlen 3 Zeichen = 32^3 = 32.768
|
|
43
43
|
* zusätzliche Combinations pro Wortpaar. */
|
|
44
44
|
readonly suffix?: { readonly length: number };
|
|
45
|
-
/** Custom Adjective-Liste — default ADJECTIVES (
|
|
45
|
+
/** Custom Adjective-Liste — default ADJECTIVES (191 generic). */
|
|
46
46
|
readonly adjectives?: readonly string[];
|
|
47
|
-
/** Custom Noun-Liste — default NOUNS (
|
|
47
|
+
/** Custom Noun-Liste — default NOUNS (173 generic). Apps die Domain-
|
|
48
48
|
* spezifische Slugs wollen (z.B. webhook-feature mit eigenen
|
|
49
49
|
* -receiver/-listener-Substantiven) reichen ihre eigene Liste. */
|
|
50
50
|
readonly nouns?: readonly string[];
|
|
@@ -83,7 +83,7 @@ export type GenerateUniqueNameOptions = {
|
|
|
83
83
|
* ist (typisch: DB-Query "select where slug=$1" → row count === 0). */
|
|
84
84
|
readonly isAvailable: (name: string) => Promise<boolean>;
|
|
85
85
|
/** Max Versuche OHNE Suffix bevor wir auf suffix-mode wechseln.
|
|
86
|
-
* Default 3. Bei
|
|
86
|
+
* Default 3. Bei 33.043 Default-Combos und ~150 existierenden
|
|
87
87
|
* Tenants liegt p(Kollision) < 1% — 3 Versuche reichen weit. */
|
|
88
88
|
readonly maxCleanAttempts?: number;
|
|
89
89
|
/** Suffix-Länge bei Kollision-Mode. Default 3 (= 32.768 Combinations
|
package/src/random/words.ts
CHANGED
|
@@ -9,12 +9,12 @@
|
|
|
9
9
|
// - Keine Personennamen (cultural appropriation, prominenten-collision)
|
|
10
10
|
// - Keine Themen-Cluster (kein Wetter-only, kein Geographie-only)
|
|
11
11
|
// - Lowercase, ASCII-only, keine Bindestriche im Wort selbst
|
|
12
|
-
// -
|
|
12
|
+
// - 3-10 Buchstaben pro Wort (kompakter Slug)
|
|
13
13
|
// - Aussprechbar in Deutsch UND Englisch (User-Telefon-Support)
|
|
14
14
|
// - Keine Wörter mit ambiguer Bedeutung in Englisch+Deutsch
|
|
15
15
|
//
|
|
16
|
-
//
|
|
17
|
-
// Hashing-Kollision (Birthday-Bound) reicht das für ~
|
|
16
|
+
// 191 × 173 = 33.043 saubere Kombinationen — bei einer Standard-
|
|
17
|
+
// Hashing-Kollision (Birthday-Bound) reicht das für ~180 Tenants ohne
|
|
18
18
|
// Suffix. Drüber kommt der Suffix-Pfad in generateUniqueName.
|
|
19
19
|
//
|
|
20
20
|
// Erweiterung: weitere Wörter unten anhängen reicht (sortiert ist
|
|
@@ -60,8 +60,8 @@ function isMetaShape(v: unknown): v is EntityTableMeta {
|
|
|
60
60
|
v !== null &&
|
|
61
61
|
typeof (v as EntityTableMeta).tableName === "string" &&
|
|
62
62
|
Array.isArray((v as EntityTableMeta).columns) &&
|
|
63
|
-
|
|
64
|
-
|
|
63
|
+
Array.isArray((v as EntityTableMeta).indexes) &&
|
|
64
|
+
((v as EntityTableMeta).source === "managed" || (v as EntityTableMeta).source === "unmanaged")
|
|
65
65
|
);
|
|
66
66
|
}
|
|
67
67
|
|
package/src/stack/test-stack.ts
CHANGED
|
@@ -171,8 +171,8 @@ export async function setupTestStack(options: TestStackOptions): Promise<TestSta
|
|
|
171
171
|
// everything registered via r.projection() — keeps tests from having to
|
|
172
172
|
// know which projections a feature happens to declare. Two projections
|
|
173
173
|
// backed by the same physical table (e.g. an alternative apply-shape for
|
|
174
|
-
// the same read-model in a test feature) are deduped by
|
|
175
|
-
//
|
|
174
|
+
// the same read-model in a test feature) are deduped by table reference so
|
|
175
|
+
// we emit only one CREATE TABLE per physical table.
|
|
176
176
|
const projectionTables: Record<string, unknown> = {};
|
|
177
177
|
const seenTables = new Set<unknown>();
|
|
178
178
|
for (const feature of options.features) {
|
|
@@ -205,8 +205,7 @@ export async function setupTestStack(options: TestStackOptions): Promise<TestSta
|
|
|
205
205
|
// unsafePushTables emits raw CREATE TABLE — fine for ephemeral test DBs but
|
|
206
206
|
// collides on re-boot against a persistent DB whose projection tables
|
|
207
207
|
// were created during a previous run. Filter out the ones that already
|
|
208
|
-
// exist
|
|
209
|
-
// them again.
|
|
208
|
+
// exist so the re-boot doesn't fail on duplicate CREATE TABLE.
|
|
210
209
|
const { tableExists } = await import("../db/schema-inspection");
|
|
211
210
|
const missing: Record<string, unknown> = {};
|
|
212
211
|
for (const [key, tbl] of Object.entries(projectionTables)) {
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
import { describe, expect, test } from "bun:test";
|
|
2
|
-
import type { FieldIssue as FrameworkFieldIssue } from "@cosmicdrift/kumiko-framework/errors";
|
|
3
|
-
import type { FieldIssue as HeadlessFieldIssue } from "@cosmicdrift/kumiko-headless";
|
|
4
|
-
|
|
5
|
-
describe("FieldIssue cross-package contract", () => {
|
|
6
|
-
test("framework and headless FieldIssue shapes are assignable", () => {
|
|
7
|
-
const frameworkIssue: FrameworkFieldIssue = {
|
|
8
|
-
path: "title",
|
|
9
|
-
code: "too_small",
|
|
10
|
-
i18nKey: "errors.validation.too_small",
|
|
11
|
-
params: { minimum: 1 },
|
|
12
|
-
};
|
|
13
|
-
const headlessIssue: HeadlessFieldIssue = frameworkIssue;
|
|
14
|
-
expect(headlessIssue.path).toBe("title");
|
|
15
|
-
});
|
|
16
|
-
});
|