@cosmicdrift/kumiko-framework 0.258.0 → 0.259.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 +3 -3
- package/src/__tests__/anonymous-access.integration.test.ts +3 -3
- package/src/__tests__/derived-fields.integration.test.ts +1 -1
- package/src/__tests__/entity-list-limits.integration.test.ts +1 -1
- package/src/__tests__/error-contract.integration.test.ts +1 -1
- package/src/__tests__/ownership-where-write-path.integration.test.ts +1 -1
- package/src/__tests__/ownership.integration.test.ts +7 -3
- package/src/__tests__/schema-cli-rebuild.integration.test.ts +2 -2
- package/src/__tests__/transition-guard.integration.test.ts +3 -3
- package/src/api/__tests__/api.test.ts +21 -3
- package/src/api/__tests__/batch.integration.test.ts +3 -3
- package/src/api/__tests__/body-limit.test.ts +7 -1
- package/src/api/__tests__/dispatcher-live.integration.test.ts +1 -1
- package/src/api/__tests__/http-route-rate-limit.integration.test.ts +7 -1
- package/src/api/__tests__/metrics-endpoint.test.ts +7 -1
- package/src/api/__tests__/nested-write.integration.test.ts +3 -3
- package/src/api/__tests__/server-boot-guards.test.ts +11 -4
- package/src/bun-db/__tests__/write-brand.test.ts +4 -1
- package/src/changes.json +6 -0
- package/src/db/__tests__/apply-entity-event-tenant.integration.test.ts +1 -1
- package/src/db/__tests__/assert-exists-in.integration.test.ts +1 -1
- package/src/db/__tests__/assert-no-unreachable-live-rows.integration.test.ts +2 -2
- package/src/db/__tests__/collect-table-metas.test.ts +9 -5
- package/src/db/__tests__/compound-types.test.ts +1 -1
- package/src/db/__tests__/config-seed.integration.test.ts +3 -3
- package/src/db/__tests__/eagerload.integration.test.ts +7 -7
- package/src/db/__tests__/entity-table-from-registry.test.ts +8 -2
- package/src/db/__tests__/entity-table-meta-source.test.ts +7 -3
- package/src/db/__tests__/entity-table-types.test.ts +4 -4
- package/src/db/__tests__/event-store-executor-list.integration.test.ts +9 -2
- package/src/db/__tests__/event-store-executor-reference-search.integration.test.ts +4 -4
- package/src/db/__tests__/event-store-executor-reference-sort.integration.test.ts +3 -3
- package/src/db/__tests__/event-store-executor-write-verbs.integration.test.ts +4 -4
- package/src/db/__tests__/event-store-executor.integration.test.ts +11 -6
- package/src/db/__tests__/event-store-system-stream.integration.test.ts +2 -2
- package/src/db/__tests__/implicit-projection-equivalence.integration.test.ts +6 -4
- package/src/db/__tests__/located-timestamp.test.ts +1 -1
- package/src/db/__tests__/money.test.ts +1 -1
- package/src/db/__tests__/multi-row-insert.integration.test.ts +3 -3
- package/src/db/__tests__/schema-migration.integration.test.ts +30 -14
- package/src/db/__tests__/source-shadow-create.integration.test.ts +1 -1
- package/src/db/__tests__/table-builder-indexes.test.ts +14 -12
- package/src/db/__tests__/table-builder-required.test.ts +2 -2
- package/src/db/__tests__/tenant-db-where-merge.integration.test.ts +1 -1
- package/src/db/__tests__/tenant-db-where-merge.test.ts +5 -2
- package/src/db/__tests__/tenant-db.integration.test.ts +2 -2
- package/src/db/__tests__/unique-violation-mapping.integration.test.ts +2 -2
- package/src/engine/__tests__/boot-validator-action-wiring.test.ts +50 -8
- package/src/engine/__tests__/boot-validator-dashboard.test.ts +138 -1
- package/src/engine/__tests__/boot-validator-detail-for.test.ts +28 -4
- package/src/engine/__tests__/boot-validator-entity-list.test.ts +20 -4
- package/src/engine/__tests__/boot-validator-i18n-keys.test.ts +9 -3
- package/src/engine/__tests__/boot-validator.test.ts +488 -91
- package/src/engine/__tests__/define-feature-entity-mapping.test.ts +2 -2
- package/src/engine/__tests__/engine.test.ts +128 -37
- package/src/engine/__tests__/entity-handlers.test.ts +3 -3
- package/src/engine/__tests__/entity-presave-wiring.integration.test.ts +4 -4
- package/src/engine/__tests__/entity-restore-tenant-isolation.integration.test.ts +1 -1
- package/src/engine/__tests__/entity-write-crosstenant.integration.test.ts +1 -1
- package/src/engine/__tests__/extend-entity-projection.test.ts +1 -1
- package/src/engine/__tests__/extends-registrar.test.ts +13 -3
- package/src/engine/__tests__/factories-long-text.test.ts +10 -6
- package/src/engine/__tests__/feature-crud-shorthand.test.ts +1 -1
- package/src/engine/__tests__/feature-crud-verb-access.integration.test.ts +1 -1
- package/src/engine/__tests__/multiselect-filter.integration.test.ts +1 -1
- package/src/engine/__tests__/nav.test.ts +1 -1
- package/src/engine/__tests__/pipeline-handler.integration.test.ts +1 -1
- package/src/engine/__tests__/pipeline-observability.integration.test.ts +1 -1
- package/src/engine/__tests__/pipeline-performance.integration.test.ts +1 -1
- package/src/engine/__tests__/projection-detail-actions.test.ts +6 -1
- package/src/engine/__tests__/projection-detail-singleton.test.ts +6 -1
- package/src/engine/__tests__/projection-detail-tabs.test.ts +6 -1
- package/src/engine/__tests__/projection-list-filter.integration.test.ts +7 -2
- package/src/engine/__tests__/projection.test.ts +1 -1
- package/src/engine/__tests__/registry.test.ts +13 -3
- package/src/engine/__tests__/schema-builder.test.ts +39 -11
- package/src/engine/__tests__/screen.test.ts +21 -15
- package/src/engine/__tests__/search-payload-extension.test.ts +15 -3
- package/src/engine/__tests__/store-table.test.ts +6 -3
- package/src/engine/__tests__/validate-projection-allowlist.test.ts +12 -4
- package/src/engine/__tests__/validation-hooks.test.ts +7 -1
- package/src/engine/boot-validator/__tests__/ownership.test.ts +2 -2
- package/src/engine/boot-validator/query-refs.ts +11 -0
- package/src/engine/boot-validator/screens.ts +45 -2
- package/src/engine/build-config-feature-schema.ts +2 -2
- package/src/engine/index.ts +2 -0
- package/src/engine/types/index.ts +2 -0
- package/src/es-ops/__tests__/runner.integration.test.ts +1 -1
- package/src/event-store/__tests__/upcaster.integration.test.ts +1 -1
- package/src/files/__tests__/file-field-pipeline.integration.test.ts +1 -1
- package/src/files/__tests__/files.integration.test.ts +1 -1
- package/src/files/file-ref-entity.ts +9 -9
- package/src/i18n/__tests__/i18n.test.ts +7 -1
- package/src/migrations/__tests__/kumiko-drift.integration.test.ts +3 -1
- package/src/migrations/__tests__/pending-rebuilds.integration.test.ts +2 -2
- package/src/pipeline/__tests__/archive-stream.integration.test.ts +1 -1
- package/src/pipeline/__tests__/cascade-handler.integration.test.ts +23 -8
- package/src/pipeline/__tests__/cascade-handler.test.ts +18 -3
- package/src/pipeline/__tests__/causation-chain.integration.test.ts +1 -1
- package/src/pipeline/__tests__/ctx-bridge.integration.test.ts +5 -3
- package/src/pipeline/__tests__/dispatcher.test.ts +42 -6
- package/src/pipeline/__tests__/domain-events-projections.integration.test.ts +2 -2
- package/src/pipeline/__tests__/fetch-for-writing.integration.test.ts +1 -1
- package/src/pipeline/__tests__/lifecycle-pipeline.test.ts +42 -6
- package/src/pipeline/__tests__/load-aggregate-query.integration.test.ts +2 -2
- package/src/pipeline/__tests__/msp-multi-hop.integration.test.ts +1 -1
- package/src/pipeline/__tests__/msp-rebuild.integration.test.ts +6 -2
- package/src/pipeline/__tests__/multi-stream-projection.integration.test.ts +6 -2
- package/src/pipeline/__tests__/perf-rebuild.integration.test.ts +1 -1
- package/src/pipeline/__tests__/post-query-hook.integration.test.ts +3 -3
- package/src/pipeline/__tests__/projection-rebuild.integration.test.ts +3 -3
- package/src/pipeline/__tests__/query-projection.integration.test.ts +1 -1
- package/src/pipeline/__tests__/rebuild-poison-quarantine.integration.test.ts +2 -2
- package/src/pipeline/__tests__/search-consumer-named-events.integration.test.ts +13 -2
- package/src/pipeline/__tests__/try-append-event.integration.test.ts +1 -1
- package/src/search/__tests__/reindex-entity.integration.test.ts +6 -1
- package/src/search/__tests__/search-pii-derived-index.integration.test.ts +7 -1
- package/src/stack/__tests__/ownership-boot-guard.integration.test.ts +1 -1
- package/src/testing/__tests__/e2e-generator.test.ts +15 -5
- package/src/testing/shared-entities.ts +4 -2
- package/src/ui-types/index.ts +2 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cosmicdrift/kumiko-framework",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.259.0",
|
|
4
4
|
"description": "Framework core — engine, pipeline, API, DB, and every other bit that makes Kumiko go.",
|
|
5
5
|
"license": "BUSL-1.1",
|
|
6
6
|
"author": "Marc Frost <marc@cosmicdriftgamestudio.com>",
|
|
@@ -198,7 +198,7 @@
|
|
|
198
198
|
"./package.json": "./package.json"
|
|
199
199
|
},
|
|
200
200
|
"dependencies": {
|
|
201
|
-
"@cosmicdrift/kumiko-types": "0.
|
|
201
|
+
"@cosmicdrift/kumiko-types": "0.259.0",
|
|
202
202
|
"bullmq": "^5.76.7",
|
|
203
203
|
"bun-types": "^1.3.13",
|
|
204
204
|
"hono": "^4.13.1",
|
|
@@ -214,7 +214,7 @@
|
|
|
214
214
|
"zod": "^4.4.3"
|
|
215
215
|
},
|
|
216
216
|
"devDependencies": {
|
|
217
|
-
"@cosmicdrift/kumiko-dispatcher-live": "0.
|
|
217
|
+
"@cosmicdrift/kumiko-dispatcher-live": "0.259.0",
|
|
218
218
|
"bun-types": "^1.3.13",
|
|
219
219
|
"pino-pretty": "^13.1.3"
|
|
220
220
|
},
|
|
@@ -29,7 +29,7 @@ const OTHER_TENANT_ID = "00000000-0000-4000-8000-000000000002" as TenantId;
|
|
|
29
29
|
const productEntity = createEntity({
|
|
30
30
|
table: "anon_products",
|
|
31
31
|
fields: {
|
|
32
|
-
name: createTextField({ required: true }),
|
|
32
|
+
name: createTextField({ personal: false, reason: "test_fixture", required: true }),
|
|
33
33
|
},
|
|
34
34
|
});
|
|
35
35
|
const productTable = buildEntityTable("product", productEntity);
|
|
@@ -37,8 +37,8 @@ const productTable = buildEntityTable("product", productEntity);
|
|
|
37
37
|
const orderEntity = createEntity({
|
|
38
38
|
table: "anon_orders",
|
|
39
39
|
fields: {
|
|
40
|
-
productName: createTextField({ required: true }),
|
|
41
|
-
placedBy: createTextField({ default: "" }),
|
|
40
|
+
productName: createTextField({ personal: false, reason: "test_fixture", required: true }),
|
|
41
|
+
placedBy: createTextField({ personal: false, reason: "test_fixture", default: "" }),
|
|
42
42
|
},
|
|
43
43
|
});
|
|
44
44
|
const orderTable = buildEntityTable("order", orderEntity);
|
|
@@ -23,7 +23,7 @@ import { setupTestStack, type TestStack, TestUsers, unsafeCreateEntityTable } fr
|
|
|
23
23
|
const gadgetEntity = createEntity({
|
|
24
24
|
table: "derived_gadgets",
|
|
25
25
|
fields: {
|
|
26
|
-
name: createTextField({ required: true }),
|
|
26
|
+
name: createTextField({ personal: false, reason: "test_fixture", required: true }),
|
|
27
27
|
priceCents: createNumberField({ required: true }),
|
|
28
28
|
},
|
|
29
29
|
derivedFields: {
|
|
@@ -19,7 +19,7 @@ import { setupTestStack, type TestStack, TestUsers, unsafeCreateEntityTable } fr
|
|
|
19
19
|
|
|
20
20
|
const widgetEntity = createEntity({
|
|
21
21
|
table: "limit_widgets",
|
|
22
|
-
fields: { name: createTextField({ required: true }) },
|
|
22
|
+
fields: { name: createTextField({ personal: false, reason: "test_fixture", required: true }) },
|
|
23
23
|
});
|
|
24
24
|
|
|
25
25
|
const widgetFeature = defineFeature("limitwidgets", (r) => {
|
|
@@ -35,7 +35,7 @@ import {
|
|
|
35
35
|
const itemEntity = createEntity({
|
|
36
36
|
table: "errctr_items",
|
|
37
37
|
fields: {
|
|
38
|
-
name: createTextField({ required: true }),
|
|
38
|
+
name: createTextField({ personal: false, reason: "test_fixture", required: true }),
|
|
39
39
|
stock: createNumberField({ default: 0 }),
|
|
40
40
|
},
|
|
41
41
|
});
|
|
@@ -46,7 +46,7 @@ const memoEntity = createEntity({
|
|
|
46
46
|
softDelete: true,
|
|
47
47
|
fields: {
|
|
48
48
|
ownerId: createTextField({ required: true }),
|
|
49
|
-
title: createTextField({ required: true }),
|
|
49
|
+
title: createTextField({ personal: false, reason: "test_fixture", required: true }),
|
|
50
50
|
},
|
|
51
51
|
access: {
|
|
52
52
|
read: { Admin: "all", Member: "all" },
|
|
@@ -36,17 +36,21 @@ const contractEntity = createEntity({
|
|
|
36
36
|
table: "h2_contracts",
|
|
37
37
|
softDelete: true,
|
|
38
38
|
fields: {
|
|
39
|
-
teamId: createTextField({ required: true }),
|
|
39
|
+
teamId: createTextField({ personal: false, reason: "test_fixture", required: true }),
|
|
40
40
|
assigneeId: createTextField(),
|
|
41
|
-
title: createTextField({ required: true }),
|
|
41
|
+
title: createTextField({ personal: false, reason: "test_fixture", required: true }),
|
|
42
42
|
// propA: public on read + write
|
|
43
|
-
propA: createTextField(),
|
|
43
|
+
propA: createTextField({ personal: false, reason: "test_fixture" }),
|
|
44
44
|
// propB: Admin-only
|
|
45
45
|
propB: createTextField({
|
|
46
|
+
personal: false,
|
|
47
|
+
reason: "test_fixture",
|
|
46
48
|
access: { read: { Admin: "all" }, write: { Admin: "all" } },
|
|
47
49
|
}),
|
|
48
50
|
// propC: Admin full, TeamMember scoped to matching teamId
|
|
49
51
|
propC: createTextField({
|
|
52
|
+
personal: false,
|
|
53
|
+
reason: "test_fixture",
|
|
50
54
|
access: {
|
|
51
55
|
read: { Admin: "all", TeamMember: from("claim:teams:teamId") },
|
|
52
56
|
write: { Admin: "all", TeamMember: from("claim:teams:teamId") },
|
|
@@ -33,8 +33,8 @@ import { ensureTemporalPolyfill } from "../time/polyfill";
|
|
|
33
33
|
const itemEntity = createEntity({
|
|
34
34
|
table: "read_apply_items",
|
|
35
35
|
fields: {
|
|
36
|
-
groupId: createTextField({ required: true }),
|
|
37
|
-
name: createTextField({ required: true }),
|
|
36
|
+
groupId: createTextField({ personal: false, reason: "test_fixture", required: true }),
|
|
37
|
+
name: createTextField({ personal: false, reason: "test_fixture", required: true }),
|
|
38
38
|
},
|
|
39
39
|
softDelete: true,
|
|
40
40
|
});
|
|
@@ -21,7 +21,7 @@ import { expectErrorIncludes } from "../testing";
|
|
|
21
21
|
const invoiceEntity = createEntity({
|
|
22
22
|
table: "tg_invoices",
|
|
23
23
|
fields: {
|
|
24
|
-
title: createTextField({ required: true }),
|
|
24
|
+
title: createTextField({ personal: false, reason: "test_fixture", required: true }),
|
|
25
25
|
status: createSelectField({ options: ["draft", "sent", "paid"] as const, default: "draft" }),
|
|
26
26
|
},
|
|
27
27
|
transitions: {
|
|
@@ -36,7 +36,7 @@ const invoiceEntity = createEntity({
|
|
|
36
36
|
const orderEntity = createEntity({
|
|
37
37
|
table: "tg_orders",
|
|
38
38
|
fields: {
|
|
39
|
-
title: createTextField({ required: true }),
|
|
39
|
+
title: createTextField({ personal: false, reason: "test_fixture", required: true }),
|
|
40
40
|
status: createSelectField({
|
|
41
41
|
options: ["open", "shipped", "delivered"] as const,
|
|
42
42
|
default: "open",
|
|
@@ -55,7 +55,7 @@ const orderEntity = createEntity({
|
|
|
55
55
|
const ticketEntity = createEntity({
|
|
56
56
|
table: "tg_tickets",
|
|
57
57
|
fields: {
|
|
58
|
-
title: createTextField({ required: true }),
|
|
58
|
+
title: createTextField({ personal: false, reason: "test_fixture", required: true }),
|
|
59
59
|
status: createSelectField({ options: ["open", "closed"] as const, default: "open" }),
|
|
60
60
|
isDeleted: createBooleanField({ default: false }),
|
|
61
61
|
},
|
|
@@ -18,7 +18,13 @@ import { buildServer } from "../server";
|
|
|
18
18
|
const JWT_SECRET = "test-secret-at-least-32-chars-long!!";
|
|
19
19
|
|
|
20
20
|
const testFeature = defineFeature("test", (r) => {
|
|
21
|
-
r.entity(
|
|
21
|
+
r.entity(
|
|
22
|
+
"item",
|
|
23
|
+
createEntity({
|
|
24
|
+
table: "Items",
|
|
25
|
+
fields: { name: createTextField({ personal: false, reason: "test_fixture" }) },
|
|
26
|
+
}),
|
|
27
|
+
);
|
|
22
28
|
|
|
23
29
|
r.writeHandler(
|
|
24
30
|
"item:create",
|
|
@@ -726,7 +732,13 @@ describe("feature-declared HTTP routes (r.httpRoute)", () => {
|
|
|
726
732
|
// → Hono-app.{get,post}(path) → Response. deps.app erlaubt internal-call
|
|
727
733
|
// an /api/* (gleicher Auth-Pfad wie ein echter HTTP-Call).
|
|
728
734
|
const routeFeature = defineFeature("routes", (r) => {
|
|
729
|
-
r.entity(
|
|
735
|
+
r.entity(
|
|
736
|
+
"item",
|
|
737
|
+
createEntity({
|
|
738
|
+
table: "Items",
|
|
739
|
+
fields: { name: createTextField({ personal: false, reason: "test_fixture" }) },
|
|
740
|
+
}),
|
|
741
|
+
);
|
|
730
742
|
r.queryHandler("item:list", z.object({}), async () => [{ id: 7 }], {
|
|
731
743
|
access: { openToAll: true },
|
|
732
744
|
});
|
|
@@ -776,7 +788,13 @@ describe("feature-declared HTTP routes (r.httpRoute)", () => {
|
|
|
776
788
|
// defaultTenantId macht den inner-Call ohne Bearer-Token möglich;
|
|
777
789
|
// pinst dass deps.app.fetch identisch zu einem echten HTTP-Call läuft.
|
|
778
790
|
const inner = defineFeature("inner", (r) => {
|
|
779
|
-
r.entity(
|
|
791
|
+
r.entity(
|
|
792
|
+
"item",
|
|
793
|
+
createEntity({
|
|
794
|
+
table: "Items",
|
|
795
|
+
fields: { name: createTextField({ personal: false, reason: "test_fixture" }) },
|
|
796
|
+
}),
|
|
797
|
+
);
|
|
780
798
|
// Bewusst "anonymous" — openToAll schließt anonymous-User explizit
|
|
781
799
|
// aus (siehe access.ts), damit das Aktivieren von anonymousAccess
|
|
782
800
|
// nicht versehentlich jeden openToAll-Handler public macht.
|
|
@@ -22,7 +22,7 @@ import { setupTestStack, type TestStack, TestUsers, unsafeCreateEntityTable } fr
|
|
|
22
22
|
const itemEntity = createEntity({
|
|
23
23
|
table: "batch_items",
|
|
24
24
|
fields: {
|
|
25
|
-
name: createTextField({ required: true }),
|
|
25
|
+
name: createTextField({ personal: false, reason: "test_fixture", required: true }),
|
|
26
26
|
counter: createNumberField({ default: 0 }),
|
|
27
27
|
},
|
|
28
28
|
});
|
|
@@ -34,8 +34,8 @@ const itemTable = buildEntityTable("item", itemEntity);
|
|
|
34
34
|
const auditEntity = createEntity({
|
|
35
35
|
table: "batch_audit",
|
|
36
36
|
fields: {
|
|
37
|
-
action: createTextField({ required: true }),
|
|
38
|
-
itemId: createTextField({ required: true }),
|
|
37
|
+
action: createTextField({ personal: false, reason: "test_fixture", required: true }),
|
|
38
|
+
itemId: createTextField({ personal: false, reason: "test_fixture", required: true }),
|
|
39
39
|
},
|
|
40
40
|
});
|
|
41
41
|
// Brand (#742) is compile-time-only; the postSave hook writes this sink via method-form,
|
|
@@ -7,7 +7,13 @@ import { buildServer } from "../server";
|
|
|
7
7
|
const JWT_SECRET = "test-secret-at-least-32-chars-long!!";
|
|
8
8
|
|
|
9
9
|
const testFeature = defineFeature("blob", (r) => {
|
|
10
|
-
r.entity(
|
|
10
|
+
r.entity(
|
|
11
|
+
"note",
|
|
12
|
+
createEntity({
|
|
13
|
+
table: "Notes",
|
|
14
|
+
fields: { body: createTextField({ personal: false, reason: "test_fixture" }) },
|
|
15
|
+
}),
|
|
16
|
+
);
|
|
11
17
|
r.writeHandler(
|
|
12
18
|
"note:create",
|
|
13
19
|
z.object({ body: z.string() }),
|
|
@@ -23,7 +23,7 @@ import { generateId } from "../../utils";
|
|
|
23
23
|
|
|
24
24
|
const itemEntity = createEntity({
|
|
25
25
|
table: "dispatcher_live_items",
|
|
26
|
-
fields: { name: createTextField({ required: true }) },
|
|
26
|
+
fields: { name: createTextField({ personal: false, reason: "test_fixture", required: true }) },
|
|
27
27
|
});
|
|
28
28
|
const itemTable = buildEntityTable("item", itemEntity);
|
|
29
29
|
|
|
@@ -14,7 +14,13 @@ import { setupTestStack, type TestStack } from "../../stack";
|
|
|
14
14
|
const SYSTEM_TENANT_ID = "00000000-0000-4000-8000-000000000000" as TenantId;
|
|
15
15
|
|
|
16
16
|
const ipLimitedFeature = defineFeature("rl-http", (r) => {
|
|
17
|
-
r.entity(
|
|
17
|
+
r.entity(
|
|
18
|
+
"item",
|
|
19
|
+
createEntity({
|
|
20
|
+
table: "Items",
|
|
21
|
+
fields: { name: createTextField({ personal: false, reason: "test_fixture" }) },
|
|
22
|
+
}),
|
|
23
|
+
);
|
|
18
24
|
r.queryHandler("ping", z.object({}), async () => ({ ok: true }), {
|
|
19
25
|
access: { roles: ["anonymous"] },
|
|
20
26
|
rateLimit: { per: "ip", limit: 2, windowSeconds: 60 },
|
|
@@ -10,7 +10,13 @@ import { buildServer } from "../server";
|
|
|
10
10
|
const JWT = "metrics-endpoint-test-secret-minimum-32-chars!!";
|
|
11
11
|
|
|
12
12
|
const noopFeature = defineFeature("m", (r) => {
|
|
13
|
-
r.entity(
|
|
13
|
+
r.entity(
|
|
14
|
+
"widget",
|
|
15
|
+
createEntity({
|
|
16
|
+
table: "Widgets",
|
|
17
|
+
fields: { name: createTextField({ personal: false, reason: "test_fixture" }) },
|
|
18
|
+
}),
|
|
19
|
+
);
|
|
14
20
|
});
|
|
15
21
|
|
|
16
22
|
// Swap the NoopProvider's meter for a PrometheusMeter. Tracer + lifecycle
|
|
@@ -12,15 +12,15 @@ import { setupTestStack, type TestStack, TestUsers, unsafeCreateEntityTable } fr
|
|
|
12
12
|
// per entry — all in the same TX as the parent.
|
|
13
13
|
const projectEntity = createEntity({
|
|
14
14
|
table: "nested_projects",
|
|
15
|
-
fields: { name: createTextField({ required: true }) },
|
|
15
|
+
fields: { name: createTextField({ personal: false, reason: "test_fixture", required: true }) },
|
|
16
16
|
});
|
|
17
17
|
const projectTable = buildEntityTable("project", projectEntity);
|
|
18
18
|
|
|
19
19
|
const taskEntity = createEntity({
|
|
20
20
|
table: "nested_tasks",
|
|
21
21
|
fields: {
|
|
22
|
-
projectId: createTextField({ required: true }),
|
|
23
|
-
title: createTextField({ required: true }),
|
|
22
|
+
projectId: createTextField({ personal: false, reason: "test_fixture", required: true }),
|
|
23
|
+
title: createTextField({ personal: false, reason: "test_fixture", required: true }),
|
|
24
24
|
},
|
|
25
25
|
});
|
|
26
26
|
const taskTable = buildEntityTable("task", taskEntity);
|
|
@@ -30,7 +30,10 @@ describe("buildServer — file-storage provider guard", () => {
|
|
|
30
30
|
"doc",
|
|
31
31
|
createEntity({
|
|
32
32
|
table: "boot_guard_docs",
|
|
33
|
-
fields: {
|
|
33
|
+
fields: {
|
|
34
|
+
title: createTextField({ personal: false, reason: "test_fixture" }),
|
|
35
|
+
attachment: createFileField(),
|
|
36
|
+
},
|
|
34
37
|
}),
|
|
35
38
|
);
|
|
36
39
|
});
|
|
@@ -88,7 +91,9 @@ describe("buildServer — search-adapter boot warning (#2051)", () => {
|
|
|
88
91
|
"note",
|
|
89
92
|
createEntity({
|
|
90
93
|
table: "boot_guard_notes",
|
|
91
|
-
fields: {
|
|
94
|
+
fields: {
|
|
95
|
+
title: createTextField({ personal: false, reason: "test_fixture", searchable: true }),
|
|
96
|
+
},
|
|
92
97
|
}),
|
|
93
98
|
);
|
|
94
99
|
r.screen({ id: "note-list", type: "entityList", entity: "note", columns: ["title"] });
|
|
@@ -99,7 +104,7 @@ describe("buildServer — search-adapter boot warning (#2051)", () => {
|
|
|
99
104
|
"note",
|
|
100
105
|
createEntity({
|
|
101
106
|
table: "boot_guard_plain_notes",
|
|
102
|
-
fields: { title: createTextField() },
|
|
107
|
+
fields: { title: createTextField({ personal: false, reason: "test_fixture" }) },
|
|
103
108
|
}),
|
|
104
109
|
);
|
|
105
110
|
r.screen({ id: "note-list", type: "entityList", entity: "note", columns: ["title"] });
|
|
@@ -114,7 +119,9 @@ describe("buildServer — search-adapter boot warning (#2051)", () => {
|
|
|
114
119
|
"download-attempt",
|
|
115
120
|
createEntity({
|
|
116
121
|
table: "boot_guard_download_attempts",
|
|
117
|
-
fields: {
|
|
122
|
+
fields: {
|
|
123
|
+
title: createTextField({ personal: false, reason: "test_fixture", searchable: true }),
|
|
124
|
+
},
|
|
118
125
|
}),
|
|
119
126
|
);
|
|
120
127
|
r.screen({
|
|
@@ -14,7 +14,10 @@ import { type AnyDb, deleteMany, insertOne, selectMany, updateMany } from "../qu
|
|
|
14
14
|
|
|
15
15
|
const brandedEntity = buildEntityTable(
|
|
16
16
|
"brandSample",
|
|
17
|
-
createEntity({
|
|
17
|
+
createEntity({
|
|
18
|
+
table: "brand_sample",
|
|
19
|
+
fields: { title: createTextField({ personal: false, reason: "test_fixture", required: true }) },
|
|
20
|
+
}),
|
|
18
21
|
);
|
|
19
22
|
|
|
20
23
|
const unmanagedTable = defineUnmanagedTable({
|
package/src/changes.json
CHANGED
|
@@ -1,4 +1,10 @@
|
|
|
1
1
|
[
|
|
2
|
+
{
|
|
3
|
+
"version": "0.259.0",
|
|
4
|
+
"type": "improvement",
|
|
5
|
+
"title": "Dashboard screens compose other declarative screens via kind: \"screen\" panels (fw#2844, decision fw#2841).",
|
|
6
|
+
"detail": "`DashboardScreenPanel` (`@cosmicdrift/kumiko-types`) embeds a registered screen by same-feature short id or `<feature>:screen:<id>`; embeddable are projectionList, actionForm, secretMint, configEdit, secretsEdit — the boot validator rejects unresolvable targets and dashboard/entityEdit/projectionDetail/custom/entityList. `visibleWhen: { query, field, eq }` shows the panel only while the live query's flat result matches (query boot-checked). A user without access to the target gets no tile. `DashboardBodyProps` gains the required `featureName` (only relevant for a custom dashboard body implementation); `useEmbeddedScreen` is exported from `@cosmicdrift/kumiko-renderer`. Replaces \"framework screen plus own content\" custom screens with an app-feature-structure lint-ignore."
|
|
7
|
+
},
|
|
2
8
|
{
|
|
3
9
|
"version": "0.242.0",
|
|
4
10
|
"type": "improvement",
|
|
@@ -29,7 +29,7 @@ import { buildEntityTable } from "../table-builder";
|
|
|
29
29
|
const entity = createEntity({
|
|
30
30
|
table: "read_apply_tenant_check",
|
|
31
31
|
fields: {
|
|
32
|
-
name: createTextField({ required: true }),
|
|
32
|
+
name: createTextField({ required: true, personal: false, reason: "test_fixture" }),
|
|
33
33
|
},
|
|
34
34
|
});
|
|
35
35
|
const table = buildEntityTable("apply-tenant-check", entity);
|
|
@@ -14,7 +14,7 @@ import { createTenantDb } from "../tenant-db";
|
|
|
14
14
|
|
|
15
15
|
const orderEntity = createEntity({
|
|
16
16
|
table: "ax_orders",
|
|
17
|
-
fields: { name: createTextField({ required: true }) },
|
|
17
|
+
fields: { name: createTextField({ required: true, personal: false, reason: "test_fixture" }) },
|
|
18
18
|
});
|
|
19
19
|
const orderTable = buildEntityTable("order", orderEntity);
|
|
20
20
|
|
|
@@ -26,8 +26,8 @@ import { createTenantDb, type TenantDb } from "../tenant-db";
|
|
|
26
26
|
const userEntity = createEntity({
|
|
27
27
|
table: "read_unreachable_users",
|
|
28
28
|
fields: {
|
|
29
|
-
email: createTextField({ required: true }),
|
|
30
|
-
firstName: createTextField(),
|
|
29
|
+
email: createTextField({ required: true, personal: false, reason: "test_fixture" }),
|
|
30
|
+
firstName: createTextField({ personal: false, reason: "test_fixture" }),
|
|
31
31
|
isEnabled: createBooleanField({ default: true }),
|
|
32
32
|
},
|
|
33
33
|
softDelete: true,
|
|
@@ -10,7 +10,7 @@ import { buildBaseColumns, buildEntityTable } from "../table-builder";
|
|
|
10
10
|
function exampleEntity() {
|
|
11
11
|
return createEntity({
|
|
12
12
|
table: "read_units",
|
|
13
|
-
fields: { name: createTextField() },
|
|
13
|
+
fields: { name: createTextField({ personal: false, reason: "test_fixture" }) },
|
|
14
14
|
});
|
|
15
15
|
}
|
|
16
16
|
|
|
@@ -140,7 +140,9 @@ describe("collectTableMetas — r.entity backing table (#347)", () => {
|
|
|
140
140
|
function widgetEntity() {
|
|
141
141
|
return createEntity({
|
|
142
142
|
table: "read_widgets",
|
|
143
|
-
fields: {
|
|
143
|
+
fields: {
|
|
144
|
+
name: createTextField({ required: true, personal: false, reason: "test_fixture" }),
|
|
145
|
+
},
|
|
144
146
|
});
|
|
145
147
|
}
|
|
146
148
|
|
|
@@ -165,13 +167,15 @@ describe("collectTableMetas — r.entity backing table (#347)", () => {
|
|
|
165
167
|
test("throws when the backing table is missing a field's column (superset violated)", () => {
|
|
166
168
|
const thin = createEntity({
|
|
167
169
|
table: "read_widgets",
|
|
168
|
-
fields: {
|
|
170
|
+
fields: {
|
|
171
|
+
name: createTextField({ required: true, personal: false, reason: "test_fixture" }),
|
|
172
|
+
},
|
|
169
173
|
});
|
|
170
174
|
const rich = createEntity({
|
|
171
175
|
table: "read_widgets",
|
|
172
176
|
fields: {
|
|
173
|
-
name: createTextField({ required: true }),
|
|
174
|
-
extra: createTextField({ required: true }),
|
|
177
|
+
name: createTextField({ required: true, personal: false, reason: "test_fixture" }),
|
|
178
|
+
extra: createTextField({ required: true, personal: false, reason: "test_fixture" }),
|
|
175
179
|
},
|
|
176
180
|
});
|
|
177
181
|
// Backing table built from the THIN entity lacks the `extra` column.
|
|
@@ -18,7 +18,7 @@ import { flattenCompoundTypes, rehydrateCompoundTypes } from "../compound-types"
|
|
|
18
18
|
const mixedEntity: EntityDefinition = createEntity({
|
|
19
19
|
defaultCurrency: "EUR",
|
|
20
20
|
fields: {
|
|
21
|
-
label: createTextField(),
|
|
21
|
+
label: createTextField({ personal: false, reason: "test_fixture" }),
|
|
22
22
|
pickup: createLocatedTimestampField(),
|
|
23
23
|
buyingPrice: createMoneyField(),
|
|
24
24
|
},
|
|
@@ -23,9 +23,9 @@ import { buildEntityTable } from "../table-builder";
|
|
|
23
23
|
const configEntity = createEntity({
|
|
24
24
|
table: "read_cfg_seed_test",
|
|
25
25
|
fields: {
|
|
26
|
-
key: createTextField({ required: true }),
|
|
27
|
-
value: createTextField({}),
|
|
28
|
-
userId: createTextField({}),
|
|
26
|
+
key: createTextField({ required: true, personal: false, reason: "test_fixture" }),
|
|
27
|
+
value: createTextField({ personal: false, reason: "test_fixture" }),
|
|
28
|
+
userId: createTextField({ personal: false, reason: "test_fixture" }),
|
|
29
29
|
},
|
|
30
30
|
indexes: [
|
|
31
31
|
{
|
|
@@ -30,12 +30,12 @@ import { createTenantDb } from "../tenant-db";
|
|
|
30
30
|
|
|
31
31
|
const authorEntity = createEntity({
|
|
32
32
|
table: "el_authors",
|
|
33
|
-
fields: { name: createTextField({ required: true }) },
|
|
33
|
+
fields: { name: createTextField({ required: true, personal: false, reason: "test_fixture" }) },
|
|
34
34
|
});
|
|
35
35
|
const postEntity = createEntity({
|
|
36
36
|
table: "el_posts",
|
|
37
37
|
fields: {
|
|
38
|
-
title: createTextField({ required: true }),
|
|
38
|
+
title: createTextField({ required: true, personal: false, reason: "test_fixture" }),
|
|
39
39
|
author: { type: "reference", entity: "author" },
|
|
40
40
|
tags: { type: "reference", entity: "author", multiple: true },
|
|
41
41
|
},
|
|
@@ -48,7 +48,7 @@ const authorTable = buildEntityTable("author", authorEntity);
|
|
|
48
48
|
const contactEntity = createEntity({
|
|
49
49
|
table: "el_contacts",
|
|
50
50
|
fields: {
|
|
51
|
-
name: createTextField({ required: true }),
|
|
51
|
+
name: createTextField({ required: true, personal: false, reason: "test_fixture" }),
|
|
52
52
|
email: createTextField({ required: true, personal: "tenant", find: "none" }),
|
|
53
53
|
iban: createTextField({ required: true, encrypted: true }),
|
|
54
54
|
},
|
|
@@ -56,7 +56,7 @@ const contactEntity = createEntity({
|
|
|
56
56
|
const leadEntity = createEntity({
|
|
57
57
|
table: "el_leads",
|
|
58
58
|
fields: {
|
|
59
|
-
title: createTextField({ required: true }),
|
|
59
|
+
title: createTextField({ required: true, personal: false, reason: "test_fixture" }),
|
|
60
60
|
contact: { type: "reference", entity: "contact" },
|
|
61
61
|
ownedContact: { type: "reference", entity: "ownedContact" },
|
|
62
62
|
unrestrictedContact: { type: "reference", entity: "unrestrictedContact" },
|
|
@@ -70,7 +70,7 @@ const contactTable = buildEntityTable("contact", contactEntity);
|
|
|
70
70
|
const ownedContactEntity = createEntity({
|
|
71
71
|
table: "el_owned_contacts",
|
|
72
72
|
fields: {
|
|
73
|
-
name: createTextField({ required: true }),
|
|
73
|
+
name: createTextField({ required: true, personal: false, reason: "test_fixture" }),
|
|
74
74
|
email: createTextField({ required: true, personal: "tenant", find: "none" }),
|
|
75
75
|
iban: createTextField({ required: true, encrypted: true }),
|
|
76
76
|
},
|
|
@@ -84,7 +84,7 @@ const ownedContactTable = buildEntityTable("ownedContact", ownedContactEntity);
|
|
|
84
84
|
const unrestrictedContactEntity = createEntity({
|
|
85
85
|
table: "el_unrestricted_contacts",
|
|
86
86
|
fields: {
|
|
87
|
-
name: createTextField({ required: true }),
|
|
87
|
+
name: createTextField({ required: true, personal: false, reason: "test_fixture" }),
|
|
88
88
|
email: createTextField({ required: true, personal: "tenant", find: "none" }),
|
|
89
89
|
},
|
|
90
90
|
access: { read: { admin: "all", member: "all" } },
|
|
@@ -218,7 +218,7 @@ describe("collectReferenceFields", () => {
|
|
|
218
218
|
const e = createEntity({
|
|
219
219
|
table: "x",
|
|
220
220
|
fields: {
|
|
221
|
-
title: createTextField(),
|
|
221
|
+
title: createTextField({ personal: false, reason: "test_fixture" }),
|
|
222
222
|
author: { type: "reference", entity: "users:user" },
|
|
223
223
|
tags: { type: "reference", entity: "tag", multiple: true },
|
|
224
224
|
},
|
|
@@ -7,7 +7,10 @@ import { entityTableFromRegistry } from "../entity-table-from-registry";
|
|
|
7
7
|
import { buildEntityTable } from "../table-builder";
|
|
8
8
|
|
|
9
9
|
function unitEntity() {
|
|
10
|
-
return createEntity({
|
|
10
|
+
return createEntity({
|
|
11
|
+
table: "read_units",
|
|
12
|
+
fields: { name: createTextField({ personal: false, reason: "test_fixture" }) },
|
|
13
|
+
});
|
|
11
14
|
}
|
|
12
15
|
|
|
13
16
|
describe("entityTableFromRegistry", () => {
|
|
@@ -50,7 +53,10 @@ describe("entityTableFromRegistry", () => {
|
|
|
50
53
|
}),
|
|
51
54
|
]);
|
|
52
55
|
|
|
53
|
-
const other = createEntity({
|
|
56
|
+
const other = createEntity({
|
|
57
|
+
table: "read_tenants",
|
|
58
|
+
fields: { name: createTextField({ personal: false, reason: "test_fixture" }) },
|
|
59
|
+
});
|
|
54
60
|
const derived = entityTableFromRegistry(registry, "tenant", other);
|
|
55
61
|
|
|
56
62
|
expect(extractTableName(derived)).toBe("read_tenants");
|
|
@@ -14,7 +14,7 @@ import { diffSnapshots, snapshotFromMetas } from "../migrate-generator";
|
|
|
14
14
|
const entity = createEntity({
|
|
15
15
|
table: "source-probe",
|
|
16
16
|
fields: {
|
|
17
|
-
userId: createTextField({ required: true }),
|
|
17
|
+
userId: createTextField({ required: true, personal: false, reason: "test_fixture" }),
|
|
18
18
|
ip: createTextField({
|
|
19
19
|
personal: { of: "userId" },
|
|
20
20
|
find: "none",
|
|
@@ -61,7 +61,9 @@ describe("unmanaged builders reject read_ prefix (#1208)", () => {
|
|
|
61
61
|
test("deriveEntityTableMeta(..., { source: unmanaged }) with read_ table throws", () => {
|
|
62
62
|
const readEntity = createEntity({
|
|
63
63
|
table: "read_source_probe",
|
|
64
|
-
fields: {
|
|
64
|
+
fields: {
|
|
65
|
+
userId: createTextField({ required: true, personal: false, reason: "test_fixture" }),
|
|
66
|
+
},
|
|
65
67
|
});
|
|
66
68
|
expect(() =>
|
|
67
69
|
deriveEntityTableMeta("source-probe", readEntity, { source: "unmanaged" }),
|
|
@@ -70,7 +72,9 @@ describe("unmanaged builders reject read_ prefix (#1208)", () => {
|
|
|
70
72
|
|
|
71
73
|
test("default toTableName (read_*) + unmanaged throws", () => {
|
|
72
74
|
const noTable = createEntity({
|
|
73
|
-
fields: {
|
|
75
|
+
fields: {
|
|
76
|
+
userId: createTextField({ required: true, personal: false, reason: "test_fixture" }),
|
|
77
|
+
},
|
|
74
78
|
});
|
|
75
79
|
expect(() => deriveEntityTableMeta("source-probe", noTable, { source: "unmanaged" })).toThrow(
|
|
76
80
|
/the "read_" prefix is reserved/,
|
|
@@ -28,7 +28,7 @@ describe("EntityTable<E> — Property-Names existieren", () => {
|
|
|
28
28
|
const sampleEntity = createEntity({
|
|
29
29
|
table: "x",
|
|
30
30
|
fields: {
|
|
31
|
-
title: createTextField({ required: true }),
|
|
31
|
+
title: createTextField({ required: true, personal: false, reason: "test_fixture" }),
|
|
32
32
|
done: createBooleanField({ default: false }),
|
|
33
33
|
priority: createSelectField({ options: ["low", "high"] as const }),
|
|
34
34
|
},
|
|
@@ -119,7 +119,7 @@ describe("EntityTable<E> — verschiedene Feld-Typen existieren", () => {
|
|
|
119
119
|
const ent = createEntity({
|
|
120
120
|
table: "many",
|
|
121
121
|
fields: {
|
|
122
|
-
txt: createTextField(),
|
|
122
|
+
txt: createTextField({ personal: false, reason: "test_fixture" }),
|
|
123
123
|
num: createNumberField(),
|
|
124
124
|
dt: createDateField(),
|
|
125
125
|
ts: createTimestampField(),
|
|
@@ -142,12 +142,12 @@ describe("EntityTable<E> — verschiedene Feld-Typen existieren", () => {
|
|
|
142
142
|
describe("EntityTable<E> — idType wirkt", () => {
|
|
143
143
|
const uuidEnt = createEntity({
|
|
144
144
|
table: "uuid_ent",
|
|
145
|
-
fields: { name: createTextField() },
|
|
145
|
+
fields: { name: createTextField({ personal: false, reason: "test_fixture" }) },
|
|
146
146
|
// default: idType: "uuid"
|
|
147
147
|
});
|
|
148
148
|
const serialEnt = createEntity({
|
|
149
149
|
table: "serial_ent",
|
|
150
|
-
fields: { name: createTextField() },
|
|
150
|
+
fields: { name: createTextField({ personal: false, reason: "test_fixture" }) },
|
|
151
151
|
idType: "serial",
|
|
152
152
|
});
|
|
153
153
|
const tu = buildEntityTable("uuid_ent", uuidEnt);
|
|
@@ -26,7 +26,12 @@ import { createTenantDb, type TenantDb } from "../tenant-db";
|
|
|
26
26
|
const entity = createEntity({
|
|
27
27
|
table: "read_pager_items",
|
|
28
28
|
fields: {
|
|
29
|
-
title: createTextField({
|
|
29
|
+
title: createTextField({
|
|
30
|
+
required: true,
|
|
31
|
+
sortable: true,
|
|
32
|
+
personal: false,
|
|
33
|
+
reason: "test_fixture",
|
|
34
|
+
}),
|
|
30
35
|
rank: createNumberField({ sortable: true }),
|
|
31
36
|
dueDate: createDateField({ sortable: true }),
|
|
32
37
|
},
|
|
@@ -551,7 +556,9 @@ describe("event-store-executor.list — runtime SearchAdapter (Tier 2.7e Audit-F
|
|
|
551
556
|
const sysEntity = createEntity({
|
|
552
557
|
table: "read_pager_sys",
|
|
553
558
|
systemStream: true,
|
|
554
|
-
fields: {
|
|
559
|
+
fields: {
|
|
560
|
+
title: createTextField({ required: true, personal: false, reason: "test_fixture" }),
|
|
561
|
+
},
|
|
555
562
|
});
|
|
556
563
|
const sysTable = buildEntityTable("pagerSys", sysEntity);
|
|
557
564
|
await unsafeCreateEntityTable(testDb.db, sysEntity, "pagerSys");
|