@cosmicdrift/kumiko-bundled-features 0.1.0 → 0.2.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/LICENSE +57 -0
- package/package.json +1 -1
- package/src/audit/__tests__/audit.integration.ts +2 -2
- package/src/auth-email-password/__tests__/account-lockout-no-redis.integration.ts +5 -5
- package/src/auth-email-password/__tests__/account-lockout.integration.ts +5 -5
- package/src/auth-email-password/__tests__/auth-claims.integration.ts +14 -14
- package/src/auth-email-password/__tests__/auth.integration.ts +8 -8
- package/src/auth-email-password/__tests__/email-verification.integration.ts +5 -5
- package/src/auth-email-password/__tests__/identity-v3-login.integration.ts +5 -5
- package/src/auth-email-password/__tests__/invite-flow.integration.ts +6 -6
- package/src/auth-email-password/__tests__/multi-roles.integration.ts +5 -5
- package/src/auth-email-password/__tests__/password-reset.integration.ts +5 -5
- package/src/auth-email-password/__tests__/public-routes-rate-limit.integration.ts +5 -5
- package/src/auth-email-password/__tests__/seed-admin.integration.ts +5 -5
- package/src/auth-email-password/__tests__/session-callbacks.integration.ts +5 -5
- package/src/auth-email-password/__tests__/signup-flow.integration.ts +6 -6
- package/src/cap-counter/__tests__/cap-counter.integration.ts +2 -2
- package/src/cap-counter/__tests__/with-cap-enforcement.integration.ts +2 -2
- package/src/config/__tests__/config.integration.ts +2 -2
- package/src/delivery/__tests__/delivery-events.integration.ts +4 -4
- package/src/delivery/__tests__/delivery.integration.ts +4 -4
- package/src/feature-toggles/__tests__/feature-toggles.integration.ts +5 -5
- package/src/file-foundation/__tests__/file-foundation.integration.ts +4 -4
- package/src/jobs/__tests__/job-system-user.integration.ts +3 -3
- package/src/jobs/__tests__/jobs-events.integration.ts +2 -2
- package/src/jobs/__tests__/jobs-feature.integration.ts +3 -3
- package/src/legal-pages/__tests__/legal-pages.integration.ts +3 -3
- package/src/mail-foundation/__tests__/mail-foundation.integration.ts +4 -4
- package/src/secrets/__tests__/rotate.integration.ts +2 -2
- package/src/secrets/__tests__/secrets-events.integration.ts +2 -2
- package/src/secrets/__tests__/secrets.integration.ts +2 -2
- package/src/sessions/__tests__/cleanup.integration.ts +2 -2
- package/src/sessions/__tests__/password-auto-revoke.integration.ts +6 -6
- package/src/sessions/__tests__/sessions.integration.ts +6 -6
- package/src/tenant/__tests__/multi-tenant.integration.ts +4 -4
- package/src/tenant/__tests__/seed-testing.integration.ts +4 -4
- package/src/tenant/__tests__/tenant.integration.ts +4 -4
- package/src/tenant/seeding.ts +12 -1
- package/src/text-content/README.md +6 -2
- package/src/text-content/__tests__/text-content.integration.ts +2 -2
- package/src/tier-engine/__tests__/tier-engine.integration.ts +5 -5
- package/src/user/__tests__/seed-testing.integration.ts +4 -4
- package/src/user/__tests__/user.integration.ts +2 -2
package/LICENSE
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
Business Source License 1.1
|
|
2
|
+
|
|
3
|
+
Parameters
|
|
4
|
+
|
|
5
|
+
Licensor: Marc Frost
|
|
6
|
+
|
|
7
|
+
Licensed Work: @cosmicdrift/kumiko-framework
|
|
8
|
+
The Licensed Work is © 2026 Marc Frost.
|
|
9
|
+
|
|
10
|
+
Additional Use Grant:
|
|
11
|
+
You may use the Licensed Work in production for any purpose, including
|
|
12
|
+
commercially, EXCEPT for the Restricted Use.
|
|
13
|
+
|
|
14
|
+
"Restricted Use" is defined as using the Licensed Work to provide a platform
|
|
15
|
+
or service to third parties that allows them to host, deploy, or run their
|
|
16
|
+
own applications built with the Licensed Work. This includes, but is not
|
|
17
|
+
limited to: managed hosting services, software-as-a-service (SaaS) platforms,
|
|
18
|
+
platform-as-a-service (PaaS), developer platforms, or any multi-tenant
|
|
19
|
+
managed offering of the Licensed Work.
|
|
20
|
+
|
|
21
|
+
This restriction does not apply to the Licensor, any entity controlled by,
|
|
22
|
+
controlling, or under common control with the Licensor ("Affiliates"), or
|
|
23
|
+
contractors acting on their behalf. The Licensor remains free to use the
|
|
24
|
+
Licensed Work for any purpose, including for the operation of kumiko.so.
|
|
25
|
+
|
|
26
|
+
Change Date: 2030-05-05
|
|
27
|
+
Change License: Apache License, Version 2.0
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
Terms
|
|
31
|
+
|
|
32
|
+
The Licensor hereby grants you the right to copy, modify, create derivative works,
|
|
33
|
+
redistribute, and make non-production use of the Licensed Work. The Licensor may
|
|
34
|
+
make an Additional Use Grant, above, permitting limited production use.
|
|
35
|
+
|
|
36
|
+
Effective on the Change Date, or the fourth anniversary of the first publicly
|
|
37
|
+
available distribution of the Licensed Work under this License, whichever comes
|
|
38
|
+
first, this License will convert to the Change License.
|
|
39
|
+
|
|
40
|
+
This Business Source License governs use of the Licensed Work in all cases, except
|
|
41
|
+
as to any use that is explicitly granted in the Additional Use Grant above or
|
|
42
|
+
under the Change License after the Change Date.
|
|
43
|
+
|
|
44
|
+
If your use of the Licensed Work does not comply with the requirements of this
|
|
45
|
+
License, you must cease use of the Licensed Work immediately.
|
|
46
|
+
|
|
47
|
+
All copies of the Licensed Work, and all derivative works thereof, must include
|
|
48
|
+
this License.
|
|
49
|
+
|
|
50
|
+
This License does not grant you any right, title, or interest in any trademark,
|
|
51
|
+
logo, or branding of the Licensor, except as required to comply with this License.
|
|
52
|
+
|
|
53
|
+
TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON AN
|
|
54
|
+
“AS IS” BASIS. LICENSOR DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
|
|
55
|
+
WITHOUT LIMITATION WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE,
|
|
56
|
+
TITLE, AND NON-INFRINGEMENT. IN NO EVENT WILL LICENSOR BE LIABLE FOR ANY DAMAGES
|
|
57
|
+
ARISING OUT OF OR RELATED TO THIS LICENSE OR THE USE OF THE LICENSED WORK.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cosmicdrift/kumiko-bundled-features",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "Built-in features — tenant, user, auth, delivery. The stuff you'd rewrite anyway, already typed.",
|
|
5
5
|
"license": "BUSL-1.1",
|
|
6
6
|
"author": "Marc Frost <marc@cosmicdriftgamestudio.com>",
|
|
@@ -10,13 +10,13 @@ import {
|
|
|
10
10
|
type SessionUser,
|
|
11
11
|
} from "@cosmicdrift/kumiko-framework/engine";
|
|
12
12
|
import {
|
|
13
|
-
createEntityTable,
|
|
14
13
|
createTestUser,
|
|
15
14
|
resetEventStore,
|
|
16
15
|
setupTestStack,
|
|
17
16
|
type TestStack,
|
|
18
17
|
TestUsers,
|
|
19
18
|
testTenantId,
|
|
19
|
+
unsafeCreateEntityTable,
|
|
20
20
|
} from "@cosmicdrift/kumiko-framework/stack";
|
|
21
21
|
import { sql } from "drizzle-orm";
|
|
22
22
|
import { afterAll, beforeAll, beforeEach, describe, expect, test } from "vitest";
|
|
@@ -60,7 +60,7 @@ beforeAll(async () => {
|
|
|
60
60
|
stack = await setupTestStack({
|
|
61
61
|
features: [widgetFeature, createAuditFeature()],
|
|
62
62
|
});
|
|
63
|
-
await
|
|
63
|
+
await unsafeCreateEntityTable(stack.db, widgetEntity);
|
|
64
64
|
});
|
|
65
65
|
|
|
66
66
|
afterAll(async () => {
|
|
@@ -14,11 +14,11 @@ import { randomBytes } from "node:crypto";
|
|
|
14
14
|
import { createEncryptionProvider } from "@cosmicdrift/kumiko-framework/db";
|
|
15
15
|
import type { TenantId } from "@cosmicdrift/kumiko-framework/engine";
|
|
16
16
|
import {
|
|
17
|
-
createEntityTable,
|
|
18
|
-
pushTables,
|
|
19
17
|
setupTestStack,
|
|
20
18
|
type TestStack,
|
|
21
19
|
TestUsers,
|
|
20
|
+
unsafeCreateEntityTable,
|
|
21
|
+
unsafePushTables,
|
|
22
22
|
} from "@cosmicdrift/kumiko-framework/stack";
|
|
23
23
|
import { afterAll, beforeAll, beforeEach, describe, expect, test } from "vitest";
|
|
24
24
|
import { createConfigFeature } from "../../config";
|
|
@@ -74,9 +74,9 @@ beforeAll(async () => {
|
|
|
74
74
|
},
|
|
75
75
|
});
|
|
76
76
|
|
|
77
|
-
await
|
|
78
|
-
await
|
|
79
|
-
await
|
|
77
|
+
await unsafeCreateEntityTable(stack.db, userEntity);
|
|
78
|
+
await unsafeCreateEntityTable(stack.db, tenantEntity);
|
|
79
|
+
await unsafePushTables(stack.db, { configValuesTable, tenantMembershipsTable });
|
|
80
80
|
});
|
|
81
81
|
|
|
82
82
|
afterAll(async () => {
|
|
@@ -13,11 +13,11 @@ import { randomBytes } from "node:crypto";
|
|
|
13
13
|
import { createEncryptionProvider } from "@cosmicdrift/kumiko-framework/db";
|
|
14
14
|
import type { TenantId } from "@cosmicdrift/kumiko-framework/engine";
|
|
15
15
|
import {
|
|
16
|
-
createEntityTable,
|
|
17
|
-
pushTables,
|
|
18
16
|
setupTestStack,
|
|
19
17
|
type TestStack,
|
|
20
18
|
TestUsers,
|
|
19
|
+
unsafeCreateEntityTable,
|
|
20
|
+
unsafePushTables,
|
|
21
21
|
} from "@cosmicdrift/kumiko-framework/stack";
|
|
22
22
|
import { afterAll, beforeAll, beforeEach, describe, expect, test } from "vitest";
|
|
23
23
|
import { createConfigFeature } from "../../config";
|
|
@@ -74,9 +74,9 @@ beforeAll(async () => {
|
|
|
74
74
|
},
|
|
75
75
|
});
|
|
76
76
|
|
|
77
|
-
await
|
|
78
|
-
await
|
|
79
|
-
await
|
|
77
|
+
await unsafeCreateEntityTable(stack.db, userEntity);
|
|
78
|
+
await unsafeCreateEntityTable(stack.db, tenantEntity);
|
|
79
|
+
await unsafePushTables(stack.db, { configValuesTable, tenantMembershipsTable });
|
|
80
80
|
});
|
|
81
81
|
|
|
82
82
|
afterAll(async () => {
|
|
@@ -3,12 +3,12 @@ import { createEncryptionProvider } from "@cosmicdrift/kumiko-framework/db";
|
|
|
3
3
|
import type { TenantId } from "@cosmicdrift/kumiko-framework/engine";
|
|
4
4
|
import { defineFeature } from "@cosmicdrift/kumiko-framework/engine";
|
|
5
5
|
import {
|
|
6
|
-
createEntityTable,
|
|
7
|
-
pushTables,
|
|
8
6
|
setupTestStack,
|
|
9
7
|
type TestStack,
|
|
10
8
|
TestUsers,
|
|
11
9
|
testTenantId,
|
|
10
|
+
unsafeCreateEntityTable,
|
|
11
|
+
unsafePushTables,
|
|
12
12
|
} from "@cosmicdrift/kumiko-framework/stack";
|
|
13
13
|
import { afterAll, beforeAll, beforeEach, describe, expect, test } from "vitest";
|
|
14
14
|
import { createConfigFeature } from "../../config";
|
|
@@ -91,9 +91,9 @@ beforeAll(async () => {
|
|
|
91
91
|
},
|
|
92
92
|
});
|
|
93
93
|
|
|
94
|
-
await
|
|
95
|
-
await
|
|
96
|
-
await
|
|
94
|
+
await unsafeCreateEntityTable(stack.db, userEntity);
|
|
95
|
+
await unsafeCreateEntityTable(stack.db, tenantEntity);
|
|
96
|
+
await unsafePushTables(stack.db, { configValuesTable, tenantMembershipsTable });
|
|
97
97
|
});
|
|
98
98
|
|
|
99
99
|
afterAll(async () => {
|
|
@@ -294,9 +294,9 @@ describe("scenario 2.5: reserved separator + multi-feature isolation", () => {
|
|
|
294
294
|
},
|
|
295
295
|
});
|
|
296
296
|
try {
|
|
297
|
-
await
|
|
298
|
-
await
|
|
299
|
-
await
|
|
297
|
+
await unsafeCreateEntityTable(localStack.db, userEntity);
|
|
298
|
+
await unsafeCreateEntityTable(localStack.db, tenantEntity);
|
|
299
|
+
await unsafePushTables(localStack.db, { configValuesTable, tenantMembershipsTable });
|
|
300
300
|
|
|
301
301
|
const hash = await hashPassword("pw-long-enough");
|
|
302
302
|
const created = await localStack.http.writeOk<{ id: string }>(
|
|
@@ -386,9 +386,9 @@ describe("scenario 2.6: multi-feature drift warnings fire independently", () =>
|
|
|
386
386
|
},
|
|
387
387
|
});
|
|
388
388
|
try {
|
|
389
|
-
await
|
|
390
|
-
await
|
|
391
|
-
await
|
|
389
|
+
await unsafeCreateEntityTable(localStack.db, userEntity);
|
|
390
|
+
await unsafeCreateEntityTable(localStack.db, tenantEntity);
|
|
391
|
+
await unsafePushTables(localStack.db, { configValuesTable, tenantMembershipsTable });
|
|
392
392
|
|
|
393
393
|
const hash = await hashPassword("pw-long-enough");
|
|
394
394
|
const created = await localStack.http.writeOk<{ id: string }>(
|
|
@@ -472,9 +472,9 @@ describe("scenario 3: a broken claims hook does not break login", () => {
|
|
|
472
472
|
},
|
|
473
473
|
});
|
|
474
474
|
try {
|
|
475
|
-
await
|
|
476
|
-
await
|
|
477
|
-
await
|
|
475
|
+
await unsafeCreateEntityTable(localStack.db, userEntity);
|
|
476
|
+
await unsafeCreateEntityTable(localStack.db, tenantEntity);
|
|
477
|
+
await unsafePushTables(localStack.db, { configValuesTable, tenantMembershipsTable });
|
|
478
478
|
|
|
479
479
|
const hash = await hashPassword("pw-long-enough");
|
|
480
480
|
const created = await localStack.http.writeOk<{ id: string }>(
|
|
@@ -2,13 +2,13 @@ import { randomBytes } from "node:crypto";
|
|
|
2
2
|
import { createEncryptionProvider } from "@cosmicdrift/kumiko-framework/db";
|
|
3
3
|
import type { TenantId } from "@cosmicdrift/kumiko-framework/engine";
|
|
4
4
|
import {
|
|
5
|
-
createEntityTable,
|
|
6
5
|
createTestUser,
|
|
7
|
-
pushTables,
|
|
8
6
|
setupTestStack,
|
|
9
7
|
type TestStack,
|
|
10
8
|
TestUsers,
|
|
11
9
|
testTenantId,
|
|
10
|
+
unsafeCreateEntityTable,
|
|
11
|
+
unsafePushTables,
|
|
12
12
|
} from "@cosmicdrift/kumiko-framework/stack";
|
|
13
13
|
import {
|
|
14
14
|
expectErrorIncludes,
|
|
@@ -57,9 +57,9 @@ beforeAll(async () => {
|
|
|
57
57
|
},
|
|
58
58
|
});
|
|
59
59
|
|
|
60
|
-
await
|
|
61
|
-
await
|
|
62
|
-
await
|
|
60
|
+
await unsafeCreateEntityTable(stack.db, userEntity);
|
|
61
|
+
await unsafeCreateEntityTable(stack.db, tenantEntity);
|
|
62
|
+
await unsafePushTables(stack.db, { configValuesTable, tenantMembershipsTable });
|
|
63
63
|
});
|
|
64
64
|
|
|
65
65
|
afterAll(async () => {
|
|
@@ -359,9 +359,9 @@ describe("scenario 7b: login rate limiting", () => {
|
|
|
359
359
|
loginRateLimit: createInMemoryLoginRateLimiter(3, 60_000),
|
|
360
360
|
},
|
|
361
361
|
});
|
|
362
|
-
await
|
|
363
|
-
await
|
|
364
|
-
await
|
|
362
|
+
await unsafeCreateEntityTable(rlStack.db, userEntity);
|
|
363
|
+
await unsafeCreateEntityTable(rlStack.db, tenantEntity);
|
|
364
|
+
await unsafePushTables(rlStack.db, { configValuesTable, tenantMembershipsTable });
|
|
365
365
|
|
|
366
366
|
// Seed one real user
|
|
367
367
|
const hash = await hashPassword("right-password");
|
|
@@ -2,11 +2,11 @@ import { randomBytes } from "node:crypto";
|
|
|
2
2
|
import { createEncryptionProvider } from "@cosmicdrift/kumiko-framework/db";
|
|
3
3
|
import type { TenantId } from "@cosmicdrift/kumiko-framework/engine";
|
|
4
4
|
import {
|
|
5
|
-
createEntityTable,
|
|
6
|
-
pushTables,
|
|
7
5
|
setupTestStack,
|
|
8
6
|
type TestStack,
|
|
9
7
|
TestUsers,
|
|
8
|
+
unsafeCreateEntityTable,
|
|
9
|
+
unsafePushTables,
|
|
10
10
|
} from "@cosmicdrift/kumiko-framework/stack";
|
|
11
11
|
import { eq } from "drizzle-orm";
|
|
12
12
|
import { Temporal } from "temporal-polyfill";
|
|
@@ -84,9 +84,9 @@ beforeAll(async () => {
|
|
|
84
84
|
},
|
|
85
85
|
});
|
|
86
86
|
|
|
87
|
-
await
|
|
88
|
-
await
|
|
89
|
-
await
|
|
87
|
+
await unsafeCreateEntityTable(stack.db, userEntity);
|
|
88
|
+
await unsafeCreateEntityTable(stack.db, tenantEntity);
|
|
89
|
+
await unsafePushTables(stack.db, { configValuesTable, tenantMembershipsTable });
|
|
90
90
|
});
|
|
91
91
|
|
|
92
92
|
afterAll(async () => {
|
|
@@ -9,11 +9,11 @@ import { pbkdf2Sync, randomBytes } from "node:crypto";
|
|
|
9
9
|
import { createEncryptionProvider } from "@cosmicdrift/kumiko-framework/db";
|
|
10
10
|
import type { TenantId } from "@cosmicdrift/kumiko-framework/engine";
|
|
11
11
|
import {
|
|
12
|
-
createEntityTable,
|
|
13
|
-
pushTables,
|
|
14
12
|
setupTestStack,
|
|
15
13
|
type TestStack,
|
|
16
14
|
TestUsers,
|
|
15
|
+
unsafeCreateEntityTable,
|
|
16
|
+
unsafePushTables,
|
|
17
17
|
} from "@cosmicdrift/kumiko-framework/stack";
|
|
18
18
|
import { afterAll, beforeAll, beforeEach, describe, expect, test } from "vitest";
|
|
19
19
|
import { createConfigFeature } from "../../config";
|
|
@@ -69,9 +69,9 @@ beforeAll(async () => {
|
|
|
69
69
|
},
|
|
70
70
|
});
|
|
71
71
|
|
|
72
|
-
await
|
|
73
|
-
await
|
|
74
|
-
await
|
|
72
|
+
await unsafeCreateEntityTable(stack.db, userEntity);
|
|
73
|
+
await unsafeCreateEntityTable(stack.db, tenantEntity);
|
|
74
|
+
await unsafePushTables(stack.db, { configValuesTable, tenantMembershipsTable });
|
|
75
75
|
});
|
|
76
76
|
|
|
77
77
|
afterAll(async () => {
|
|
@@ -21,10 +21,10 @@ import {
|
|
|
21
21
|
type TenantId,
|
|
22
22
|
} from "@cosmicdrift/kumiko-framework/engine";
|
|
23
23
|
import {
|
|
24
|
-
createEntityTable,
|
|
25
|
-
pushTables,
|
|
26
24
|
setupTestStack,
|
|
27
25
|
type TestStack,
|
|
26
|
+
unsafeCreateEntityTable,
|
|
27
|
+
unsafePushTables,
|
|
28
28
|
} from "@cosmicdrift/kumiko-framework/stack";
|
|
29
29
|
import { eq } from "drizzle-orm";
|
|
30
30
|
import { afterAll, beforeAll, beforeEach, describe, expect, test } from "vitest";
|
|
@@ -103,10 +103,10 @@ beforeAll(async () => {
|
|
|
103
103
|
},
|
|
104
104
|
});
|
|
105
105
|
|
|
106
|
-
await
|
|
107
|
-
await
|
|
108
|
-
await
|
|
109
|
-
await
|
|
106
|
+
await unsafeCreateEntityTable(stack.db, userEntity);
|
|
107
|
+
await unsafeCreateEntityTable(stack.db, tenantEntity);
|
|
108
|
+
await unsafeCreateEntityTable(stack.db, tenantInvitationEntity);
|
|
109
|
+
await unsafePushTables(stack.db, { configValuesTable, tenantMembershipsTable });
|
|
110
110
|
});
|
|
111
111
|
|
|
112
112
|
afterAll(async () => {
|
|
@@ -10,12 +10,12 @@
|
|
|
10
10
|
|
|
11
11
|
import type { TenantId } from "@cosmicdrift/kumiko-framework/engine";
|
|
12
12
|
import {
|
|
13
|
-
createEntityTable,
|
|
14
|
-
pushTables,
|
|
15
13
|
setupTestStack,
|
|
16
14
|
type TestStack,
|
|
17
15
|
TestUsers,
|
|
18
16
|
testTenantId,
|
|
17
|
+
unsafeCreateEntityTable,
|
|
18
|
+
unsafePushTables,
|
|
19
19
|
} from "@cosmicdrift/kumiko-framework/stack";
|
|
20
20
|
import { afterAll, beforeAll, beforeEach, describe, expect, test } from "vitest";
|
|
21
21
|
import { createConfigFeature } from "../../config";
|
|
@@ -61,9 +61,9 @@ beforeAll(async () => {
|
|
|
61
61
|
},
|
|
62
62
|
});
|
|
63
63
|
|
|
64
|
-
await
|
|
65
|
-
await
|
|
66
|
-
await
|
|
64
|
+
await unsafeCreateEntityTable(stack.db, userEntity);
|
|
65
|
+
await unsafeCreateEntityTable(stack.db, tenantEntity);
|
|
66
|
+
await unsafePushTables(stack.db, { configValuesTable, tenantMembershipsTable });
|
|
67
67
|
});
|
|
68
68
|
|
|
69
69
|
afterAll(async () => {
|
|
@@ -2,11 +2,11 @@ import { randomBytes } from "node:crypto";
|
|
|
2
2
|
import { createEncryptionProvider } from "@cosmicdrift/kumiko-framework/db";
|
|
3
3
|
import type { TenantId } from "@cosmicdrift/kumiko-framework/engine";
|
|
4
4
|
import {
|
|
5
|
-
createEntityTable,
|
|
6
|
-
pushTables,
|
|
7
5
|
setupTestStack,
|
|
8
6
|
type TestStack,
|
|
9
7
|
TestUsers,
|
|
8
|
+
unsafeCreateEntityTable,
|
|
9
|
+
unsafePushTables,
|
|
10
10
|
} from "@cosmicdrift/kumiko-framework/stack";
|
|
11
11
|
import { Temporal } from "temporal-polyfill";
|
|
12
12
|
import { afterAll, beforeAll, beforeEach, describe, expect, test } from "vitest";
|
|
@@ -79,9 +79,9 @@ beforeAll(async () => {
|
|
|
79
79
|
},
|
|
80
80
|
});
|
|
81
81
|
|
|
82
|
-
await
|
|
83
|
-
await
|
|
84
|
-
await
|
|
82
|
+
await unsafeCreateEntityTable(stack.db, userEntity);
|
|
83
|
+
await unsafeCreateEntityTable(stack.db, tenantEntity);
|
|
84
|
+
await unsafePushTables(stack.db, {
|
|
85
85
|
configValuesTable,
|
|
86
86
|
tenantMembershipsTable,
|
|
87
87
|
userSessionTable,
|
|
@@ -7,10 +7,10 @@
|
|
|
7
7
|
import { randomBytes } from "node:crypto";
|
|
8
8
|
import { createEncryptionProvider } from "@cosmicdrift/kumiko-framework/db";
|
|
9
9
|
import {
|
|
10
|
-
createEntityTable,
|
|
11
|
-
pushTables,
|
|
12
10
|
setupTestStack,
|
|
13
11
|
type TestStack,
|
|
12
|
+
unsafeCreateEntityTable,
|
|
13
|
+
unsafePushTables,
|
|
14
14
|
} from "@cosmicdrift/kumiko-framework/stack";
|
|
15
15
|
import { afterAll, beforeAll, beforeEach, describe, expect, test } from "vitest";
|
|
16
16
|
import { createConfigFeature } from "../../config";
|
|
@@ -67,9 +67,9 @@ beforeAll(async () => {
|
|
|
67
67
|
},
|
|
68
68
|
});
|
|
69
69
|
|
|
70
|
-
await
|
|
71
|
-
await
|
|
72
|
-
await
|
|
70
|
+
await unsafeCreateEntityTable(stack.db, userEntity);
|
|
71
|
+
await unsafeCreateEntityTable(stack.db, tenantEntity);
|
|
72
|
+
await unsafePushTables(stack.db, { configValuesTable, tenantMembershipsTable });
|
|
73
73
|
});
|
|
74
74
|
|
|
75
75
|
afterAll(async () => {
|
|
@@ -13,10 +13,10 @@
|
|
|
13
13
|
import type { TenantId } from "@cosmicdrift/kumiko-framework/engine";
|
|
14
14
|
import { createEventsTable, eventsTable } from "@cosmicdrift/kumiko-framework/event-store";
|
|
15
15
|
import {
|
|
16
|
-
createEntityTable,
|
|
17
|
-
pushTables,
|
|
18
16
|
setupTestStack,
|
|
19
17
|
type TestStack,
|
|
18
|
+
unsafeCreateEntityTable,
|
|
19
|
+
unsafePushTables,
|
|
20
20
|
} from "@cosmicdrift/kumiko-framework/stack";
|
|
21
21
|
import { and, eq } from "drizzle-orm";
|
|
22
22
|
import { afterAll, beforeAll, beforeEach, describe, expect, test } from "vitest";
|
|
@@ -42,9 +42,9 @@ beforeAll(async () => {
|
|
|
42
42
|
features: [createConfigFeature(), createUserFeature(), createTenantFeature()],
|
|
43
43
|
extraContext: { configResolver: resolver },
|
|
44
44
|
});
|
|
45
|
-
await
|
|
46
|
-
await
|
|
47
|
-
await
|
|
45
|
+
await unsafeCreateEntityTable(stack.db, tenantEntity);
|
|
46
|
+
await unsafeCreateEntityTable(stack.db, userEntity);
|
|
47
|
+
await unsafePushTables(stack.db, { configValuesTable, tenantMembershipsTable });
|
|
48
48
|
await createEventsTable(stack.db);
|
|
49
49
|
});
|
|
50
50
|
|
|
@@ -2,11 +2,11 @@ import { randomBytes } from "node:crypto";
|
|
|
2
2
|
import { createEncryptionProvider } from "@cosmicdrift/kumiko-framework/db";
|
|
3
3
|
import type { TenantId } from "@cosmicdrift/kumiko-framework/engine";
|
|
4
4
|
import {
|
|
5
|
-
createEntityTable,
|
|
6
|
-
pushTables,
|
|
7
5
|
setupTestStack,
|
|
8
6
|
type TestStack,
|
|
9
7
|
TestUsers,
|
|
8
|
+
unsafeCreateEntityTable,
|
|
9
|
+
unsafePushTables,
|
|
10
10
|
} from "@cosmicdrift/kumiko-framework/stack";
|
|
11
11
|
import * as jose from "jose";
|
|
12
12
|
import { afterAll, beforeAll, beforeEach, describe, expect, test } from "vitest";
|
|
@@ -116,9 +116,9 @@ beforeAll(async () => {
|
|
|
116
116
|
},
|
|
117
117
|
});
|
|
118
118
|
|
|
119
|
-
await
|
|
120
|
-
await
|
|
121
|
-
await
|
|
119
|
+
await unsafeCreateEntityTable(stack.db, userEntity);
|
|
120
|
+
await unsafeCreateEntityTable(stack.db, tenantEntity);
|
|
121
|
+
await unsafePushTables(stack.db, { configValuesTable, tenantMembershipsTable });
|
|
122
122
|
});
|
|
123
123
|
|
|
124
124
|
afterAll(async () => {
|
|
@@ -25,10 +25,10 @@
|
|
|
25
25
|
// zusammen).
|
|
26
26
|
|
|
27
27
|
import {
|
|
28
|
-
createEntityTable,
|
|
29
|
-
pushTables,
|
|
30
28
|
setupTestStack,
|
|
31
29
|
type TestStack,
|
|
30
|
+
unsafeCreateEntityTable,
|
|
31
|
+
unsafePushTables,
|
|
32
32
|
} from "@cosmicdrift/kumiko-framework/stack";
|
|
33
33
|
import { eq } from "drizzle-orm";
|
|
34
34
|
import { afterAll, beforeAll, beforeEach, describe, expect, test } from "vitest";
|
|
@@ -77,12 +77,12 @@ beforeAll(async () => {
|
|
|
77
77
|
},
|
|
78
78
|
});
|
|
79
79
|
|
|
80
|
-
await
|
|
80
|
+
await unsafeCreateEntityTable(stack.db, userEntity);
|
|
81
81
|
// tenant-entity hat den unique-constraint auf .key (siehe
|
|
82
|
-
// tenant.schema.indexes).
|
|
82
|
+
// tenant.schema.indexes). unsafeCreateEntityTable baut das via
|
|
83
83
|
// buildDrizzleTable nach — pinst den TOCTOU-Schutz für signup-confirm.
|
|
84
|
-
await
|
|
85
|
-
await
|
|
84
|
+
await unsafeCreateEntityTable(stack.db, tenantEntity);
|
|
85
|
+
await unsafePushTables(stack.db, { configValuesTable, tenantMembershipsTable });
|
|
86
86
|
});
|
|
87
87
|
|
|
88
88
|
afterAll(async () => {
|
|
@@ -10,12 +10,12 @@ import type { DbConnection } from "@cosmicdrift/kumiko-framework/db";
|
|
|
10
10
|
import { defineFeature, type WriteHandlerDef } from "@cosmicdrift/kumiko-framework/engine";
|
|
11
11
|
import { createEventsTable } from "@cosmicdrift/kumiko-framework/event-store";
|
|
12
12
|
import {
|
|
13
|
-
createEntityTable,
|
|
14
13
|
createTestUser,
|
|
15
14
|
setupTestStack,
|
|
16
15
|
type TestStack,
|
|
17
16
|
TestUsers,
|
|
18
17
|
testTenantId,
|
|
18
|
+
unsafeCreateEntityTable,
|
|
19
19
|
} from "@cosmicdrift/kumiko-framework/stack";
|
|
20
20
|
import { afterAll, beforeAll, describe, expect, test } from "vitest";
|
|
21
21
|
import { z } from "zod";
|
|
@@ -180,7 +180,7 @@ beforeAll(async () => {
|
|
|
180
180
|
});
|
|
181
181
|
db = stack.db;
|
|
182
182
|
|
|
183
|
-
await
|
|
183
|
+
await unsafeCreateEntityTable(db, capCounterEntity);
|
|
184
184
|
await createEventsTable(db);
|
|
185
185
|
});
|
|
186
186
|
|
|
@@ -12,11 +12,11 @@ import type { DbConnection } from "@cosmicdrift/kumiko-framework/db";
|
|
|
12
12
|
import { defineFeature, type WriteHandlerDef } from "@cosmicdrift/kumiko-framework/engine";
|
|
13
13
|
import { createEventsTable } from "@cosmicdrift/kumiko-framework/event-store";
|
|
14
14
|
import {
|
|
15
|
-
createEntityTable,
|
|
16
15
|
createTestUser,
|
|
17
16
|
setupTestStack,
|
|
18
17
|
type TestStack,
|
|
19
18
|
testTenantId,
|
|
19
|
+
unsafeCreateEntityTable,
|
|
20
20
|
} from "@cosmicdrift/kumiko-framework/stack";
|
|
21
21
|
import { afterAll, beforeAll, describe, expect, test } from "vitest";
|
|
22
22
|
import { z } from "zod";
|
|
@@ -95,7 +95,7 @@ let db: DbConnection;
|
|
|
95
95
|
beforeAll(async () => {
|
|
96
96
|
stack = await setupTestStack({ features: [capCounterFeature, newsletterFeature] });
|
|
97
97
|
db = stack.db;
|
|
98
|
-
await
|
|
98
|
+
await unsafeCreateEntityTable(db, capCounterEntity);
|
|
99
99
|
await createEventsTable(db);
|
|
100
100
|
});
|
|
101
101
|
|
|
@@ -10,10 +10,10 @@ import {
|
|
|
10
10
|
import { eventsTable } from "@cosmicdrift/kumiko-framework/event-store";
|
|
11
11
|
import {
|
|
12
12
|
createTestUser,
|
|
13
|
-
pushTables,
|
|
14
13
|
setupTestStack,
|
|
15
14
|
type TestStack,
|
|
16
15
|
TestUsers,
|
|
16
|
+
unsafePushTables,
|
|
17
17
|
} from "@cosmicdrift/kumiko-framework/stack";
|
|
18
18
|
import { expectErrorIncludes } from "@cosmicdrift/kumiko-framework/testing";
|
|
19
19
|
import { eq } from "drizzle-orm";
|
|
@@ -199,7 +199,7 @@ beforeAll(async () => {
|
|
|
199
199
|
});
|
|
200
200
|
db = stack.db;
|
|
201
201
|
|
|
202
|
-
await
|
|
202
|
+
await unsafePushTables(db, { configValuesTable });
|
|
203
203
|
// setupTestStack already calls createEventsTable + createArchivedStreamsTable
|
|
204
204
|
// for us; nothing extra needed for the config-changed event-store writes.
|
|
205
205
|
});
|
|
@@ -9,12 +9,12 @@
|
|
|
9
9
|
import type { DbConnection } from "@cosmicdrift/kumiko-framework/db";
|
|
10
10
|
import { eventsTable } from "@cosmicdrift/kumiko-framework/event-store";
|
|
11
11
|
import {
|
|
12
|
-
createEntityTable,
|
|
13
12
|
createTestUser,
|
|
14
|
-
pushTables,
|
|
15
13
|
setupTestStack,
|
|
16
14
|
type TestStack,
|
|
17
15
|
TestUsers,
|
|
16
|
+
unsafeCreateEntityTable,
|
|
17
|
+
unsafePushTables,
|
|
18
18
|
} from "@cosmicdrift/kumiko-framework/stack";
|
|
19
19
|
import { eq } from "drizzle-orm";
|
|
20
20
|
import { afterAll, beforeAll, beforeEach, describe, expect, test } from "vitest";
|
|
@@ -51,12 +51,12 @@ beforeAll(async () => {
|
|
|
51
51
|
extraContext: { configResolver: createConfigResolver() },
|
|
52
52
|
});
|
|
53
53
|
db = stack.db;
|
|
54
|
-
await
|
|
54
|
+
await unsafeCreateEntityTable(db, tenantEntity);
|
|
55
55
|
// Events-table is auto-pushed by setupTestStack; we only need to add
|
|
56
56
|
// the feature-specific projection + lookup tables here. notificationPre-
|
|
57
57
|
// ferencesTable is explicit because delivery-service queries it on
|
|
58
58
|
// every notify() — without it, notify() crashes before the event append.
|
|
59
|
-
await
|
|
59
|
+
await unsafePushTables(db, {
|
|
60
60
|
configValuesTable,
|
|
61
61
|
tenantMembershipsTable,
|
|
62
62
|
inAppMessagesTable,
|
|
@@ -10,10 +10,10 @@ import {
|
|
|
10
10
|
} from "@cosmicdrift/kumiko-framework/engine";
|
|
11
11
|
import {
|
|
12
12
|
createTestUser,
|
|
13
|
-
pushTables,
|
|
14
13
|
setupTestStack,
|
|
15
14
|
type TestStack,
|
|
16
15
|
TestUsers,
|
|
16
|
+
unsafePushTables,
|
|
17
17
|
} from "@cosmicdrift/kumiko-framework/stack";
|
|
18
18
|
import { and, eq } from "drizzle-orm";
|
|
19
19
|
import { afterAll, beforeAll, beforeEach, describe, expect, test } from "vitest";
|
|
@@ -289,7 +289,7 @@ beforeAll(async () => {
|
|
|
289
289
|
// deliveryAttemptsTable is auto-pushed by setupTestStack as MSP-projection-table;
|
|
290
290
|
// notificationPreferencesTable is an ES-entity, so it still needs explicit
|
|
291
291
|
// push here (entity-tables are not auto-provisioned — only projection ones).
|
|
292
|
-
await
|
|
292
|
+
await unsafePushTables(db, {
|
|
293
293
|
configValuesTable,
|
|
294
294
|
tenantMembershipsTable,
|
|
295
295
|
notificationPreferencesTable,
|
|
@@ -298,8 +298,8 @@ beforeAll(async () => {
|
|
|
298
298
|
});
|
|
299
299
|
|
|
300
300
|
// Create tenant entity table + seed memberships for tenant broadcast tests
|
|
301
|
-
const {
|
|
302
|
-
await
|
|
301
|
+
const { unsafeCreateEntityTable } = await import("@cosmicdrift/kumiko-framework/stack");
|
|
302
|
+
await unsafeCreateEntityTable(db, tenantEntity, "tenant");
|
|
303
303
|
|
|
304
304
|
// Create tenant + members via real API
|
|
305
305
|
await stack.http.writeOk(
|
|
@@ -16,11 +16,11 @@ import {
|
|
|
16
16
|
} from "@cosmicdrift/kumiko-framework/engine";
|
|
17
17
|
import { createEventDispatcher, type EventConsumer } from "@cosmicdrift/kumiko-framework/pipeline";
|
|
18
18
|
import {
|
|
19
|
-
createEntityTable,
|
|
20
19
|
createTestUser,
|
|
21
|
-
pushTables,
|
|
22
20
|
setupTestStack,
|
|
23
21
|
type TestStack,
|
|
22
|
+
unsafeCreateEntityTable,
|
|
23
|
+
unsafePushTables,
|
|
24
24
|
} from "@cosmicdrift/kumiko-framework/stack";
|
|
25
25
|
import { createLateBoundHolder } from "@cosmicdrift/kumiko-framework/testing";
|
|
26
26
|
import { generateId } from "@cosmicdrift/kumiko-framework/utils";
|
|
@@ -165,12 +165,12 @@ beforeAll(async () => {
|
|
|
165
165
|
systemHooks: [],
|
|
166
166
|
});
|
|
167
167
|
|
|
168
|
-
await
|
|
168
|
+
await unsafePushTables(stack.db, { globalFeatureStateTable });
|
|
169
169
|
// widgetTrackerTable is auto-pushed by setupTestStack because it's the
|
|
170
170
|
// projection-table of a registered r.multiStreamProjection — manually
|
|
171
171
|
// pushing again would re-run the CREATE TABLE and fail duplicate.
|
|
172
|
-
await
|
|
173
|
-
await
|
|
172
|
+
await unsafeCreateEntityTable(stack.db, widgetEntity);
|
|
173
|
+
await unsafeCreateEntityTable(stack.db, widgetAuditEntity, "widget-audit");
|
|
174
174
|
|
|
175
175
|
runtime = new GlobalFeatureToggleRuntime(stack.db, stack.registry);
|
|
176
176
|
await runtime.initialize();
|
|
@@ -8,12 +8,12 @@ import { defineFeature, defineWriteHandler } from "@cosmicdrift/kumiko-framework
|
|
|
8
8
|
import { createEventsTable } from "@cosmicdrift/kumiko-framework/event-store";
|
|
9
9
|
import { createEnvMasterKeyProvider } from "@cosmicdrift/kumiko-framework/secrets";
|
|
10
10
|
import {
|
|
11
|
-
createEntityTable,
|
|
12
11
|
createTestUser,
|
|
13
|
-
pushTables,
|
|
14
12
|
setupTestStack,
|
|
15
13
|
type TestStack,
|
|
16
14
|
testTenantId,
|
|
15
|
+
unsafeCreateEntityTable,
|
|
16
|
+
unsafePushTables,
|
|
17
17
|
} from "@cosmicdrift/kumiko-framework/stack";
|
|
18
18
|
import {
|
|
19
19
|
createMutableMasterKeyProvider,
|
|
@@ -102,8 +102,8 @@ beforeAll(async () => {
|
|
|
102
102
|
});
|
|
103
103
|
db = stack.db;
|
|
104
104
|
|
|
105
|
-
await
|
|
106
|
-
await
|
|
105
|
+
await unsafeCreateEntityTable(db, tenantEntity);
|
|
106
|
+
await unsafePushTables(db, { configValuesTable, tenant_secrets: tenantSecretsTable });
|
|
107
107
|
await createEventsTable(db);
|
|
108
108
|
});
|
|
109
109
|
|
|
@@ -20,10 +20,10 @@ import { createJobRunner, type JobRunner } from "@cosmicdrift/kumiko-framework/j
|
|
|
20
20
|
import {
|
|
21
21
|
createTestDb,
|
|
22
22
|
createTestRedis,
|
|
23
|
-
pushTables,
|
|
24
23
|
type TestDb,
|
|
25
24
|
type TestRedis,
|
|
26
25
|
TestUsers,
|
|
26
|
+
unsafePushTables,
|
|
27
27
|
} from "@cosmicdrift/kumiko-framework/stack";
|
|
28
28
|
import { bridgeStub, sleep } from "@cosmicdrift/kumiko-framework/testing";
|
|
29
29
|
import { afterAll, beforeAll, describe, expect, test } from "vitest";
|
|
@@ -99,11 +99,11 @@ beforeAll(async () => {
|
|
|
99
99
|
testRedis = await createTestRedis();
|
|
100
100
|
db = testDb.db;
|
|
101
101
|
|
|
102
|
-
await
|
|
102
|
+
await unsafePushTables(db, { configValuesTable });
|
|
103
103
|
// Post-ES config writes go through the event-store executor, which needs
|
|
104
104
|
// the framework events + archived-streams tables to exist before the
|
|
105
105
|
// first append. setupTestStack provisions them automatically; this test
|
|
106
|
-
// builds its DB manually (createTestDb +
|
|
106
|
+
// builds its DB manually (createTestDb + unsafePushTables), so we do it here.
|
|
107
107
|
await createEventsTable(db);
|
|
108
108
|
await createArchivedStreamsTable(db);
|
|
109
109
|
|
|
@@ -13,9 +13,9 @@ import { createEventsTable, eventsTable } from "@cosmicdrift/kumiko-framework/ev
|
|
|
13
13
|
import {
|
|
14
14
|
createTestDb,
|
|
15
15
|
createTestRedis,
|
|
16
|
-
pushTables,
|
|
17
16
|
type TestDb,
|
|
18
17
|
type TestRedis,
|
|
18
|
+
unsafePushTables,
|
|
19
19
|
} from "@cosmicdrift/kumiko-framework/stack";
|
|
20
20
|
import { eq } from "drizzle-orm";
|
|
21
21
|
import { afterAll, beforeAll, beforeEach, describe, expect, test } from "vitest";
|
|
@@ -37,7 +37,7 @@ beforeAll(async () => {
|
|
|
37
37
|
testDb = await createTestDb();
|
|
38
38
|
testRedis = await createTestRedis();
|
|
39
39
|
const registry = createRegistry([createJobsFeature()]);
|
|
40
|
-
await
|
|
40
|
+
await unsafePushTables(testDb.db, { jobRunsTable, jobRunLogsTable });
|
|
41
41
|
await createEventsTable(testDb.db);
|
|
42
42
|
logger = createJobRunLogger({ db: testDb.db, registry });
|
|
43
43
|
});
|
|
@@ -11,10 +11,10 @@ import {
|
|
|
11
11
|
createTestDb,
|
|
12
12
|
createTestRedis,
|
|
13
13
|
createTestUser,
|
|
14
|
-
pushTables,
|
|
15
14
|
type TestDb,
|
|
16
15
|
type TestRedis,
|
|
17
16
|
TestUsers,
|
|
17
|
+
unsafePushTables,
|
|
18
18
|
} from "@cosmicdrift/kumiko-framework/stack";
|
|
19
19
|
import { sleep } from "@cosmicdrift/kumiko-framework/testing";
|
|
20
20
|
import type { Hono } from "hono";
|
|
@@ -72,10 +72,10 @@ beforeAll(async () => {
|
|
|
72
72
|
const registry = createRegistry([appFeature, jobsFeature]);
|
|
73
73
|
|
|
74
74
|
// jobRuns + jobRunLogs are projection tables (auto-pushed by
|
|
75
|
-
//
|
|
75
|
+
// unsafePushTables via the registry-declared inline projections in jobs-feature).
|
|
76
76
|
// We need events + archived_streams for the ES writes the job-runner's
|
|
77
77
|
// logger does.
|
|
78
|
-
await
|
|
78
|
+
await unsafePushTables(db, { jobRunsTable, jobRunLogsTable });
|
|
79
79
|
await createEventsTable(db);
|
|
80
80
|
|
|
81
81
|
const redisUrl = `redis://${testRedis.redis.options.host}:${testRedis.redis.options.port}/${testRedis.redis.options.db}`;
|
|
@@ -9,9 +9,9 @@ import type { DbConnection } from "@cosmicdrift/kumiko-framework/db";
|
|
|
9
9
|
import { SYSTEM_TENANT_ID } from "@cosmicdrift/kumiko-framework/engine";
|
|
10
10
|
import { createEventsTable } from "@cosmicdrift/kumiko-framework/event-store";
|
|
11
11
|
import {
|
|
12
|
-
createEntityTable,
|
|
13
12
|
setupTestStack,
|
|
14
13
|
type TestStack,
|
|
14
|
+
unsafeCreateEntityTable,
|
|
15
15
|
} from "@cosmicdrift/kumiko-framework/stack";
|
|
16
16
|
import { afterAll, beforeAll, describe, expect, test } from "vitest";
|
|
17
17
|
import { createLegalPagesFeature, runLegalPagesBootCheck } from "../feature";
|
|
@@ -36,7 +36,7 @@ beforeAll(async () => {
|
|
|
36
36
|
}),
|
|
37
37
|
});
|
|
38
38
|
db = stack.db;
|
|
39
|
-
await
|
|
39
|
+
await unsafeCreateEntityTable(db, textBlockEntity);
|
|
40
40
|
await createEventsTable(db);
|
|
41
41
|
|
|
42
42
|
// Seed legal blocks für SYSTEM_TENANT in DE
|
|
@@ -219,7 +219,7 @@ describe("legal-pages :: SYSTEM_TENANT-routing (production-bug-regression)", ()
|
|
|
219
219
|
}),
|
|
220
220
|
});
|
|
221
221
|
try {
|
|
222
|
-
await
|
|
222
|
+
await unsafeCreateEntityTable(hostScopedStack.db, textBlockEntity);
|
|
223
223
|
await createEventsTable(hostScopedStack.db);
|
|
224
224
|
|
|
225
225
|
// Block NUR im SYSTEM_TENANT seeden — NICHT im otherTenantId
|
|
@@ -14,12 +14,12 @@ import { defineFeature, defineWriteHandler } from "@cosmicdrift/kumiko-framework
|
|
|
14
14
|
import { createEventsTable } from "@cosmicdrift/kumiko-framework/event-store";
|
|
15
15
|
import { createEnvMasterKeyProvider } from "@cosmicdrift/kumiko-framework/secrets";
|
|
16
16
|
import {
|
|
17
|
-
createEntityTable,
|
|
18
17
|
createTestUser,
|
|
19
|
-
pushTables,
|
|
20
18
|
setupTestStack,
|
|
21
19
|
type TestStack,
|
|
22
20
|
testTenantId,
|
|
21
|
+
unsafeCreateEntityTable,
|
|
22
|
+
unsafePushTables,
|
|
23
23
|
} from "@cosmicdrift/kumiko-framework/stack";
|
|
24
24
|
import {
|
|
25
25
|
createMutableMasterKeyProvider,
|
|
@@ -106,8 +106,8 @@ beforeAll(async () => {
|
|
|
106
106
|
});
|
|
107
107
|
db = stack.db;
|
|
108
108
|
|
|
109
|
-
await
|
|
110
|
-
await
|
|
109
|
+
await unsafeCreateEntityTable(db, tenantEntity);
|
|
110
|
+
await unsafePushTables(db, { configValuesTable, tenant_secrets: tenantSecretsTable });
|
|
111
111
|
await createEventsTable(db);
|
|
112
112
|
});
|
|
113
113
|
|
|
@@ -12,9 +12,9 @@ import {
|
|
|
12
12
|
} from "@cosmicdrift/kumiko-framework/secrets";
|
|
13
13
|
import {
|
|
14
14
|
createTestUser,
|
|
15
|
-
pushTables,
|
|
16
15
|
setupTestStack,
|
|
17
16
|
type TestStack,
|
|
17
|
+
unsafePushTables,
|
|
18
18
|
} from "@cosmicdrift/kumiko-framework/stack";
|
|
19
19
|
import { eq, sql } from "drizzle-orm";
|
|
20
20
|
import { afterAll, beforeAll, describe, expect, test } from "vitest";
|
|
@@ -76,7 +76,7 @@ beforeAll(async () => {
|
|
|
76
76
|
secrets: createSecretsContext({ db, masterKeyProvider: seedProvider }),
|
|
77
77
|
}),
|
|
78
78
|
});
|
|
79
|
-
await
|
|
79
|
+
await unsafePushTables(stack.db, {
|
|
80
80
|
tenant_secrets: tenantSecretsTable,
|
|
81
81
|
});
|
|
82
82
|
|
|
@@ -13,9 +13,9 @@ import {
|
|
|
13
13
|
} from "@cosmicdrift/kumiko-framework/secrets";
|
|
14
14
|
import {
|
|
15
15
|
createTestUser,
|
|
16
|
-
pushTables,
|
|
17
16
|
setupTestStack,
|
|
18
17
|
type TestStack,
|
|
18
|
+
unsafePushTables,
|
|
19
19
|
} from "@cosmicdrift/kumiko-framework/stack";
|
|
20
20
|
import { eq } from "drizzle-orm";
|
|
21
21
|
import { afterAll, beforeAll, beforeEach, describe, expect, test } from "vitest";
|
|
@@ -50,7 +50,7 @@ beforeAll(async () => {
|
|
|
50
50
|
secrets: createSecretsContext({ db, masterKeyProvider: provider }),
|
|
51
51
|
}),
|
|
52
52
|
});
|
|
53
|
-
await
|
|
53
|
+
await unsafePushTables(stack.db, { tenantSecretsTable });
|
|
54
54
|
await createEventsTable(stack.db);
|
|
55
55
|
});
|
|
56
56
|
|
|
@@ -12,9 +12,9 @@ import {
|
|
|
12
12
|
} from "@cosmicdrift/kumiko-framework/secrets";
|
|
13
13
|
import {
|
|
14
14
|
createTestUser,
|
|
15
|
-
pushTables,
|
|
16
15
|
setupTestStack,
|
|
17
16
|
type TestStack,
|
|
17
|
+
unsafePushTables,
|
|
18
18
|
} from "@cosmicdrift/kumiko-framework/stack";
|
|
19
19
|
import { and, eq } from "drizzle-orm";
|
|
20
20
|
import { afterAll, beforeAll, describe, expect, test } from "vitest";
|
|
@@ -49,7 +49,7 @@ beforeAll(async () => {
|
|
|
49
49
|
// table (tenant_secrets) still needs an explicit push here, since it
|
|
50
50
|
// belongs to an ES entity (and entity-tables aren't auto-pushed by
|
|
51
51
|
// setupTestStack).
|
|
52
|
-
await
|
|
52
|
+
await unsafePushTables(stack.db, { tenant_secrets: tenantSecretsTable });
|
|
53
53
|
await createEventsTable(stack.db);
|
|
54
54
|
});
|
|
55
55
|
|
|
@@ -6,10 +6,10 @@
|
|
|
6
6
|
|
|
7
7
|
import type { AppContext } from "@cosmicdrift/kumiko-framework/engine";
|
|
8
8
|
import {
|
|
9
|
-
createEntityTable,
|
|
10
9
|
setupTestStack,
|
|
11
10
|
type TestStack,
|
|
12
11
|
testTenantId,
|
|
12
|
+
unsafeCreateEntityTable,
|
|
13
13
|
} from "@cosmicdrift/kumiko-framework/stack";
|
|
14
14
|
import { sql } from "drizzle-orm";
|
|
15
15
|
import { afterAll, beforeAll, beforeEach, describe, expect, test } from "vitest";
|
|
@@ -38,7 +38,7 @@ beforeAll(async () => {
|
|
|
38
38
|
stack = await setupTestStack({
|
|
39
39
|
features: [createSessionsFeature()],
|
|
40
40
|
});
|
|
41
|
-
await
|
|
41
|
+
await unsafeCreateEntityTable(stack.db, userSessionEntity);
|
|
42
42
|
});
|
|
43
43
|
|
|
44
44
|
afterAll(async () => {
|
|
@@ -2,11 +2,11 @@ import { randomBytes } from "node:crypto";
|
|
|
2
2
|
import { createEncryptionProvider } from "@cosmicdrift/kumiko-framework/db";
|
|
3
3
|
import type { TenantId } from "@cosmicdrift/kumiko-framework/engine";
|
|
4
4
|
import {
|
|
5
|
-
createEntityTable,
|
|
6
|
-
pushTables,
|
|
7
5
|
setupTestStack,
|
|
8
6
|
type TestStack,
|
|
9
7
|
testTenantId,
|
|
8
|
+
unsafeCreateEntityTable,
|
|
9
|
+
unsafePushTables,
|
|
10
10
|
} from "@cosmicdrift/kumiko-framework/stack";
|
|
11
11
|
import { createLateBoundHolder } from "@cosmicdrift/kumiko-framework/testing";
|
|
12
12
|
import { afterAll, beforeAll, beforeEach, describe, expect, test, vi } from "vitest";
|
|
@@ -77,10 +77,10 @@ beforeAll(async () => {
|
|
|
77
77
|
callbacks.set(createSessionCallbacks({ db: stack.db }));
|
|
78
78
|
h = makeSessionHelpers(stack, TENANT);
|
|
79
79
|
|
|
80
|
-
await
|
|
81
|
-
await
|
|
82
|
-
await
|
|
83
|
-
await
|
|
80
|
+
await unsafeCreateEntityTable(stack.db, userEntity);
|
|
81
|
+
await unsafeCreateEntityTable(stack.db, tenantEntity);
|
|
82
|
+
await unsafeCreateEntityTable(stack.db, userSessionEntity);
|
|
83
|
+
await unsafePushTables(stack.db, { configValuesTable, tenantMembershipsTable });
|
|
84
84
|
});
|
|
85
85
|
|
|
86
86
|
afterAll(async () => {
|
|
@@ -2,11 +2,11 @@ import { randomBytes } from "node:crypto";
|
|
|
2
2
|
import { createEncryptionProvider } from "@cosmicdrift/kumiko-framework/db";
|
|
3
3
|
import type { TenantId } from "@cosmicdrift/kumiko-framework/engine";
|
|
4
4
|
import {
|
|
5
|
-
createEntityTable,
|
|
6
|
-
pushTables,
|
|
7
5
|
setupTestStack,
|
|
8
6
|
type TestStack,
|
|
9
7
|
testTenantId,
|
|
8
|
+
unsafeCreateEntityTable,
|
|
9
|
+
unsafePushTables,
|
|
10
10
|
} from "@cosmicdrift/kumiko-framework/stack";
|
|
11
11
|
import { createLateBoundHolder } from "@cosmicdrift/kumiko-framework/testing";
|
|
12
12
|
import { and, eq } from "drizzle-orm";
|
|
@@ -64,10 +64,10 @@ beforeAll(async () => {
|
|
|
64
64
|
callbacks.set(createSessionCallbacks({ db: stack.db }));
|
|
65
65
|
h = makeSessionHelpers(stack, TENANT);
|
|
66
66
|
|
|
67
|
-
await
|
|
68
|
-
await
|
|
69
|
-
await
|
|
70
|
-
await
|
|
67
|
+
await unsafeCreateEntityTable(stack.db, userEntity);
|
|
68
|
+
await unsafeCreateEntityTable(stack.db, tenantEntity);
|
|
69
|
+
await unsafeCreateEntityTable(stack.db, userSessionEntity);
|
|
70
|
+
await unsafePushTables(stack.db, { configValuesTable, tenantMembershipsTable });
|
|
71
71
|
});
|
|
72
72
|
|
|
73
73
|
afterAll(async () => {
|
|
@@ -9,15 +9,15 @@ import {
|
|
|
9
9
|
import { createEventsTable } from "@cosmicdrift/kumiko-framework/event-store";
|
|
10
10
|
import { createJobRunner, type JobRunner } from "@cosmicdrift/kumiko-framework/jobs";
|
|
11
11
|
import {
|
|
12
|
-
createEntityTable,
|
|
13
12
|
createTestDb,
|
|
14
13
|
createTestRedis,
|
|
15
14
|
createTestUser,
|
|
16
|
-
pushTables,
|
|
17
15
|
type TestDb,
|
|
18
16
|
type TestRedis,
|
|
19
17
|
TestUsers,
|
|
20
18
|
testTenantId,
|
|
19
|
+
unsafeCreateEntityTable,
|
|
20
|
+
unsafePushTables,
|
|
21
21
|
} from "@cosmicdrift/kumiko-framework/stack";
|
|
22
22
|
import { bridgeStub, sleep } from "@cosmicdrift/kumiko-framework/testing";
|
|
23
23
|
import type { Hono } from "hono";
|
|
@@ -60,8 +60,8 @@ beforeAll(async () => {
|
|
|
60
60
|
testRedis = await createTestRedis();
|
|
61
61
|
db = testDb.db;
|
|
62
62
|
|
|
63
|
-
await
|
|
64
|
-
await
|
|
63
|
+
await unsafeCreateEntityTable(db, tenantEntity);
|
|
64
|
+
await unsafePushTables(db, { tenantMembershipsTable, configValuesTable });
|
|
65
65
|
await createEventsTable(db);
|
|
66
66
|
|
|
67
67
|
const configFeature = createConfigFeature();
|
|
@@ -14,12 +14,12 @@
|
|
|
14
14
|
import type { TenantId } from "@cosmicdrift/kumiko-framework/engine";
|
|
15
15
|
import { createEventsTable, eventsTable } from "@cosmicdrift/kumiko-framework/event-store";
|
|
16
16
|
import {
|
|
17
|
-
createEntityTable,
|
|
18
17
|
createTestUser,
|
|
19
|
-
pushTables,
|
|
20
18
|
setupTestStack,
|
|
21
19
|
type TestStack,
|
|
22
20
|
TestUsers,
|
|
21
|
+
unsafeCreateEntityTable,
|
|
22
|
+
unsafePushTables,
|
|
23
23
|
} from "@cosmicdrift/kumiko-framework/stack";
|
|
24
24
|
import { and, eq } from "drizzle-orm";
|
|
25
25
|
import { afterAll, beforeAll, beforeEach, describe, expect, test } from "vitest";
|
|
@@ -43,8 +43,8 @@ beforeAll(async () => {
|
|
|
43
43
|
features: [createConfigFeature(), createTenantFeature()],
|
|
44
44
|
extraContext: { configResolver: resolver },
|
|
45
45
|
});
|
|
46
|
-
await
|
|
47
|
-
await
|
|
46
|
+
await unsafeCreateEntityTable(stack.db, tenantEntity);
|
|
47
|
+
await unsafePushTables(stack.db, { configValuesTable, tenantMembershipsTable });
|
|
48
48
|
await createEventsTable(stack.db);
|
|
49
49
|
});
|
|
50
50
|
|
|
@@ -2,12 +2,12 @@ import { randomBytes } from "node:crypto";
|
|
|
2
2
|
import { createEncryptionProvider, type DbConnection } from "@cosmicdrift/kumiko-framework/db";
|
|
3
3
|
import { createEventsTable } from "@cosmicdrift/kumiko-framework/event-store";
|
|
4
4
|
import {
|
|
5
|
-
createEntityTable,
|
|
6
5
|
createTestUser,
|
|
7
|
-
pushTables,
|
|
8
6
|
setupTestStack,
|
|
9
7
|
type TestStack,
|
|
10
8
|
TestUsers,
|
|
9
|
+
unsafeCreateEntityTable,
|
|
10
|
+
unsafePushTables,
|
|
11
11
|
} from "@cosmicdrift/kumiko-framework/stack";
|
|
12
12
|
import { expectErrorIncludes, rolesOf } from "@cosmicdrift/kumiko-framework/testing";
|
|
13
13
|
import { afterAll, beforeAll, describe, expect, test } from "vitest";
|
|
@@ -42,8 +42,8 @@ beforeAll(async () => {
|
|
|
42
42
|
});
|
|
43
43
|
db = stack.db;
|
|
44
44
|
|
|
45
|
-
await
|
|
46
|
-
await
|
|
45
|
+
await unsafeCreateEntityTable(db, tenantEntity);
|
|
46
|
+
await unsafePushTables(db, { configValuesTable });
|
|
47
47
|
await createEventsTable(db);
|
|
48
48
|
});
|
|
49
49
|
|
package/src/tenant/seeding.ts
CHANGED
|
@@ -38,8 +38,9 @@ import {
|
|
|
38
38
|
fetchOne,
|
|
39
39
|
} from "@cosmicdrift/kumiko-framework/db";
|
|
40
40
|
import type { SessionUser, TenantId } from "@cosmicdrift/kumiko-framework/engine";
|
|
41
|
+
import { eventsTable } from "@cosmicdrift/kumiko-framework/event-store";
|
|
41
42
|
import { TestUsers } from "@cosmicdrift/kumiko-framework/stack";
|
|
42
|
-
import { eq } from "drizzle-orm";
|
|
43
|
+
import { eq, max as maxFn } from "drizzle-orm";
|
|
43
44
|
import { tenantMembershipEntity, tenantMembershipsTable } from "./membership-table";
|
|
44
45
|
import { tenantEntity, tenantTable } from "./schema/tenant";
|
|
45
46
|
|
|
@@ -94,6 +95,16 @@ export async function seedTenant(db: DbConnection, options: SeedTenantOptions):
|
|
|
94
95
|
const existing = await fetchOne(db, tenantTable, eq(tenantTable["id"], options.id));
|
|
95
96
|
if (existing) return options.id;
|
|
96
97
|
|
|
98
|
+
// Idempotenz: Aggregate kann im Event-Store existieren ohne Projection-Row
|
|
99
|
+
// (Projection-Drift nach rebuild, manuellem DELETE, oder async-lag). Wenn
|
|
100
|
+
// Stream-Version > 0 → kein create() — wäre version_conflict. Caller
|
|
101
|
+
// bekommt die ID, Projection wird beim nächsten Dispatcher-Cycle aufgebaut.
|
|
102
|
+
const [streamRow] = await db
|
|
103
|
+
.select({ v: maxFn(eventsTable.version) })
|
|
104
|
+
.from(eventsTable)
|
|
105
|
+
.where(eq(eventsTable.aggregateId, options.id));
|
|
106
|
+
if ((streamRow?.v ?? 0) > 0) return options.id;
|
|
107
|
+
|
|
97
108
|
const result = await tenantExecutor.create(
|
|
98
109
|
{ id: options.id, key: options.key, name: options.name },
|
|
99
110
|
by,
|
|
@@ -38,12 +38,16 @@ container exits. No auto-heal in production. See
|
|
|
38
38
|
In integration tests (vitest) it's enough to do:
|
|
39
39
|
|
|
40
40
|
```typescript
|
|
41
|
-
import {
|
|
41
|
+
import { unsafeCreateEntityTable } from "@cosmicdrift/kumiko-framework/stack";
|
|
42
42
|
import { textBlockEntity } from "@cosmicdrift/kumiko-bundled-features/text-content";
|
|
43
43
|
|
|
44
|
-
await
|
|
44
|
+
await unsafeCreateEntityTable(stack.db, textBlockEntity);
|
|
45
45
|
```
|
|
46
46
|
|
|
47
|
+
The `unsafe` prefix is intentional — it bypasses the projection
|
|
48
|
+
registry and is reserved for test setup and framework-internals. Apps
|
|
49
|
+
declare data via `r.entity(...)` everywhere else.
|
|
50
|
+
|
|
47
51
|
## Use cases
|
|
48
52
|
|
|
49
53
|
text-content is generic — anything that's static Markdown text per
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import type { DbConnection } from "@cosmicdrift/kumiko-framework/db";
|
|
2
2
|
import { createEventsTable } from "@cosmicdrift/kumiko-framework/event-store";
|
|
3
3
|
import {
|
|
4
|
-
createEntityTable,
|
|
5
4
|
createTestUser,
|
|
6
5
|
setupTestStack,
|
|
7
6
|
type TestStack,
|
|
8
7
|
TestUsers,
|
|
8
|
+
unsafeCreateEntityTable,
|
|
9
9
|
} from "@cosmicdrift/kumiko-framework/stack";
|
|
10
10
|
import { expectErrorIncludes } from "@cosmicdrift/kumiko-framework/testing";
|
|
11
11
|
import { afterAll, beforeAll, describe, expect, test } from "vitest";
|
|
@@ -26,7 +26,7 @@ const feature = createTextContentFeature();
|
|
|
26
26
|
beforeAll(async () => {
|
|
27
27
|
stack = await setupTestStack({ features: [feature] });
|
|
28
28
|
db = stack.db;
|
|
29
|
-
await
|
|
29
|
+
await unsafeCreateEntityTable(db, textBlockEntity);
|
|
30
30
|
await createEventsTable(db);
|
|
31
31
|
});
|
|
32
32
|
|
|
@@ -2,13 +2,13 @@ import { randomBytes } from "node:crypto";
|
|
|
2
2
|
import { createEncryptionProvider, type DbConnection } from "@cosmicdrift/kumiko-framework/db";
|
|
3
3
|
import { createEventsTable } from "@cosmicdrift/kumiko-framework/event-store";
|
|
4
4
|
import {
|
|
5
|
-
createEntityTable,
|
|
6
5
|
createTestUser,
|
|
7
|
-
pushTables,
|
|
8
6
|
setupTestStack,
|
|
9
7
|
type TestStack,
|
|
10
8
|
TestUsers,
|
|
11
9
|
testTenantId,
|
|
10
|
+
unsafeCreateEntityTable,
|
|
11
|
+
unsafePushTables,
|
|
12
12
|
} from "@cosmicdrift/kumiko-framework/stack";
|
|
13
13
|
import { expectErrorIncludes } from "@cosmicdrift/kumiko-framework/testing";
|
|
14
14
|
import { afterAll, beforeAll, describe, expect, test } from "vitest";
|
|
@@ -47,9 +47,9 @@ beforeAll(async () => {
|
|
|
47
47
|
});
|
|
48
48
|
db = stack.db;
|
|
49
49
|
|
|
50
|
-
await
|
|
51
|
-
await
|
|
52
|
-
await
|
|
50
|
+
await unsafeCreateEntityTable(db, tenantEntity);
|
|
51
|
+
await unsafeCreateEntityTable(db, tierAssignmentEntity);
|
|
52
|
+
await unsafePushTables(db, { configValuesTable });
|
|
53
53
|
await createEventsTable(db);
|
|
54
54
|
});
|
|
55
55
|
|
|
@@ -8,11 +8,11 @@
|
|
|
8
8
|
|
|
9
9
|
import { createEventsTable, eventsTable } from "@cosmicdrift/kumiko-framework/event-store";
|
|
10
10
|
import {
|
|
11
|
-
createEntityTable,
|
|
12
|
-
pushTables,
|
|
13
11
|
setupTestStack,
|
|
14
12
|
type TestStack,
|
|
15
13
|
TestUsers,
|
|
14
|
+
unsafeCreateEntityTable,
|
|
15
|
+
unsafePushTables,
|
|
16
16
|
} from "@cosmicdrift/kumiko-framework/stack";
|
|
17
17
|
import { eq } from "drizzle-orm";
|
|
18
18
|
import { afterAll, beforeAll, beforeEach, describe, expect, test } from "vitest";
|
|
@@ -31,8 +31,8 @@ beforeAll(async () => {
|
|
|
31
31
|
features: [createConfigFeature(), createUserFeature()],
|
|
32
32
|
extraContext: { configResolver: resolver },
|
|
33
33
|
});
|
|
34
|
-
await
|
|
35
|
-
await
|
|
34
|
+
await unsafeCreateEntityTable(stack.db, userEntity);
|
|
35
|
+
await unsafePushTables(stack.db, { configValuesTable });
|
|
36
36
|
await createEventsTable(stack.db);
|
|
37
37
|
});
|
|
38
38
|
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import {
|
|
2
|
-
createEntityTable,
|
|
3
2
|
createTestUser,
|
|
4
3
|
setupTestStack,
|
|
5
4
|
type TestStack,
|
|
6
5
|
TestUsers,
|
|
6
|
+
unsafeCreateEntityTable,
|
|
7
7
|
} from "@cosmicdrift/kumiko-framework/stack";
|
|
8
8
|
import { expectErrorIncludes } from "@cosmicdrift/kumiko-framework/testing";
|
|
9
9
|
import { afterAll, beforeAll, beforeEach, describe, expect, test } from "vitest";
|
|
@@ -18,7 +18,7 @@ const userFeature = createUserFeature();
|
|
|
18
18
|
|
|
19
19
|
beforeAll(async () => {
|
|
20
20
|
stack = await setupTestStack({ features: [userFeature] });
|
|
21
|
-
await
|
|
21
|
+
await unsafeCreateEntityTable(stack.db, userEntity);
|
|
22
22
|
});
|
|
23
23
|
|
|
24
24
|
afterAll(async () => {
|