@cosmicdrift/kumiko-bundled-features 0.14.0 → 0.16.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.
Files changed (269) hide show
  1. package/package.json +2 -2
  2. package/src/__tests__/env-schemas.test.ts +1 -1
  3. package/src/__tests__/es-ops-e2e.integration.ts +10 -9
  4. package/src/audit/__tests__/audit.integration.ts +3 -3
  5. package/src/audit/handlers/list.query.ts +39 -51
  6. package/src/auth-email-password/__tests__/account-lockout-no-redis.integration.ts +4 -3
  7. package/src/auth-email-password/__tests__/account-lockout.integration.ts +4 -3
  8. package/src/auth-email-password/__tests__/auth-claims.integration.ts +5 -4
  9. package/src/auth-email-password/__tests__/auth.integration.ts +4 -3
  10. package/src/auth-email-password/__tests__/confirm-token-flow.test.ts +1 -1
  11. package/src/auth-email-password/__tests__/email-templates.test.ts +1 -1
  12. package/src/auth-email-password/__tests__/email-verification.integration.ts +7 -10
  13. package/src/auth-email-password/__tests__/identity-v3-hash.test.ts +1 -1
  14. package/src/auth-email-password/__tests__/identity-v3-login.integration.ts +4 -3
  15. package/src/auth-email-password/__tests__/invite-flow.integration.ts +16 -43
  16. package/src/auth-email-password/__tests__/multi-roles.integration.ts +6 -9
  17. package/src/auth-email-password/__tests__/password-reset.integration.ts +8 -7
  18. package/src/auth-email-password/__tests__/public-routes-rate-limit.integration.ts +4 -3
  19. package/src/auth-email-password/__tests__/seed-admin.integration.ts +19 -32
  20. package/src/auth-email-password/__tests__/session-callbacks.integration.ts +6 -5
  21. package/src/auth-email-password/__tests__/session-strict-mode.integration.ts +1 -1
  22. package/src/auth-email-password/__tests__/signed-token.test.ts +1 -1
  23. package/src/auth-email-password/__tests__/signup-flow.integration.ts +11 -15
  24. package/src/auth-email-password/handlers/invite-accept-with-login.write.ts +26 -26
  25. package/src/auth-email-password/handlers/invite-accept.write.ts +24 -21
  26. package/src/auth-email-password/handlers/invite-create.write.ts +3 -8
  27. package/src/auth-email-password/handlers/invite-signup-complete.write.ts +20 -17
  28. package/src/auth-email-password/handlers/signup-confirm.write.ts +3 -7
  29. package/src/auth-email-password/seeding.ts +1 -1
  30. package/src/auth-email-password/web/__tests__/auth-gate.test.tsx +1 -2
  31. package/src/auth-email-password/web/__tests__/forgot-password-screen.test.tsx +10 -19
  32. package/src/auth-email-password/web/__tests__/login-screen.test.tsx +12 -18
  33. package/src/auth-email-password/web/__tests__/reset-password-screen.test.tsx +12 -17
  34. package/src/auth-email-password/web/__tests__/session-roles.test.ts +1 -1
  35. package/src/auth-email-password/web/__tests__/tenant-switcher.test.tsx +1 -8
  36. package/src/auth-email-password/web/__tests__/test-utils.tsx +4 -8
  37. package/src/auth-email-password/web/__tests__/user-menu.test.tsx +2 -8
  38. package/src/auth-email-password/web/__tests__/verify-email-screen.test.tsx +10 -15
  39. package/src/billing-foundation/__tests__/billing-foundation.integration.ts +1 -1
  40. package/src/billing-foundation/__tests__/feature.test.ts +1 -1
  41. package/src/billing-foundation/__tests__/webhook-handler.test.ts +6 -5
  42. package/src/billing-foundation/db/queries/subscription-projection.ts +15 -0
  43. package/src/billing-foundation/get-subscription-for-tenant.ts +2 -6
  44. package/src/billing-foundation/handlers/create-portal-session.write.ts +2 -2
  45. package/src/billing-foundation/handlers/list-subscriptions.query.ts +4 -1
  46. package/src/billing-foundation/projection.ts +32 -13
  47. package/src/cap-counter/__tests__/cap-counter.integration.ts +1 -1
  48. package/src/cap-counter/__tests__/enforce-cap.test.ts +37 -32
  49. package/src/cap-counter/__tests__/with-cap-enforcement.integration.ts +1 -1
  50. package/src/cap-counter/enforce-cap.ts +14 -20
  51. package/src/cap-counter/handlers/get-counter.query.ts +7 -13
  52. package/src/cap-counter/handlers/increment.write.ts +2 -2
  53. package/src/cap-counter/handlers/mark-soft-warned.write.ts +2 -2
  54. package/src/channel-in-app/handlers/inbox.query.ts +7 -13
  55. package/src/channel-in-app/handlers/mark-all-read.write.ts +7 -9
  56. package/src/channel-in-app/handlers/mark-read.write.ts +8 -14
  57. package/src/channel-in-app/handlers/unread-count.query.ts +10 -9
  58. package/src/channel-in-app/in-app-channel.ts +10 -12
  59. package/src/channel-in-app/tables.ts +1 -1
  60. package/src/compliance-profiles/__tests__/compliance-profiles.integration.ts +1 -1
  61. package/src/compliance-profiles/__tests__/seeding.integration.ts +1 -1
  62. package/src/compliance-profiles/_internal/parse-override.ts +19 -0
  63. package/src/compliance-profiles/handlers/for-tenant.query.ts +10 -32
  64. package/src/compliance-profiles/handlers/needs-profile.query.ts +4 -7
  65. package/src/compliance-profiles/handlers/set-profile.write.ts +5 -7
  66. package/src/compliance-profiles/resolve-for-tenant.ts +11 -27
  67. package/src/compliance-profiles/schema/profile-selection.ts +2 -2
  68. package/src/compliance-profiles/seeding.ts +4 -7
  69. package/src/config/__tests__/app-overrides.test.ts +1 -1
  70. package/src/config/__tests__/cascade.integration.ts +1 -1
  71. package/src/config/__tests__/config.integration.ts +8 -27
  72. package/src/config/db/queries/resolver.ts +47 -0
  73. package/src/config/handlers/__tests__/prepare-config-write.test.ts +1 -1
  74. package/src/config/resolver.ts +14 -62
  75. package/src/config/table.ts +4 -4
  76. package/src/config/write-helpers.ts +7 -11
  77. package/src/custom-fields/__tests__/audit-integration.integration.ts +6 -6
  78. package/src/custom-fields/__tests__/custom-fields.integration.ts +7 -7
  79. package/src/custom-fields/__tests__/feature.test.ts +1 -1
  80. package/src/custom-fields/__tests__/field-access.integration.ts +6 -6
  81. package/src/custom-fields/__tests__/quota.integration.ts +6 -6
  82. package/src/custom-fields/__tests__/retention.integration.ts +12 -10
  83. package/src/custom-fields/__tests__/user-data-rights.integration.ts +27 -17
  84. package/src/custom-fields/__tests__/wire-for-entity.test.ts +5 -5
  85. package/src/custom-fields/db/queries/field-access.ts +16 -0
  86. package/src/custom-fields/db/queries/projection.ts +43 -0
  87. package/src/custom-fields/db/queries/quota.ts +14 -0
  88. package/src/custom-fields/db/queries/retention.ts +39 -0
  89. package/src/custom-fields/db/queries/user-data-rights.ts +54 -0
  90. package/src/custom-fields/lib/field-access.ts +2 -41
  91. package/src/custom-fields/lib/quota.ts +2 -25
  92. package/src/custom-fields/run-retention.ts +19 -21
  93. package/src/custom-fields/wire-for-entity.ts +30 -23
  94. package/src/custom-fields/wire-user-data-rights.ts +33 -85
  95. package/src/data-retention/__tests__/data-retention.integration.ts +1 -1
  96. package/src/data-retention/__tests__/keep-for.test.ts +1 -1
  97. package/src/data-retention/__tests__/override-schema.test.ts +1 -1
  98. package/src/data-retention/__tests__/policy-for.integration.ts +1 -1
  99. package/src/data-retention/__tests__/resolver.test.ts +1 -1
  100. package/src/data-retention/handlers/policy-for.query.ts +5 -8
  101. package/src/data-retention/resolve-for-tenant.ts +6 -8
  102. package/src/data-retention/schema/tenant-retention-override.ts +2 -2
  103. package/src/delivery/__tests__/delivery-events.integration.ts +8 -21
  104. package/src/delivery/__tests__/delivery.integration.ts +100 -190
  105. package/src/delivery/db/queries/preferences.ts +30 -0
  106. package/src/delivery/delivery-service.ts +8 -36
  107. package/src/delivery/feature.ts +10 -2
  108. package/src/delivery/handlers/log.query.ts +5 -7
  109. package/src/delivery/handlers/preferences.query.ts +2 -5
  110. package/src/delivery/tables.ts +26 -1
  111. package/src/delivery/upsert-preference.ts +8 -14
  112. package/src/feature-toggles/__tests__/feature-toggles.integration.ts +30 -30
  113. package/src/feature-toggles/__tests__/registered-system-tenant.test.ts +7 -6
  114. package/src/feature-toggles/db/queries/toggle-state.ts +25 -0
  115. package/src/feature-toggles/feature.ts +16 -2
  116. package/src/feature-toggles/global-feature-state-table.ts +1 -1
  117. package/src/feature-toggles/handlers/list.query.ts +9 -2
  118. package/src/feature-toggles/handlers/registered.query.ts +3 -7
  119. package/src/feature-toggles/handlers/set.write.ts +37 -25
  120. package/src/feature-toggles/toggle-runtime.ts +3 -6
  121. package/src/file-foundation/__tests__/feature.test.ts +1 -1
  122. package/src/file-foundation/__tests__/file-foundation.integration.ts +1 -1
  123. package/src/file-provider-inmemory/__tests__/feature.test.ts +1 -1
  124. package/src/file-provider-s3/__tests__/feature.test.ts +1 -1
  125. package/src/files/__tests__/files.integration.ts +18 -7
  126. package/src/files/schema/file-ref.ts +1 -1
  127. package/src/files-provider-s3/__tests__/env-helper.test.ts +1 -1
  128. package/src/files-provider-s3/__tests__/s3-provider.integration.ts +1 -1
  129. package/src/files-provider-s3/__tests__/s3-provider.test.ts +1 -1
  130. package/src/jobs/__tests__/job-system-user.integration.ts +1 -1
  131. package/src/jobs/__tests__/jobs-events.integration.ts +8 -21
  132. package/src/jobs/__tests__/jobs-feature.integration.ts +1 -1
  133. package/src/jobs/feature.ts +26 -15
  134. package/src/jobs/handlers/detail.query.ts +10 -8
  135. package/src/jobs/handlers/list.query.ts +9 -21
  136. package/src/jobs/handlers/retry.write.ts +2 -7
  137. package/src/jobs/job-run-logger.ts +3 -9
  138. package/src/jobs/job-run-table.ts +49 -17
  139. package/src/legal-pages/__tests__/legal-pages.integration.ts +1 -1
  140. package/src/mail-foundation/__tests__/feature.test.ts +1 -1
  141. package/src/mail-foundation/__tests__/mail-foundation.integration.ts +1 -1
  142. package/src/mail-transport-inmemory/__tests__/feature.test.ts +1 -1
  143. package/src/mail-transport-smtp/__tests__/feature.test.ts +1 -1
  144. package/src/rate-limiting/__tests__/rate-limiting.integration.ts +1 -1
  145. package/src/renderer-foundation/__tests__/api.test.ts +2 -2
  146. package/src/renderer-foundation/__tests__/collect-plugins.integration.ts +1 -1
  147. package/src/renderer-simple/__tests__/adapter.test.ts +2 -2
  148. package/src/renderer-simple/__tests__/simple-renderer.test.ts +1 -1
  149. package/src/secrets/__tests__/require-secrets-context.test.ts +6 -5
  150. package/src/secrets/__tests__/rotate.integration.ts +6 -9
  151. package/src/secrets/__tests__/secrets-events.integration.ts +6 -12
  152. package/src/secrets/__tests__/secrets.integration.ts +6 -11
  153. package/src/secrets/db/queries/read.ts +16 -0
  154. package/src/secrets/handlers/list.query.ts +16 -17
  155. package/src/secrets/handlers/rotate.job.ts +8 -12
  156. package/src/secrets/secrets-context.ts +9 -21
  157. package/src/secrets/table.ts +1 -1
  158. package/src/sessions/__tests__/cleanup.integration.ts +8 -6
  159. package/src/sessions/__tests__/password-auto-revoke.integration.ts +7 -6
  160. package/src/sessions/__tests__/sessions.integration.ts +23 -38
  161. package/src/sessions/__tests__/test-helpers.ts +1 -1
  162. package/src/sessions/db/queries/cleanup.ts +21 -0
  163. package/src/sessions/handlers/cleanup.job.ts +6 -29
  164. package/src/sessions/handlers/list.query.ts +24 -24
  165. package/src/sessions/handlers/mine.query.ts +24 -23
  166. package/src/sessions/handlers/revoke-all-for-user.write.ts +7 -11
  167. package/src/sessions/handlers/revoke-all-others.write.ts +7 -12
  168. package/src/sessions/handlers/revoke.write.ts +11 -18
  169. package/src/sessions/schema/user-session.ts +2 -2
  170. package/src/sessions/session-callbacks.ts +19 -21
  171. package/src/subscription-mollie/__tests__/feature.test.ts +1 -1
  172. package/src/subscription-mollie/__tests__/mollie-foundation.integration.ts +1 -1
  173. package/src/subscription-mollie/__tests__/verify-webhook.test.ts +8 -7
  174. package/src/subscription-stripe/__tests__/feature.test.ts +1 -1
  175. package/src/subscription-stripe/__tests__/plugin-methods.test.ts +14 -15
  176. package/src/subscription-stripe/__tests__/stripe-foundation.integration.ts +1 -1
  177. package/src/subscription-stripe/__tests__/verify-webhook.test.ts +14 -14
  178. package/src/subscription-stripe/verify-webhook.ts +1 -1
  179. package/src/template-resolver/__tests__/handlers.integration.ts +1 -1
  180. package/src/template-resolver/__tests__/template-resolver.integration.ts +3 -2
  181. package/src/template-resolver/api.ts +7 -13
  182. package/src/template-resolver/handlers/archive.write.ts +4 -7
  183. package/src/template-resolver/handlers/find-by-id.query.ts +4 -7
  184. package/src/template-resolver/handlers/list.query.ts +13 -21
  185. package/src/template-resolver/handlers/publish.write.ts +4 -7
  186. package/src/template-resolver/handlers/upsert-system.write.ts +7 -10
  187. package/src/template-resolver/handlers/upsert-tenant.write.ts +7 -10
  188. package/src/template-resolver/table.ts +2 -5
  189. package/src/tenant/__tests__/multi-tenant.integration.ts +1 -1
  190. package/src/tenant/__tests__/seed-testing.integration.ts +19 -45
  191. package/src/tenant/__tests__/tenant.integration.ts +1 -1
  192. package/src/tenant/handlers/active-tenant-ids.query.ts +3 -8
  193. package/src/tenant/handlers/add-member.write.ts +6 -8
  194. package/src/tenant/handlers/cancel-invitation.write.ts +5 -7
  195. package/src/tenant/handlers/invitations.query.ts +5 -10
  196. package/src/tenant/handlers/me.query.ts +2 -3
  197. package/src/tenant/handlers/members.query.ts +4 -5
  198. package/src/tenant/handlers/memberships.query.ts +2 -5
  199. package/src/tenant/handlers/remove-member.write.ts +6 -8
  200. package/src/tenant/handlers/resolve-user-ids.query.ts +6 -16
  201. package/src/tenant/handlers/update-member-roles.write.ts +6 -8
  202. package/src/tenant/invitation-table.ts +2 -5
  203. package/src/tenant/membership-table.ts +3 -6
  204. package/src/tenant/schema/tenant.ts +2 -2
  205. package/src/tenant/seeding.ts +12 -18
  206. package/src/text-content/README.md +1 -1
  207. package/src/text-content/__tests__/text-content.integration.ts +2 -2
  208. package/src/text-content/api.ts +2 -9
  209. package/src/text-content/handlers/by-slug.query.ts +6 -9
  210. package/src/text-content/handlers/by-tenant.query.ts +2 -2
  211. package/src/text-content/handlers/set.write.ts +7 -9
  212. package/src/text-content/seeding.ts +6 -9
  213. package/src/text-content/table.ts +2 -2
  214. package/src/text-content/web/__tests__/editor-read-only.test.tsx +31 -45
  215. package/src/text-content/web/__tests__/group-blocks.test.ts +1 -18
  216. package/src/text-content/web/client-plugin.tsx +11 -23
  217. package/src/tier-engine/__tests__/auto-default-tier.integration.ts +10 -16
  218. package/src/tier-engine/__tests__/compose-app.test.ts +1 -1
  219. package/src/tier-engine/__tests__/drift.test.ts +1 -1
  220. package/src/tier-engine/__tests__/resolver.integration.ts +6 -6
  221. package/src/tier-engine/__tests__/tier-engine.integration.ts +1 -1
  222. package/src/tier-engine/feature.ts +9 -16
  223. package/src/user/__tests__/seed-testing.integration.ts +10 -22
  224. package/src/user/__tests__/user-status.test.ts +1 -1
  225. package/src/user/__tests__/user.integration.ts +6 -5
  226. package/src/user/handlers/create.write.ts +5 -7
  227. package/src/user/handlers/find-for-auth.query.ts +5 -7
  228. package/src/user/schema/user.ts +2 -2
  229. package/src/user/seeding.ts +2 -3
  230. package/src/user-data-rights/__tests__/audit-log.integration.ts +24 -12
  231. package/src/user-data-rights/__tests__/cross-data-matrix.integration.ts +64 -37
  232. package/src/user-data-rights/__tests__/download.integration.ts +29 -46
  233. package/src/user-data-rights/__tests__/export-job-idempotency.integration.ts +35 -28
  234. package/src/user-data-rights/__tests__/export-job-schema.test.ts +2 -2
  235. package/src/user-data-rights/__tests__/policy-to-strategy.test.ts +1 -1
  236. package/src/user-data-rights/__tests__/request-cancel-deletion.integration.ts +11 -15
  237. package/src/user-data-rights/__tests__/request-deletion-callback.integration.ts +10 -12
  238. package/src/user-data-rights/__tests__/request-export.integration.ts +23 -16
  239. package/src/user-data-rights/__tests__/restriction-flow.integration.ts +24 -32
  240. package/src/user-data-rights/__tests__/run-export-jobs.integration.ts +142 -137
  241. package/src/user-data-rights/__tests__/run-forget-cleanup.integration.ts +46 -28
  242. package/src/user-data-rights/__tests__/run-user-export.integration.ts +20 -14
  243. package/src/user-data-rights/__tests__/token-helpers.test.ts +1 -1
  244. package/src/user-data-rights/__tests__/user-data-rights.integration.ts +1 -1
  245. package/src/user-data-rights/__tests__/zip-path.test.ts +1 -1
  246. package/src/user-data-rights/audit-download.ts +3 -3
  247. package/src/user-data-rights/db/queries/export-jobs.ts +23 -0
  248. package/src/user-data-rights/db/queries/forget-cleanup.ts +13 -0
  249. package/src/user-data-rights/handlers/cancel-deletion.write.ts +28 -22
  250. package/src/user-data-rights/handlers/download-by-job.query.ts +11 -21
  251. package/src/user-data-rights/handlers/download-by-token.query.ts +20 -35
  252. package/src/user-data-rights/handlers/export-status.query.ts +19 -33
  253. package/src/user-data-rights/handlers/lift-restriction.write.ts +7 -12
  254. package/src/user-data-rights/handlers/list-download-attempts.query.ts +14 -23
  255. package/src/user-data-rights/handlers/my-audit-log.query.ts +33 -23
  256. package/src/user-data-rights/handlers/request-deletion.write.ts +15 -15
  257. package/src/user-data-rights/handlers/request-export.write.ts +7 -11
  258. package/src/user-data-rights/handlers/restrict-account.write.ts +12 -12
  259. package/src/user-data-rights/run-export-jobs.ts +20 -60
  260. package/src/user-data-rights/run-forget-cleanup.ts +19 -33
  261. package/src/user-data-rights/run-user-export.ts +4 -6
  262. package/src/user-data-rights/schema/download-attempt.ts +2 -2
  263. package/src/user-data-rights/schema/download-token.ts +2 -2
  264. package/src/user-data-rights/schema/export-job.ts +2 -3
  265. package/src/user-data-rights-defaults/__tests__/user-data-rights-defaults.integration.ts +37 -30
  266. package/src/user-data-rights-defaults/db/queries/user-hook.ts +17 -0
  267. package/src/user-data-rights-defaults/hooks/file-ref.userdata-hook.ts +12 -27
  268. package/src/user-data-rights-defaults/hooks/user.userdata-hook.ts +16 -18
  269. package/CHANGELOG.md +0 -689
