@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
|
@@ -43,8 +43,8 @@ import {
|
|
|
43
43
|
const itemEntity = createEntity({
|
|
44
44
|
table: "read_pending_items",
|
|
45
45
|
fields: {
|
|
46
|
-
groupId: createTextField({ required: true }),
|
|
47
|
-
name: createTextField({ required: true }),
|
|
46
|
+
groupId: createTextField({ personal: false, reason: "test_fixture", required: true }),
|
|
47
|
+
name: createTextField({ personal: false, reason: "test_fixture", required: true }),
|
|
48
48
|
},
|
|
49
49
|
});
|
|
50
50
|
const itemTable = buildEntityTable("pending-item", itemEntity);
|
|
@@ -25,7 +25,7 @@ import {
|
|
|
25
25
|
|
|
26
26
|
const itemEntity = createEntity({
|
|
27
27
|
table: "read_arch_items",
|
|
28
|
-
fields: { label: createTextField({ required: true }) },
|
|
28
|
+
fields: { label: createTextField({ personal: false, reason: "test_fixture", required: true }) },
|
|
29
29
|
});
|
|
30
30
|
const itemTable = buildEntityTable("arch-item", itemEntity);
|
|
31
31
|
|
|
@@ -43,39 +43,54 @@ const admin = TestUsers.admin;
|
|
|
43
43
|
|
|
44
44
|
const departmentEntity = createEntity({
|
|
45
45
|
table: "cascade_departments",
|
|
46
|
-
fields: { name: createTextField() },
|
|
46
|
+
fields: { name: createTextField({ personal: false, reason: "test_fixture" }) },
|
|
47
47
|
});
|
|
48
48
|
const userEntity = createEntity({
|
|
49
49
|
table: "cascade_users",
|
|
50
|
-
fields: {
|
|
50
|
+
fields: {
|
|
51
|
+
name: createTextField({ personal: false, reason: "test_fixture" }),
|
|
52
|
+
departmentId: createTextField({ personal: false, reason: "test_fixture" }),
|
|
53
|
+
},
|
|
51
54
|
});
|
|
52
55
|
const sessionEntity = createEntity({
|
|
53
56
|
table: "cascade_sessions",
|
|
54
|
-
fields: {
|
|
57
|
+
fields: {
|
|
58
|
+
userId: createTextField({ personal: false, reason: "test_fixture" }),
|
|
59
|
+
token: createTextField({ personal: false, reason: "test_fixture" }),
|
|
60
|
+
},
|
|
55
61
|
});
|
|
56
62
|
const groupEntity = createEntity({
|
|
57
63
|
table: "cascade_groups",
|
|
58
|
-
fields: { name: createTextField() },
|
|
64
|
+
fields: { name: createTextField({ personal: false, reason: "test_fixture" }) },
|
|
59
65
|
});
|
|
60
66
|
// Two separate junction tables so one Registry can host both onDelete
|
|
61
67
|
// strategies (restrict + cascade) on the same user→group pair.
|
|
62
68
|
const userGroupRestrictEntity = createEntity({
|
|
63
69
|
table: "cascade_user_group_restrict",
|
|
64
|
-
fields: {
|
|
70
|
+
fields: {
|
|
71
|
+
userId: createTextField({ personal: false, reason: "test_fixture" }),
|
|
72
|
+
groupId: createTextField({ personal: false, reason: "test_fixture" }),
|
|
73
|
+
},
|
|
65
74
|
});
|
|
66
75
|
const userGroupCascadeEntity = createEntity({
|
|
67
76
|
table: "cascade_user_group_cascade",
|
|
68
|
-
fields: {
|
|
77
|
+
fields: {
|
|
78
|
+
userId: createTextField({ personal: false, reason: "test_fixture" }),
|
|
79
|
+
groupId: createTextField({ personal: false, reason: "test_fixture" }),
|
|
80
|
+
},
|
|
69
81
|
});
|
|
70
82
|
// setNull pair: team→member with onDelete "setNull" — members survive
|
|
71
83
|
// the team deletion with teamId nulled out.
|
|
72
84
|
const teamEntity = createEntity({
|
|
73
85
|
table: "cascade_teams",
|
|
74
|
-
fields: { name: createTextField() },
|
|
86
|
+
fields: { name: createTextField({ personal: false, reason: "test_fixture" }) },
|
|
75
87
|
});
|
|
76
88
|
const memberEntity = createEntity({
|
|
77
89
|
table: "cascade_members",
|
|
78
|
-
fields: {
|
|
90
|
+
fields: {
|
|
91
|
+
name: createTextField({ personal: false, reason: "test_fixture" }),
|
|
92
|
+
teamId: createTextField({ personal: false, reason: "test_fixture" }),
|
|
93
|
+
},
|
|
79
94
|
});
|
|
80
95
|
|
|
81
96
|
beforeAll(async () => {
|
|
@@ -5,10 +5,25 @@ describe("getIncomingRelations", () => {
|
|
|
5
5
|
const feature = defineFeature("core", (r) => {
|
|
6
6
|
r.entity(
|
|
7
7
|
"department",
|
|
8
|
-
createEntity({
|
|
8
|
+
createEntity({
|
|
9
|
+
table: "Departments",
|
|
10
|
+
fields: { name: createTextField({ personal: false, reason: "test_fixture" }) },
|
|
11
|
+
}),
|
|
12
|
+
);
|
|
13
|
+
r.entity(
|
|
14
|
+
"user",
|
|
15
|
+
createEntity({
|
|
16
|
+
table: "Users",
|
|
17
|
+
fields: { departmentId: createTextField({ personal: false, reason: "test_fixture" }) },
|
|
18
|
+
}),
|
|
19
|
+
);
|
|
20
|
+
r.entity(
|
|
21
|
+
"session",
|
|
22
|
+
createEntity({
|
|
23
|
+
table: "Sessions",
|
|
24
|
+
fields: { userId: createTextField({ personal: false, reason: "test_fixture" }) },
|
|
25
|
+
}),
|
|
9
26
|
);
|
|
10
|
-
r.entity("user", createEntity({ table: "Users", fields: { departmentId: createTextField() } }));
|
|
11
|
-
r.entity("session", createEntity({ table: "Sessions", fields: { userId: createTextField() } }));
|
|
12
27
|
|
|
13
28
|
r.relation("department", "users", {
|
|
14
29
|
type: "hasMany",
|
|
@@ -26,7 +26,7 @@ import { setupTestStack, type TestStack, TestUsers, unsafeCreateEntityTable } fr
|
|
|
26
26
|
const bagEntity = createEntity({
|
|
27
27
|
table: "ctx_bags",
|
|
28
28
|
fields: {
|
|
29
|
-
label: createTextField({ required: true }),
|
|
29
|
+
label: createTextField({ personal: false, reason: "test_fixture", required: true }),
|
|
30
30
|
counter: createNumberField({ default: 0 }),
|
|
31
31
|
},
|
|
32
32
|
});
|
|
@@ -37,8 +37,10 @@ const bagTable = buildEntityTable("bag", bagEntity);
|
|
|
37
37
|
const secretEntity = createEntity({
|
|
38
38
|
table: "ctx_secrets",
|
|
39
39
|
fields: {
|
|
40
|
-
owner: createTextField({ required: true }),
|
|
40
|
+
owner: createTextField({ personal: false, reason: "test_fixture", required: true }),
|
|
41
41
|
token: createTextField({
|
|
42
|
+
personal: false,
|
|
43
|
+
reason: "test_fixture",
|
|
42
44
|
required: true,
|
|
43
45
|
access: { read: access.privileged, write: access.privileged },
|
|
44
46
|
}),
|
|
@@ -53,7 +55,7 @@ const secretTable = buildEntityTable("secret", secretEntity);
|
|
|
53
55
|
const echoEntity = createEntity({
|
|
54
56
|
table: "ctx_echoes",
|
|
55
57
|
fields: {
|
|
56
|
-
bagId: createTextField({ required: true }),
|
|
58
|
+
bagId: createTextField({ personal: false, reason: "test_fixture", required: true }),
|
|
57
59
|
},
|
|
58
60
|
});
|
|
59
61
|
const echoTable = buildEntityTable("echo", echoEntity);
|
|
@@ -11,7 +11,13 @@ import { createDispatcher } from "../dispatcher";
|
|
|
11
11
|
const streamCleanupState = { closed: false };
|
|
12
12
|
|
|
13
13
|
const echoFeature = defineFeature("echo", (r) => {
|
|
14
|
-
r.entity(
|
|
14
|
+
r.entity(
|
|
15
|
+
"item",
|
|
16
|
+
createEntity({
|
|
17
|
+
table: "Items",
|
|
18
|
+
fields: { name: createTextField({ personal: false, reason: "test_fixture" }) },
|
|
19
|
+
}),
|
|
20
|
+
);
|
|
15
21
|
|
|
16
22
|
r.writeHandler(
|
|
17
23
|
"item:create",
|
|
@@ -119,7 +125,13 @@ describe("dispatcher.write", () => {
|
|
|
119
125
|
// it must SKIP the rate-limit — not throw "no RateLimitResolver is
|
|
120
126
|
// configured". (The HTTP path still has the resolver for real anon writes.)
|
|
121
127
|
const rlFeature = defineFeature("rl", (r) => {
|
|
122
|
-
r.entity(
|
|
128
|
+
r.entity(
|
|
129
|
+
"item",
|
|
130
|
+
createEntity({
|
|
131
|
+
table: "Items",
|
|
132
|
+
fields: { name: createTextField({ personal: false, reason: "test_fixture" }) },
|
|
133
|
+
}),
|
|
134
|
+
);
|
|
123
135
|
r.writeHandler(
|
|
124
136
|
"item:create",
|
|
125
137
|
z.object({ name: z.string() }),
|
|
@@ -144,7 +156,13 @@ describe("dispatcher.write", () => {
|
|
|
144
156
|
// rate-limiting feature. User buckets cannot skip (unlike ip+no-IP), so we
|
|
145
157
|
// fail loud at first write instead of silently running uncapped.
|
|
146
158
|
const rlFeature = defineFeature("rl-user", (r) => {
|
|
147
|
-
r.entity(
|
|
159
|
+
r.entity(
|
|
160
|
+
"item",
|
|
161
|
+
createEntity({
|
|
162
|
+
table: "Items",
|
|
163
|
+
fields: { name: createTextField({ personal: false, reason: "test_fixture" }) },
|
|
164
|
+
}),
|
|
165
|
+
);
|
|
148
166
|
r.writeHandler(
|
|
149
167
|
"item:create",
|
|
150
168
|
z.object({ name: z.string() }),
|
|
@@ -174,7 +192,13 @@ describe("dispatcher.write", () => {
|
|
|
174
192
|
// gegen denselben SessionUser — sonst ist's nicht der gleiche.
|
|
175
193
|
const captured: { fromEvent?: unknown; fromCtx?: unknown } = {};
|
|
176
194
|
const aliasFeature = defineFeature("alias", (r) => {
|
|
177
|
-
r.entity(
|
|
195
|
+
r.entity(
|
|
196
|
+
"item",
|
|
197
|
+
createEntity({
|
|
198
|
+
table: "Items",
|
|
199
|
+
fields: { name: createTextField({ personal: false, reason: "test_fixture" }) },
|
|
200
|
+
}),
|
|
201
|
+
);
|
|
178
202
|
r.writeHandler(
|
|
179
203
|
"item:create",
|
|
180
204
|
z.object({ name: z.string() }),
|
|
@@ -676,7 +700,13 @@ describe("dispatcher feature-gate", () => {
|
|
|
676
700
|
function toggled() {
|
|
677
701
|
return defineFeature("toggled", (r) => {
|
|
678
702
|
r.toggleable({ default: true });
|
|
679
|
-
r.entity(
|
|
703
|
+
r.entity(
|
|
704
|
+
"widget",
|
|
705
|
+
createEntity({
|
|
706
|
+
table: "Widgets",
|
|
707
|
+
fields: { name: createTextField({ personal: false, reason: "test_fixture" }) },
|
|
708
|
+
}),
|
|
709
|
+
);
|
|
680
710
|
r.queryHandler("widget:list", z.object({}).passthrough(), async () => ({ items: [] }), {
|
|
681
711
|
access: { openToAll: true },
|
|
682
712
|
});
|
|
@@ -941,7 +971,13 @@ describe("write-handler shape guard", () => {
|
|
|
941
971
|
|
|
942
972
|
function brokenFeature() {
|
|
943
973
|
return defineFeature("broken", (r) => {
|
|
944
|
-
r.entity(
|
|
974
|
+
r.entity(
|
|
975
|
+
"item",
|
|
976
|
+
createEntity({
|
|
977
|
+
table: "Items",
|
|
978
|
+
fields: { name: createTextField({ personal: false, reason: "test_fixture" }) },
|
|
979
|
+
}),
|
|
980
|
+
);
|
|
945
981
|
r.writeHandler(
|
|
946
982
|
"item:create",
|
|
947
983
|
z.object({ name: z.string() }),
|
|
@@ -35,8 +35,8 @@ import {
|
|
|
35
35
|
const shipmentEntity = createEntity({
|
|
36
36
|
table: "read_domain_shipments",
|
|
37
37
|
fields: {
|
|
38
|
-
cargo: createTextField({ required: true }),
|
|
39
|
-
status: createTextField({ required: true }),
|
|
38
|
+
cargo: createTextField({ personal: false, reason: "test_fixture", required: true }),
|
|
39
|
+
status: createTextField({ personal: false, reason: "test_fixture", required: true }),
|
|
40
40
|
},
|
|
41
41
|
});
|
|
42
42
|
|
|
@@ -22,7 +22,7 @@ import { setupTestStack, type TestStack, TestUsers, unsafeCreateEntityTable } fr
|
|
|
22
22
|
const cartEntity = createEntity({
|
|
23
23
|
table: "read_f4w_carts",
|
|
24
24
|
fields: {
|
|
25
|
-
customer: createTextField({ required: true }),
|
|
25
|
+
customer: createTextField({ personal: false, reason: "test_fixture", required: true }),
|
|
26
26
|
},
|
|
27
27
|
});
|
|
28
28
|
|
|
@@ -15,7 +15,13 @@ import { buildEventId, createLifecycleHooks, type SystemHooks } from "../lifecyc
|
|
|
15
15
|
|
|
16
16
|
function makeRegistry(hooks?: { preSave?: PreSaveHookFn[]; postSave?: PostSaveHookFn[] }) {
|
|
17
17
|
const feature = defineFeature("test", (r) => {
|
|
18
|
-
r.entity(
|
|
18
|
+
r.entity(
|
|
19
|
+
"user",
|
|
20
|
+
createEntity({
|
|
21
|
+
table: "Users",
|
|
22
|
+
fields: { email: createTextField({ personal: false, reason: "test_fixture" }) },
|
|
23
|
+
}),
|
|
24
|
+
);
|
|
19
25
|
// Dummy handler so hook targets resolve (boot validation requires it)
|
|
20
26
|
r.writeHandler("user", z.object({}), async () => ({ isSuccess: true as const, data: null }), {
|
|
21
27
|
access: { openToAll: true },
|
|
@@ -422,7 +428,13 @@ describe("Sprint 8a: per-tenant entity-hook filter", () => {
|
|
|
422
428
|
const calls: Array<{ tenant: string }> = [];
|
|
423
429
|
|
|
424
430
|
const featureA = defineFeature("feat-a", (r) => {
|
|
425
|
-
r.entity(
|
|
431
|
+
r.entity(
|
|
432
|
+
"widget",
|
|
433
|
+
createEntity({
|
|
434
|
+
table: "Widgets",
|
|
435
|
+
fields: { name: createTextField({ personal: false, reason: "test_fixture" }) },
|
|
436
|
+
}),
|
|
437
|
+
);
|
|
426
438
|
r.writeHandler(
|
|
427
439
|
"widget:create",
|
|
428
440
|
z.object({ name: z.string() }),
|
|
@@ -550,7 +562,13 @@ describe("runPreDelete", () => {
|
|
|
550
562
|
test("runs feature + entity + system hooks, all inTransaction (throw on error)", async () => {
|
|
551
563
|
const calls: string[] = [];
|
|
552
564
|
const feature = defineFeature("test", (r) => {
|
|
553
|
-
r.entity(
|
|
565
|
+
r.entity(
|
|
566
|
+
"user",
|
|
567
|
+
createEntity({
|
|
568
|
+
table: "Users",
|
|
569
|
+
fields: { email: createTextField({ personal: false, reason: "test_fixture" }) },
|
|
570
|
+
}),
|
|
571
|
+
);
|
|
554
572
|
r.writeHandler("user", z.object({}), async () => ({ isSuccess: true as const, data: null }), {
|
|
555
573
|
access: { openToAll: true },
|
|
556
574
|
});
|
|
@@ -580,7 +598,13 @@ describe("runPreDelete", () => {
|
|
|
580
598
|
|
|
581
599
|
test("a hook throwing aborts the delete (rejects, not swallowed)", async () => {
|
|
582
600
|
const feature = defineFeature("test", (r) => {
|
|
583
|
-
r.entity(
|
|
601
|
+
r.entity(
|
|
602
|
+
"user",
|
|
603
|
+
createEntity({
|
|
604
|
+
table: "Users",
|
|
605
|
+
fields: { email: createTextField({ personal: false, reason: "test_fixture" }) },
|
|
606
|
+
}),
|
|
607
|
+
);
|
|
584
608
|
r.writeHandler("user", z.object({}), async () => ({ isSuccess: true as const, data: null }), {
|
|
585
609
|
access: { openToAll: true },
|
|
586
610
|
});
|
|
@@ -620,7 +644,13 @@ describe("runPostDelete", () => {
|
|
|
620
644
|
test("runs feature then system hooks (best-effort by default phase)", async () => {
|
|
621
645
|
const calls: string[] = [];
|
|
622
646
|
const feature = defineFeature("test", (r) => {
|
|
623
|
-
r.entity(
|
|
647
|
+
r.entity(
|
|
648
|
+
"user",
|
|
649
|
+
createEntity({
|
|
650
|
+
table: "Users",
|
|
651
|
+
fields: { email: createTextField({ personal: false, reason: "test_fixture" }) },
|
|
652
|
+
}),
|
|
653
|
+
);
|
|
624
654
|
r.writeHandler("user", z.object({}), async () => ({ isSuccess: true as const, data: null }), {
|
|
625
655
|
access: { openToAll: true },
|
|
626
656
|
});
|
|
@@ -647,7 +677,13 @@ describe("runPostDelete", () => {
|
|
|
647
677
|
|
|
648
678
|
test("inTransaction phase: hook errors throw", async () => {
|
|
649
679
|
const feature = defineFeature("test", (r) => {
|
|
650
|
-
r.entity(
|
|
680
|
+
r.entity(
|
|
681
|
+
"user",
|
|
682
|
+
createEntity({
|
|
683
|
+
table: "Users",
|
|
684
|
+
fields: { email: createTextField({ personal: false, reason: "test_fixture" }) },
|
|
685
|
+
}),
|
|
686
|
+
);
|
|
651
687
|
r.writeHandler("user", z.object({}), async () => ({ isSuccess: true as const, data: null }), {
|
|
652
688
|
access: { openToAll: true },
|
|
653
689
|
});
|
|
@@ -29,8 +29,8 @@ import {
|
|
|
29
29
|
const invoiceEntity = createEntity({
|
|
30
30
|
table: "read_asof_invoices",
|
|
31
31
|
fields: {
|
|
32
|
-
customer: createTextField({ required: true }),
|
|
33
|
-
status: createTextField({ required: true }),
|
|
32
|
+
customer: createTextField({ personal: false, reason: "test_fixture", required: true }),
|
|
33
|
+
status: createTextField({ personal: false, reason: "test_fixture", required: true }),
|
|
34
34
|
},
|
|
35
35
|
});
|
|
36
36
|
const invoiceTable = buildEntityTable("asof-invoice", invoiceEntity);
|
|
@@ -40,13 +40,17 @@ import {
|
|
|
40
40
|
|
|
41
41
|
const invoiceEntity = createEntity({
|
|
42
42
|
table: "read_mspreb_invoices",
|
|
43
|
-
fields: {
|
|
43
|
+
fields: {
|
|
44
|
+
customer: createTextField({ personal: false, reason: "test_fixture", required: true }),
|
|
45
|
+
},
|
|
44
46
|
});
|
|
45
47
|
const invoiceTable = buildEntityTable("msp-reb-invoice", invoiceEntity);
|
|
46
48
|
|
|
47
49
|
const paymentEntity = createEntity({
|
|
48
50
|
table: "read_mspreb_payments",
|
|
49
|
-
fields: {
|
|
51
|
+
fields: {
|
|
52
|
+
customer: createTextField({ personal: false, reason: "test_fixture", required: true }),
|
|
53
|
+
},
|
|
50
54
|
});
|
|
51
55
|
const paymentTable = buildEntityTable("msp-reb-payment", paymentEntity);
|
|
52
56
|
|
|
@@ -26,13 +26,17 @@ import {
|
|
|
26
26
|
|
|
27
27
|
const shipmentEntity = createEntity({
|
|
28
28
|
table: "read_msp_shipments",
|
|
29
|
-
fields: {
|
|
29
|
+
fields: {
|
|
30
|
+
customer: createTextField({ personal: false, reason: "test_fixture", required: true }),
|
|
31
|
+
},
|
|
30
32
|
});
|
|
31
33
|
const shipmentTable = buildEntityTable("msp-shipment", shipmentEntity);
|
|
32
34
|
|
|
33
35
|
const refundEntity = createEntity({
|
|
34
36
|
table: "read_msp_refunds",
|
|
35
|
-
fields: {
|
|
37
|
+
fields: {
|
|
38
|
+
customer: createTextField({ personal: false, reason: "test_fixture", required: true }),
|
|
39
|
+
},
|
|
36
40
|
});
|
|
37
41
|
const refundTable = buildEntityTable("msp-refund", refundEntity);
|
|
38
42
|
|
|
@@ -52,7 +52,7 @@ const taskCountProjection: ProjectionDefinition = {
|
|
|
52
52
|
|
|
53
53
|
const taskEntity = createEntity({
|
|
54
54
|
table: "perf_rebuild_tasks",
|
|
55
|
-
fields: { title: createTextField({ required: true }) },
|
|
55
|
+
fields: { title: createTextField({ personal: false, reason: "test_fixture", required: true }) },
|
|
56
56
|
});
|
|
57
57
|
|
|
58
58
|
const feature = defineFeature("perfrebuild", (r) => {
|
|
@@ -20,7 +20,7 @@ import { setupTestStack, type TestStack, TestUsers } from "../../stack";
|
|
|
20
20
|
const widgetEntity = createEntity({
|
|
21
21
|
table: "read_post_query_widgets",
|
|
22
22
|
fields: {
|
|
23
|
-
name: createTextField({ required: true }),
|
|
23
|
+
name: createTextField({ personal: false, reason: "test_fixture", required: true }),
|
|
24
24
|
},
|
|
25
25
|
});
|
|
26
26
|
|
|
@@ -78,11 +78,11 @@ const postQueryFeature = defineFeature("postquerytest", (r) => {
|
|
|
78
78
|
|
|
79
79
|
const gadgetEntity = createEntity({
|
|
80
80
|
table: "read_post_query_gadgets",
|
|
81
|
-
fields: { name: createTextField({ required: true }) },
|
|
81
|
+
fields: { name: createTextField({ personal: false, reason: "test_fixture", required: true }) },
|
|
82
82
|
});
|
|
83
83
|
const gizmoEntity = createEntity({
|
|
84
84
|
table: "read_post_query_gizmos",
|
|
85
|
-
fields: { name: createTextField({ required: true }) },
|
|
85
|
+
fields: { name: createTextField({ personal: false, reason: "test_fixture", required: true }) },
|
|
86
86
|
});
|
|
87
87
|
|
|
88
88
|
const dropRowHook: PostQueryHookFn = async () => ({ rows: [] });
|
|
@@ -47,8 +47,8 @@ import {
|
|
|
47
47
|
const itemEntity = createEntity({
|
|
48
48
|
table: "read_rebuild_items",
|
|
49
49
|
fields: {
|
|
50
|
-
groupId: createTextField({ required: true }),
|
|
51
|
-
name: createTextField({ required: true }),
|
|
50
|
+
groupId: createTextField({ personal: false, reason: "test_fixture", required: true }),
|
|
51
|
+
name: createTextField({ personal: false, reason: "test_fixture", required: true }),
|
|
52
52
|
},
|
|
53
53
|
softDelete: true,
|
|
54
54
|
});
|
|
@@ -586,7 +586,7 @@ describe("rebuildProjection — online shadow-swap mechanics", () => {
|
|
|
586
586
|
// list/progress tests above keep seeing exactly one registered projection.
|
|
587
587
|
const swapEntity = createEntity({
|
|
588
588
|
table: "read_swap_indexed",
|
|
589
|
-
fields: { label: createTextField({ required: true }) },
|
|
589
|
+
fields: { label: createTextField({ personal: false, reason: "test_fixture", required: true }) },
|
|
590
590
|
});
|
|
591
591
|
const swapTable = buildEntityTable("swap-indexed", swapEntity);
|
|
592
592
|
// Empty apply: a 0-event rebuild still builds the shadow + swaps it in, so
|
|
@@ -25,7 +25,7 @@ import {
|
|
|
25
25
|
|
|
26
26
|
const widgetEntity = createEntity({
|
|
27
27
|
table: "read_qp_widgets",
|
|
28
|
-
fields: { name: createTextField({ required: true }) },
|
|
28
|
+
fields: { name: createTextField({ personal: false, reason: "test_fixture", required: true }) },
|
|
29
29
|
});
|
|
30
30
|
const widgetTable = buildEntityTable("qp-widget", widgetEntity);
|
|
31
31
|
|
|
@@ -48,8 +48,8 @@ const POISON_SQL = "poison-sql";
|
|
|
48
48
|
const itemEntity = createEntity({
|
|
49
49
|
table: "read_poison_items",
|
|
50
50
|
fields: {
|
|
51
|
-
groupId: createTextField({ required: true }),
|
|
52
|
-
name: createTextField({ required: true }),
|
|
51
|
+
groupId: createTextField({ personal: false, reason: "test_fixture", required: true }),
|
|
52
|
+
name: createTextField({ personal: false, reason: "test_fixture", required: true }),
|
|
53
53
|
},
|
|
54
54
|
});
|
|
55
55
|
const itemTable = buildEntityTable("poison-item", itemEntity);
|
|
@@ -18,7 +18,13 @@ import { SEARCH_CONSUMER_NAME } from "../system-hooks";
|
|
|
18
18
|
const noteEntity = createEntity({
|
|
19
19
|
table: "read_named_search_notes",
|
|
20
20
|
fields: {
|
|
21
|
-
label: createTextField({
|
|
21
|
+
label: createTextField({
|
|
22
|
+
personal: false,
|
|
23
|
+
reason: "test_fixture",
|
|
24
|
+
required: true,
|
|
25
|
+
maxLength: 100,
|
|
26
|
+
searchable: true,
|
|
27
|
+
}),
|
|
22
28
|
},
|
|
23
29
|
softDelete: true,
|
|
24
30
|
});
|
|
@@ -29,7 +35,12 @@ const noteTable = buildEntityTable("note", noteEntity);
|
|
|
29
35
|
const ghostEntity = createEntity({
|
|
30
36
|
table: "read_named_search_ghosts",
|
|
31
37
|
fields: {
|
|
32
|
-
note: createTextField({
|
|
38
|
+
note: createTextField({
|
|
39
|
+
personal: false,
|
|
40
|
+
reason: "test_fixture",
|
|
41
|
+
required: true,
|
|
42
|
+
maxLength: 50,
|
|
43
|
+
}),
|
|
33
44
|
},
|
|
34
45
|
});
|
|
35
46
|
|
|
@@ -37,7 +37,7 @@ const TAE_AGGREGATE_TYPE = "taeDoc";
|
|
|
37
37
|
const markerEntity = createEntity({
|
|
38
38
|
table: "tae_markers",
|
|
39
39
|
fields: {
|
|
40
|
-
note: createTextField({ required: true }),
|
|
40
|
+
note: createTextField({ personal: false, reason: "test_fixture", required: true }),
|
|
41
41
|
},
|
|
42
42
|
});
|
|
43
43
|
const markerTable = buildEntityTable("taeMarker", markerEntity);
|
|
@@ -31,7 +31,12 @@ const widgetEntity = createEntity({
|
|
|
31
31
|
table: "read_reindex_widgets",
|
|
32
32
|
softDelete: true,
|
|
33
33
|
fields: {
|
|
34
|
-
name: createTextField({
|
|
34
|
+
name: createTextField({
|
|
35
|
+
personal: false,
|
|
36
|
+
reason: "test_fixture",
|
|
37
|
+
required: true,
|
|
38
|
+
searchable: true,
|
|
39
|
+
}),
|
|
35
40
|
},
|
|
36
41
|
});
|
|
37
42
|
|
|
@@ -20,7 +20,13 @@ const contactEntity = createEntity({
|
|
|
20
20
|
fields: {
|
|
21
21
|
// personal: "self" → subject = entity id. find: "fuzzy" → searchable via derived index.
|
|
22
22
|
label: createTextField({ required: true, maxLength: 100, personal: "self", find: "fuzzy" }),
|
|
23
|
-
note: createTextField({
|
|
23
|
+
note: createTextField({
|
|
24
|
+
personal: false,
|
|
25
|
+
reason: "test_fixture",
|
|
26
|
+
required: true,
|
|
27
|
+
maxLength: 100,
|
|
28
|
+
searchable: true,
|
|
29
|
+
}),
|
|
24
30
|
},
|
|
25
31
|
});
|
|
26
32
|
|
|
@@ -38,7 +38,7 @@ function memoEntity(access: Parameters<typeof createEntity>[0]["access"]) {
|
|
|
38
38
|
table: "fwbootguard_memos",
|
|
39
39
|
fields: {
|
|
40
40
|
ownerId: createTextField({ required: true }),
|
|
41
|
-
title: createTextField({ required: true }),
|
|
41
|
+
title: createTextField({ personal: false, reason: "test_fixture", required: true }),
|
|
42
42
|
},
|
|
43
43
|
...(access ? { access } : {}),
|
|
44
44
|
});
|
|
@@ -16,7 +16,12 @@ import { generateE2ESpec, generateZodFixture } from "../e2e-generator";
|
|
|
16
16
|
const taskEntity = createEntity({
|
|
17
17
|
table: "tasks",
|
|
18
18
|
fields: {
|
|
19
|
-
title: createTextField({
|
|
19
|
+
title: createTextField({
|
|
20
|
+
personal: false,
|
|
21
|
+
reason: "test_fixture",
|
|
22
|
+
required: true,
|
|
23
|
+
maxLength: 200,
|
|
24
|
+
}),
|
|
20
25
|
done: createBooleanField({ default: false }),
|
|
21
26
|
status: createSelectField({ options: ["todo", "doing", "done"] as const }),
|
|
22
27
|
},
|
|
@@ -92,7 +97,7 @@ describe("generateE2ESpec", () => {
|
|
|
92
97
|
const entity = createEntity({
|
|
93
98
|
table: "events",
|
|
94
99
|
fields: {
|
|
95
|
-
title: createTextField({ required: true }),
|
|
100
|
+
title: createTextField({ personal: false, reason: "test_fixture", required: true }),
|
|
96
101
|
day: createDateField(),
|
|
97
102
|
at: createTimestampField(),
|
|
98
103
|
},
|
|
@@ -180,9 +185,14 @@ describe("generateE2ESpec", () => {
|
|
|
180
185
|
const contactEntity = createEntity({
|
|
181
186
|
table: "contacts",
|
|
182
187
|
fields: {
|
|
183
|
-
name: createTextField({ required: true }),
|
|
184
|
-
email: createTextField({
|
|
185
|
-
|
|
188
|
+
name: createTextField({ personal: false, reason: "test_fixture", required: true }),
|
|
189
|
+
email: createTextField({
|
|
190
|
+
personal: false,
|
|
191
|
+
reason: "test_fixture",
|
|
192
|
+
required: true,
|
|
193
|
+
format: "email",
|
|
194
|
+
}),
|
|
195
|
+
homepage: createTextField({ personal: false, reason: "test_fixture", format: "url" }),
|
|
186
196
|
},
|
|
187
197
|
});
|
|
188
198
|
const feature = defineFeature("contacts", (r) => {
|
|
@@ -17,7 +17,9 @@ import {
|
|
|
17
17
|
// Used by every pipeline test that only needs SOMETHING to write events
|
|
18
18
|
// against (event-dispatcher*, event-retention, event-dedup, …).
|
|
19
19
|
export const sharedWidgetEntity = createEntity({
|
|
20
|
-
fields: {
|
|
20
|
+
fields: {
|
|
21
|
+
name: createTextField({ required: true, personal: false, reason: "test_fixture" }),
|
|
22
|
+
},
|
|
21
23
|
softDelete: true,
|
|
22
24
|
});
|
|
23
25
|
export const sharedWidgetTable = buildEntityTable("widget", sharedWidgetEntity);
|
|
@@ -55,7 +57,7 @@ export const sharedUserTable = buildEntityTable("user", sharedUserEntity);
|
|
|
55
57
|
// projection-rebuild — tests that need "a thing you can CRUD".
|
|
56
58
|
export const sharedItemEntity = createEntity({
|
|
57
59
|
fields: {
|
|
58
|
-
name: createTextField({ required: true }),
|
|
60
|
+
name: createTextField({ required: true, personal: false, reason: "test_fixture" }),
|
|
59
61
|
price: createNumberField(),
|
|
60
62
|
},
|
|
61
63
|
softDelete: true,
|
package/src/ui-types/index.ts
CHANGED
|
@@ -66,8 +66,10 @@ export type {
|
|
|
66
66
|
DashboardFilterDefinition,
|
|
67
67
|
DashboardListPanel,
|
|
68
68
|
DashboardPanelDefinition,
|
|
69
|
+
DashboardPanelVisibility,
|
|
69
70
|
DashboardProgressListPanel,
|
|
70
71
|
DashboardScreenDefinition,
|
|
72
|
+
DashboardScreenPanel,
|
|
71
73
|
DashboardStatGroupPanel,
|
|
72
74
|
DashboardStatPanel,
|
|
73
75
|
EditExtensionSection,
|