@@ -9,6 +9,8 @@
9
9
  // User-Explicit-Anforderung "exporte + fristen" — der Frist-Set-Pfad ist
10
10
  // hier; der Frist-Ablauf-Cleanup folgt mit S2.U5b.
11
11
 
12
+ import { afterAll, beforeAll, beforeEach, describe, expect, test } from "bun:test";
13
+ import { asRawClient, insertOne, selectMany } from "@cosmicdrift/kumiko-framework/bun-db";
12
14
  import { createEventsTable } from "@cosmicdrift/kumiko-framework/event-store";
13
15
  import {
14
16
  createTestUser,
@@ -19,8 +21,6 @@ import {
19
21
  unsafeCreateEntityTable,
20
22
  } from "@cosmicdrift/kumiko-framework/stack";
21
23
  import { getTemporal } from "@cosmicdrift/kumiko-framework/time";
22
- import { eq, sql } from "drizzle-orm";
23
- import { afterAll, beforeAll, beforeEach, describe, expect, test } from "vitest";
24
24
  import {
25
25
  createComplianceProfilesFeature,
26
26
  tenantComplianceProfileEntity,
@@ -71,9 +71,9 @@ afterAll(async () => {
71
71
  beforeEach(async () => {
72
72
  // Hard-clean User-Rows fuer einen sauberen Start je Test. softDelete
73
73
  // wuerde sonst row-state aus voherigen Tests einschleppen.
74
- await stack.db.delete(userTable);
75
- await stack.db.execute(sql`DELETE FROM read_tenant_compliance_profiles`);
76
- await stack.db.execute(sql`DELETE FROM kumiko_events`);
74
+ await asRawClient(stack.db).unsafe(`DELETE FROM "${userTable.tableName}"`);
75
+ await asRawClient(stack.db).unsafe(`DELETE FROM read_tenant_compliance_profiles`);
76
+ await asRawClient(stack.db).unsafe(`DELETE FROM kumiko_events`);
77
77
  });
78
78
 
79
79
  // gracePeriodEnd ist `instant()` (Temporal.Instant in JS). Nicht JS-Date —
@@ -91,7 +91,7 @@ async function seedAlice(
91
91
  gracePeriodEnd: Instant | null;
92
92
  }> = {},
93
93
  ): Promise<void> {
94
- await stack.db.insert(userTable).values({
94
+ await insertOne(stack.db, userTable, {
95
95
  id: aliceUser.id,
96
96
  tenantId: tenantA,
97
97
  email: "alice@example.com",
@@ -109,14 +109,10 @@ async function fetchAlice(): Promise<{
109
109
  status: string;
110
110
  gracePeriodEnd: Instant | null;
111
111
  } | null> {
112
- const rows = (await stack.db
113
- .select({
114
- status: userTable["status"],
115
- gracePeriodEnd: userTable["gracePeriodEnd"],
116
- })
117
- .from(userTable)
118
- .where(eq(userTable["id"], aliceUser.id))
119
- .limit(1)) as Array<{ status: string; gracePeriodEnd: Instant | null }>;
112
+ const rows = (await selectMany(stack.db, userTable, { id: aliceUser.id })) as Array<{
113
+ status: string;
114
+ gracePeriodEnd: Instant | null;
115
+ }>;
120
116
  return rows[0] ?? null;
121
117
  }
122
118
 
@@ -348,7 +344,7 @@ describe("Cross-User-Isolation", () => {
348
344
  tenantId: tenantA,
349
345
  roles: ["Member"],
350
346
  });
351
- await stack.db.insert(userTable).values({
347
+ await insertOne(stack.db, userTable, {
352
348
  id: testUserId(43),
353
349
  tenantId: tenantA,
354
350
  email: "bob@example.com",
@@ -7,6 +7,8 @@
7
7
  // Der Code-Comment in handlers/request-deletion.write.ts behauptet beide
8
8
  // Properties — dieser Test verifiziert sie end-to-end.
9
9
 
10
+ import { afterAll, beforeAll, beforeEach, describe, expect, test } from "bun:test";
11
+ import { asRawClient, insertOne, selectMany } from "@cosmicdrift/kumiko-framework/bun-db";
10
12
  import { createEventsTable } from "@cosmicdrift/kumiko-framework/event-store";
11
13
  import {
12
14
  createTestUser,
@@ -15,8 +17,6 @@ import {
15
17
  testTenantId,
16
18
  unsafeCreateEntityTable,
17
19
  } from "@cosmicdrift/kumiko-framework/stack";
18
- import { eq, sql } from "drizzle-orm";
19
- import { afterAll, beforeAll, beforeEach, describe, expect, test } from "vitest";
20
20
  import {
21
21
  createComplianceProfilesFeature,
22
22
  tenantComplianceProfileEntity,
@@ -76,13 +76,13 @@ afterAll(async () => {
76
76
  beforeEach(async () => {
77
77
  state.calls = [];
78
78
  state.shouldThrow = false;
79
- await stack.db.delete(userTable);
80
- await stack.db.execute(sql`DELETE FROM read_tenant_compliance_profiles`);
81
- await stack.db.execute(sql`DELETE FROM kumiko_events`);
79
+ await asRawClient(stack.db).unsafe(`DELETE FROM "${userTable.tableName}"`);
80
+ await asRawClient(stack.db).unsafe(`DELETE FROM read_tenant_compliance_profiles`);
81
+ await asRawClient(stack.db).unsafe(`DELETE FROM kumiko_events`);
82
82
  });
83
83
 
84
84
  async function seedAlice(email: string = "alice@example.com"): Promise<void> {
85
- await stack.db.insert(userTable).values({
85
+ await insertOne(stack.db, userTable, {
86
86
  id: aliceUser.id,
87
87
  tenantId: tenantA,
88
88
  email,
@@ -137,11 +137,9 @@ describe("request-deletion :: sendDeletionRequestedEmail callback", () => {
137
137
  // DB-State ist tatsaechlich geflipt — der zentrale "best-effort"-
138
138
  // Beweis. Wenn das Write die Email-Failure-Exception bubbelt, waere
139
139
  // der Status hier noch Active.
140
- const rows = (await stack.db
141
- .select({ status: userTable["status"] })
142
- .from(userTable)
143
- .where(eq(userTable["id"], aliceUser.id))
144
- .limit(1)) as Array<{ status: string }>;
140
+ const rows = (await selectMany(stack.db, userTable, { id: aliceUser.id })) as Array<{
141
+ status: string;
142
+ }>;
145
143
  expect(rows[0]?.status).toBe(USER_STATUS.DeletionRequested);
146
144
  });
147
145
 
@@ -152,7 +150,7 @@ describe("request-deletion :: sendDeletionRequestedEmail callback", () => {
152
150
  });
153
151
 
154
152
  test("422 user_not_in_active_state → callback NICHT gefeuert", async () => {
155
- await stack.db.insert(userTable).values({
153
+ await insertOne(stack.db, userTable, {
156
154
  id: aliceUser.id,
157
155
  tenantId: tenantA,
158
156
  email: "alice@example.com",
@@ -17,6 +17,13 @@
17
17
  // - Status-Polling: User sieht eigene Jobs, Cross-User-Isolation,
18
18
  // hasJob=false wenn nichts da
19
19
 
20
+ import { afterAll, beforeAll, beforeEach, describe, expect, test } from "bun:test";
21
+ import {
22
+ asRawClient,
23
+ insertOne,
24
+ selectMany,
25
+ updateMany,
26
+ } from "@cosmicdrift/kumiko-framework/bun-db";
20
27
  import { createEventsTable } from "@cosmicdrift/kumiko-framework/event-store";
21
28
  import {
22
29
  createTestUser,
@@ -26,8 +33,6 @@ import {
26
33
  unsafeCreateEntityTable,
27
34
  } from "@cosmicdrift/kumiko-framework/stack";
28
35
  import { getTemporal } from "@cosmicdrift/kumiko-framework/time";
29
- import { sql } from "drizzle-orm";
30
- import { afterAll, beforeAll, beforeEach, describe, expect, test } from "vitest";
31
36
  import { createComplianceProfilesFeature } from "../../compliance-profiles";
32
37
  import { createDataRetentionFeature } from "../../data-retention";
33
38
  import { createUserFeature } from "../../user";
@@ -63,8 +68,8 @@ afterAll(async () => {
63
68
  });
64
69
 
65
70
  beforeEach(async () => {
66
- await stack.db.delete(exportJobsTable);
67
- await stack.db.execute(sql`DELETE FROM kumiko_events`);
71
+ await asRawClient(stack.db).unsafe(`DELETE FROM "${exportJobsTable.tableName}"`);
72
+ await asRawClient(stack.db).unsafe(`DELETE FROM kumiko_events`);
68
73
  });
69
74
 
70
75
  type RequestExportResponse = {
@@ -81,7 +86,7 @@ describe("request-export :: happy path", () => {
81
86
  expect(result.status).toBe(EXPORT_JOB_STATUS.Pending);
82
87
  expect(result.jobId).toMatch(/^[0-9a-f]{8}-[0-9a-f]{4}-/);
83
88
 
84
- const rows = await stack.db.select().from(exportJobsTable);
89
+ const rows = await selectMany(stack.db, exportJobsTable);
85
90
  expect(rows).toHaveLength(1);
86
91
  // biome-ignore lint/suspicious/noExplicitAny: drizzle-row typing
87
92
  expect((rows[0] as any).userId).toBe(aliceUser.id);
@@ -94,7 +99,7 @@ describe("request-export :: happy path", () => {
94
99
  test("Event 'export-job.created' im Stream", async () => {
95
100
  await stack.http.writeOk(REQUEST_EXPORT, {}, aliceUser);
96
101
 
97
- const events = await stack.db.execute(sql`
102
+ const events = await asRawClient(stack.db).unsafe(`
98
103
  SELECT type FROM kumiko_events WHERE aggregate_type = 'export-job'
99
104
  `);
100
105
  // biome-ignore lint/suspicious/noExplicitAny: drizzle-execute typing
@@ -114,10 +119,10 @@ describe("request-export :: App-side-Idempotency (primaerer Pfad)", () => {
114
119
  expect(second.jobId).toBe(first.jobId);
115
120
  expect(second.status).toBe(EXPORT_JOB_STATUS.Pending);
116
121
 
117
- const rows = await stack.db.select().from(exportJobsTable);
122
+ const rows = await selectMany(stack.db, exportJobsTable);
118
123
  expect(rows).toHaveLength(1);
119
124
 
120
- const events = await stack.db.execute(sql`
125
+ const events = await asRawClient(stack.db).unsafe(`
121
126
  SELECT type FROM kumiko_events WHERE aggregate_type = 'export-job'
122
127
  `);
123
128
  // biome-ignore lint/suspicious/noExplicitAny: drizzle-execute typing
@@ -128,16 +133,18 @@ describe("request-export :: App-side-Idempotency (primaerer Pfad)", () => {
128
133
  test("Klick nach done-Job ist NEUER Job (Audit-Historie wird nicht blockiert)", async () => {
129
134
  const first = await stack.http.writeOk<RequestExportResponse>(REQUEST_EXPORT, {}, aliceUser);
130
135
  // Worker-Simulation: status auf done flippen (direct-update OK in Test)
131
- await stack.db
132
- .update(exportJobsTable)
133
- .set({ status: EXPORT_JOB_STATUS.Done })
134
- .where(sql`id = ${first.jobId}`);
136
+ await updateMany(
137
+ stack.db,
138
+ exportJobsTable,
139
+ { status: EXPORT_JOB_STATUS.Done },
140
+ { id: first.jobId },
141
+ );
135
142
 
136
143
  const second = await stack.http.writeOk<RequestExportResponse>(REQUEST_EXPORT, {}, aliceUser);
137
144
  expect(second.isExisting).toBe(false);
138
145
  expect(second.jobId).not.toBe(first.jobId);
139
146
 
140
- const rows = await stack.db.select().from(exportJobsTable);
147
+ const rows = await selectMany(stack.db, exportJobsTable);
141
148
  expect(rows).toHaveLength(2);
142
149
  });
143
150
  });
@@ -154,7 +161,7 @@ describe("request-export :: Cross-Tenant (Plan-Doc-Pflicht-Test)", () => {
154
161
  expect(fromB.jobId).toBe(fromA.jobId);
155
162
 
156
163
  // Genau 1 Job (kein 2. fuer Tenant B)
157
- const rows = await stack.db.select().from(exportJobsTable);
164
+ const rows = await selectMany(stack.db, exportJobsTable);
158
165
  expect(rows).toHaveLength(1);
159
166
  // requestedFromTenantId = Tenant aus 1. Klick (= A), nicht B
160
167
  // biome-ignore lint/suspicious/noExplicitAny: drizzle-row typing
@@ -183,7 +190,7 @@ describe("request-export :: Race-Schutz (Promise.all parallel)", () => {
183
190
  const winners = [a, b].filter((r) => r.isExisting === false);
184
191
  expect(winners).toHaveLength(1);
185
192
 
186
- const rows = await stack.db.select().from(exportJobsTable);
193
+ const rows = await selectMany(stack.db, exportJobsTable);
187
194
  expect(rows).toHaveLength(1);
188
195
  });
189
196
 
@@ -241,7 +248,7 @@ describe("export-status :: User-Polling", () => {
241
248
  const T = getTemporal();
242
249
  // 1. Job done in der Vergangenheit
243
250
  const oldJobId = "11111111-1111-4111-8111-111111111111";
244
- await stack.db.insert(exportJobsTable).values({
251
+ await insertOne(stack.db, exportJobsTable, {
245
252
  id: oldJobId,
246
253
  tenantId: tenantA,
247
254
  userId: aliceUser.id,
@@ -10,7 +10,9 @@
10
10
  // - State-Transition-Matrix: Active↔Restricted, andere Uebergaenge
11
11
  // fehlgeschlagen mit klaren error codes
12
12
 
13
+ import { afterAll, beforeAll, beforeEach, describe, expect, test } from "bun:test";
13
14
  import { randomBytes } from "node:crypto";
15
+ import { asRawClient, selectMany, updateMany } from "@cosmicdrift/kumiko-framework/bun-db";
14
16
  import { createEncryptionProvider } from "@cosmicdrift/kumiko-framework/db";
15
17
  import type { TenantId } from "@cosmicdrift/kumiko-framework/engine";
16
18
  import { createEventsTable } from "@cosmicdrift/kumiko-framework/event-store";
@@ -23,8 +25,6 @@ import {
23
25
  unsafePushTables,
24
26
  } from "@cosmicdrift/kumiko-framework/stack";
25
27
  import { createLateBoundHolder } from "@cosmicdrift/kumiko-framework/testing";
26
- import { eq, sql } from "drizzle-orm";
27
- import { afterAll, beforeAll, beforeEach, describe, expect, test } from "vitest";
28
28
  import { AuthErrors, AuthHandlers } from "../../auth-email-password/constants";
29
29
  import { createAuthEmailPasswordFeature } from "../../auth-email-password/feature";
30
30
  import { hashPassword } from "../../auth-email-password/password-hashing";
@@ -97,11 +97,11 @@ afterAll(async () => {
97
97
  });
98
98
 
99
99
  beforeEach(async () => {
100
- await stack.db.delete(userSessionTable);
101
- await stack.db.delete(userTable);
102
- await stack.db.delete(tenantMembershipsTable);
103
- await stack.db.execute(sql`DELETE FROM read_tenant_compliance_profiles`);
104
- await stack.db.execute(sql`DELETE FROM kumiko_events`);
100
+ await asRawClient(stack.db).unsafe(`DELETE FROM "${userSessionTable.tableName}"`);
101
+ await asRawClient(stack.db).unsafe(`DELETE FROM "${userTable.tableName}"`);
102
+ await asRawClient(stack.db).unsafe(`DELETE FROM "${tenantMembershipsTable.tableName}"`);
103
+ await asRawClient(stack.db).unsafe(`DELETE FROM read_tenant_compliance_profiles`);
104
+ await asRawClient(stack.db).unsafe(`DELETE FROM kumiko_events`);
105
105
  });
106
106
 
107
107
  async function seedAliceWithMembership(
@@ -114,7 +114,7 @@ async function seedAliceWithMembership(
114
114
  TestUsers.systemAdmin,
115
115
  );
116
116
  if (status !== USER_STATUS.Active) {
117
- await stack.db.update(userTable).set({ status }).where(eq(userTable["id"], created.id));
117
+ await updateMany(stack.db, userTable, { status }, { id: created.id });
118
118
  }
119
119
  await seedTenantMembership(stack.db, {
120
120
  userId: created.id,
@@ -141,10 +141,7 @@ describe("S2.U6 :: restrict-account state-transitions", () => {
141
141
  expect(loginRes.status).toBe(200);
142
142
 
143
143
  // Session-Row vorhanden + live (revokedAt=null).
144
- const sessionsBefore = (await stack.db
145
- .select({ id: userSessionTable["id"], revokedAt: userSessionTable["revokedAt"] })
146
- .from(userSessionTable)
147
- .where(eq(userSessionTable["userId"], userId))) as Array<{
144
+ const sessionsBefore = (await selectMany(stack.db, userSessionTable, { userId })) as Array<{
148
145
  id: string;
149
146
  revokedAt: unknown;
150
147
  }>;
@@ -166,17 +163,15 @@ describe("S2.U6 :: restrict-account state-transitions", () => {
166
163
  expect(result.userId).toBe(userId);
167
164
 
168
165
  // DB-State: status=Restricted.
169
- const userRow = (await stack.db
170
- .select({ status: userTable["status"] })
171
- .from(userTable)
172
- .where(eq(userTable["id"], userId))) as Array<{ status: string }>;
166
+ const userRow = (await selectMany(stack.db, userTable, { id: userId })) as Array<{
167
+ status: string;
168
+ }>;
173
169
  expect(userRow[0]?.status).toBe(USER_STATUS.Restricted);
174
170
 
175
171
  // Alle Sessions revoked (revokedAt != null).
176
- const sessionsAfter = (await stack.db
177
- .select({ revokedAt: userSessionTable["revokedAt"] })
178
- .from(userSessionTable)
179
- .where(eq(userSessionTable["userId"], userId))) as Array<{ revokedAt: unknown }>;
172
+ const sessionsAfter = (await selectMany(stack.db, userSessionTable, { userId })) as Array<{
173
+ revokedAt: unknown;
174
+ }>;
180
175
  expect(sessionsAfter.every((s) => s.revokedAt !== null)).toBe(true);
181
176
  });
182
177
 
@@ -204,10 +199,9 @@ describe("S2.U6 :: lift-restriction state-transitions", () => {
204
199
  const result = await stack.http.writeOk<{ status: string }>(LIFT, {}, aliceUser);
205
200
  expect(result.status).toBe(USER_STATUS.Active);
206
201
 
207
- const userRow = (await stack.db
208
- .select({ status: userTable["status"] })
209
- .from(userTable)
210
- .where(eq(userTable["id"], userId))) as Array<{ status: string }>;
202
+ const userRow = (await selectMany(stack.db, userTable, { id: userId })) as Array<{
203
+ status: string;
204
+ }>;
211
205
  expect(userRow[0]?.status).toBe(USER_STATUS.Active);
212
206
  });
213
207
 
@@ -279,10 +273,9 @@ describe("S2.U6 :: Cross-Feature sessions.revokeAllForUser direct", () => {
279
273
  expect(a.status).toBe(200);
280
274
  expect(b.status).toBe(200);
281
275
 
282
- const liveBefore = (await stack.db
283
- .select({ id: userSessionTable["id"] })
284
- .from(userSessionTable)
285
- .where(eq(userSessionTable["userId"], userId))) as Array<{ id: string }>;
276
+ const liveBefore = (await selectMany(stack.db, userSessionTable, { userId })) as Array<{
277
+ id: string;
278
+ }>;
286
279
  expect(liveBefore.length).toBe(2);
287
280
 
288
281
  // System-Caller.
@@ -300,10 +293,9 @@ describe("S2.U6 :: Cross-Feature sessions.revokeAllForUser direct", () => {
300
293
  expect(result.userId).toBe(userId);
301
294
 
302
295
  // Alle revoked.
303
- const revoked = (await stack.db
304
- .select({ revokedAt: userSessionTable["revokedAt"] })
305
- .from(userSessionTable)
306
- .where(eq(userSessionTable["userId"], userId))) as Array<{ revokedAt: unknown }>;
296
+ const revoked = (await selectMany(stack.db, userSessionTable, { userId })) as Array<{
297
+ revokedAt: unknown;
298
+ }>;
307
299
  expect(revoked.every((s) => s.revokedAt !== null)).toBe(true);
308
300
  });
309
301
  });